Phalcon project from scratch step by step

In one of our previous articles we were showing how to setup your local dev environment using docker that consists in Apache, PHP and Phalcon (https://keepforyourself.com/coding/php/dev-environment-in-docker-with-apache-php7-phalcon/). In this article we will go through the setup of a Phalcon project from scratch step by step.

Starting the container

Before we start let’s start our docker image with a local folder mounted so that we can use our IDE or loved text editor and change files on the fly so that these changes can be reflected in the docker container. Let’s create in our filesystem this directory

/Users/my-username/phalcon-app

mkdir -p /Users/my-username/phalcon-app

and run this command

docker run -v /Users/my-username/phalcon-app:/var/www/localhost/htdocs -p 8086:80 --name phalcon_app -d dev_env_apache_phalcon

What this command will do is

  • will start a new container named phalcon_app,
  • will forward port 8086 to the container 80 AND
  • will mount our local folder /Users/my-username/phalcon-app into the html container folder.

In other word if you create a file test.php in /Users/my-username/phalcon-app

<?php
// test.php
echo "it's time to fly";
?>

This is the result when you will browse to http://localhost:8086/test.php

Phalcon project from scratch step by step - starting the container with a mounted folder
Phalcon project setup – starting the container with a mounted folder

Now that we have the basics covered let’s start with the basic project setup.

The bootstrap file

First thing we have to do is to create is the Bootstrap file that will act as entry point and will load all the configuration needed and eventually will provide the initialization of key components. As stated in the documentation this file handles 3 things:

  • Registration of component autoloaders
  • Configuring Services and registering them with the Dependency Injection context
  • Resolve the application’s HTTP requests

In our dev folder (/Users/my-username/phalcon-app) let’s create a folder called public and add a new file called index.php with this content

<?php
use Phalcon\Di\FactoryDefault;
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Application;
use Phalcon\Url;

define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');

$loader = new Loader();

$loader->registerDirs(
    [
        APP_PATH . '/controllers/',
        APP_PATH . '/models/',
    ]
);

$loader->register();

$container = new FactoryDefault();

$container->set(
    'view',
    function () {
        $view = new View();
        $view->setViewsDir(APP_PATH . '/views/');
        return $view;
    }
);

$container->set(
    'url',
    function () {
        $url = new Url();
        $url->setBaseUri('/');
        return $url;
    }
);

$application = new Application($container);

try {
    // Handle the request
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );
    
    $response->send();
} catch (\Exception $e) {
    echo 'Exception: ', $e->getMessage();
}

You can find detailed description of what each section mean here https://docs.phalcon.io/4.0/en/tutorial-basic

But in short is:

Importing basic classes for allowing the necessary scaffolding for the application to run

use Phalcon\Di\FactoryDefault;
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Application;
use Phalcon\Url;

Create the loader and registering the directories that will need to be accessible so that the necessaries classes and functions can be used later

$loader = new Loader();

$loader->registerDirs(
    [
        APP_PATH . '/controllers/',
        APP_PATH . '/models/',
    ]
);

Create the dependency injection container

$container = new FactoryDefault();

Register the services (in our case view and url)

$container->set(
    'view',
    function () {
        $view = new View();
        $view->setViewsDir(APP_PATH . '/views/');
        return $view;
    }
);

$container->set(
    'url',
    function () {
        $url = new Url();
        $url->setBaseUri('/');
        return $url;
    }
);

Start the handler for the application requests and wrap into a try/catch

$application = new Application($container);

try {
    // Handle the request
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );
    
    $response->send();
} catch (\Exception $e) {
    echo 'Exception: ', $e->getMessage();
}

Next thing to do is to create a controller

Create a Phalcon controller

In the above index.html bootstrap file we registered the controller directory as APP_PATH . ‘/controllers/’ that translates into /Users/my-username/phalcon-app/app/controllers

This means that we have to create that folder

mkdir -p /Users/my-username/phalcon-app/app/controllers

in this folder we will add a file called IndexController.php that will be the starting point when no action has been added to the requesting url (will see more about this below)

<?php
// IndexController.php
<?php

use Phalcon\Mvc\Controller;

class IndexController extends Controller
{
    public function indexAction()
    {
        return '<h1>Hello!</h1>';
    }
}

At this stage everything should start to work but is not because if we navigate to http://localhost:8086 this is the result

Phalcon project from scratch step by step - Phalcon project from scratch step by step

Even worse when we try to open the public link this error message will appear Exception: PublicController handler class cannot be loaded

Exception: PublicController handler class cannot be loaded
Exception: PublicController handler class cannot be loaded

The reason is behind the fact that we missed one key aspect of our Phalcon project to let it run on the Apache web server:

The .htaccess file

The .htaccess file allows you to make webserver configuration changes on the fly on a per-directory basis (in a limited way). In other words we can have a limited set of configuration changes that will alter the webserver functioning only in the directory in which this file exists. All we need to do for our Phalcon application to run is to provide the right configuration so that can bootstrap the application correctly and start to serve request as the application was designed to. For doing that, in our root app folder, that should be /Users/my-username/phalcon-app, create a file called .htaccess (the dot “.” is included in the name) as follow:

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteRule   ^$ public/    [L]
    RewriteRule   ((?s).*) public/$1 [L]
</IfModule>

And what this file is doing basically is checking that the mod_rewrite is loaded as Apache extension, if so then turns on (for this folder only) and every url request will be mapped to the public ones but, because this can lead to an infinite loop, if public/ itself is in the url then do nothing and stop the processing [L].

In the public folder one instead we will need this .htaccess that is different from the above one

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond   %{REQUEST_FILENAME} !-d
    RewriteCond   %{REQUEST_FILENAME} !-f
    RewriteRule   ^((?s).*)$ index.php?_url=/$1 [QSA,L]
</IfModule>

These two lines

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

means that if the requested filename is a directory or a file on the web server filesystem, that RewriteCond it fill fail and nothing will happen (folder or file will be served). If instead this is not the case then the RewriteRule will be processed and the request will be rewritten.

This is the directory structure we should have at the end of these steps

Phalcon project from scratch step by step - Directory Structure Phalcon project setup step by step
Directory Structure Phalcon project setup step by step

Once these file will be added we can try our test again

Phalcon project from scratch step by step - Hello

Nothing extraordinary so far, we might try to make things a little bit more exciting: let’s add another controller

The default Phalcon routing

Before continuing with adding a new controller it is important at this stage to understand that by using the default Phalcon configuration, the default Phalcon routing is in place. This is going outside the scope of this article but for now let’s say that by default a URL like

http://localhost:8086/user/registration

could be easily mapped to

UserController and within that to the

public function registrationAction

This is due to the fact that if you want to make the function accessible by a URL in the form of http://your-host/controller/action you must declare the function as public and must have the action suffix.

Add another Controller

First question for who is new to this is “why?”. The reason is behind the C of the MVC pattern. M is for Model, V is for View (will see in another article this) and C is for Controller. The three forms what is commonly called the Model View Controller pattern that separates the concerns of each area by having the Model as the data represented, the View as the visualisation of those data and the Controller that is the business logic.

For adding a new controller all we have to do is to dd a new file in the app/controllers folder, let’s call ExampleController.php for now and copy and paste the lines below in it

<?php

use Phalcon\Mvc\Controller;

class ExampleController extends Controller
{
    public function firstAction()
    {
        return 'First Example';
    }

    public function SecondAction()
    {
        return 'Second Example';
    }

    public function ThirdAction()
    {
        return 'Third Example';
    }

    public function Fifth()
    {
        return 'Fifth Example';
    }
}

As you can see you can navigate to the browser to http://localhost:8086/example/second and the result should be something similar to the below image

Phalcon project from scratch step by step - Second controller
Adding second controller

You may noticed, if not I’m telling you know that if try to navigate to http://localhost:8086/example/fifth this will happen:

Phalcon project from scratch step by step - No action found
Action was not found on ‘handler’

In the next articles we area going to look at the views and routes.

Since PHP looks like an obscure technologies nowadays, if you are looking for a more structured approach more than deeply search on the web we strongly recommend this book

Learning PHP – Introduction

Learning PHP – print and echo

Learning PHP – The variables

Learning PHP – if else

Learning PHP – Arrays

Learning PHP – The loops

d3

d3 is an experienced Software Engineer/Developer/Architect/Thinker with a demonstrated history of working in the information technology and services industry. Really passionate about technology, programming languages and problem solving. He doesn't like too much the self celebration and prefers to use that time doing something useful ...i.e. coding

You may also like...