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://brewedbrilliance.net/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
- The bootstrap file
- The default Phalcon routing
- Create a Phalcon controller
- The .htaccess file
- Add another Controller
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
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 we will probably get an error message or not the expected result!
Even worse when we try to open the public link this error message will appear 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.
Once these file will be added we can try our test again and this time should work! But 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 as the expected one!
In the next articles we area going to look at the views and routes.
Other articles of the same series
Share this content: