Home Web Development Learning Phalcon PHP

Learning Phalcon PHP

books-svg-icon Book
eBook $43.99 $29.99
Print $54.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $43.99 $29.99
Print $54.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Getting Started with Phalcon
About this book
Publication date:
August 2015
Publisher
Packt
Pages
328
ISBN
9781783555093

 

Chapter 1. Getting Started with Phalcon

What is Phalcon? Let's start by quoting from the documentation of the official website (http://phalconphp.com/):

"Phalcon is an open source, full stack framework for PHP written as a C-extension, optimized for high performance."

Version 2.0 of Phalcon was released in April, and it was developed with a new language called Zephir (http://zephir-lang.com/). Zephir was designed especially for developing PHP extensions, and it is quite user friendly for both (PHP and C) developers.

There are many frameworks out there. The main reasons why we choose Phalcon were for its steep learning curve, speed, and because it is decoupled. (We can use any of its components independently.) If you have some knowledge of the Model-View-Controller (MVC) and some experience with any Object-Relational Mapping (ORM), you will find working with it pretty straightforward.

We will start our journey with this first chapter where we will:

  • Configure our web server

  • Install Phalcon

  • Discuss a bit about how Phalcon works

Before starting, we assume that you are using a *nix environment. Personally, I feel comfortable with Debian distributions, especially Ubuntu, which I am using on a daily basis; so, the installations steps that we will talk about are for Ubuntu. The OS is a matter of personal choice, but I highly recommend any *nix distribution for development. (Even Microsoft decided to open source their ASP.NET for Linux early this year)

For other types of OS, you will have to search their official documentation, in terms of "how to". This book is intended to be about Phalcon and tutorials on installing different software on different kinds of OS are out of the scope of this book.

Senior developers might not agree with me on certain subjects or certain techniques and/or recommendations. In general, as a developer, I think you should analyze what is suitable for you and develop a platform according to your (or client) requirements. In addition, most importantly, there is no such thing as "The Perfect Solution". There is always room for improvement.

 

Installing the required software


We need to install the following software that we are going to use in this book:

  • PHP

  • Nginx and Apache

  • MongoDB

  • MySQL

  • GIT

  • Redis

  • Phalcon

Installing PHP

You have probably already installed PHP on your system since you are reading this book. However, just in case you haven't, here are the simple steps to quickly install the latest PHP version (Phalcon is running on PHP version >= 5.3). I recommend you to use the Personal Package Archive (PPA) from Ondřej Surý (https://launchpad.net/~ondrej/+archive/ubuntu/php5) because it has the latest PHP version available on it:

$ sudo add-apt-repository ppa:ondrej/php5
$ sudo apt-get update

If you don't want to use this step, you can simply install PHP from the official repositories:

$ sudo apt-get install php

Apache will be installed by default with PHP. However, if you want Nginx instead of Apache, you must install PHP in a certain order.

The following command will automatically install PHP and Apache. If you don't need/want to use Apache, please skip using this command:

$ sudo apt-get install php5 php5-fpm

To avoid Apache installation, execute the following commands in the exact same order:

$ sudo apt-get install php5-common
$ sudo apt-get install php5-cgi
$ sudo apt-get install php5 php5-fpm

The php5-cgi package fulfills the dependencies that would otherwise be fulfilled by Apache.

Installing Nginx

To install the Nginx web server, we need to execute the following commands:

$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get update
$ sudo apt-get install nginx

Installing MySQL

MySQL is probably the most widely spread RDBMS system with a market share that is greater than 50 percent. Since we are going to use it to develop our project, we need to install it by executing the following command:

$ sudo apt-get install mysql-server

Note

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Installing Redis

Redis is an advanced key-value storage/cache system. We are going to use this mostly for our session and to cache objects to improve the speed of our application. Let's install it by executing the following commands:

$ sudo add-apt-repository ppa:chris-lea/redis-server
$ sudo apt-get update
$ sudo apt-get install redis-server
$ sudo apt-get install php5-redis

Installing MongoDB

MongoDB is a document database (NoSQL database) system. We will use this to store data that is accessed frequently. Let's install it:

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
$ echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
$ sudo apt-get update
$ sudo apt-get install -y mongodb-org
$ sudo service mongodb start
$ sudo apt-get install php5-mongo

Installing Git

Git is a distributed version control system that we will use to track changes to our application and much more. We will install Git by executing the following command:

$ sudo apt-get install git

Tip

I strongly recommend that you use the latest versions of all software as much as possible.

 

Installing Phalcon


Now that we have installed all the required software, we will proceed with the installation of Phalcon. Before we continue, we must install some dependencies:

$ sudo apt-get install php5-dev libpcre3-dev gcc make php5-mysql

For Windows systems and more details about how to compile the extension on different systems, please check the latest documentation at http://phalconphp.com/en/download.

Now, we can clone the repository and compile our extension:

$ git clone --depth=1 git://github.com/phalcon/cphalcon.git
$ cd cphalcon/build
$ sudo ./install
$ echo 'extension=phalcon.so' | sudo tee /etc/php5/mods-available/phalcon.ini

$ sudo php5enmod phalcon
$ sudo service php5-fpm restart

If everything goes well, you should be able to see Phalcon in the list of PHP installed modules:

$ php -m | grep phalcon
 

The Apache and Nginx configuration files


We will use /var/www/learning-phalcon.localhost as the default directory for our project, and we will refer to it as the root folder. Please create this folder:

$ sudo mkdir -p /var/www/learning-phalcon.localhost/public

Of course, if you want, you can use another folder. Let's create a test file in our public folder under the root directory with some PHP content:

$ cd /var/www/learning-phalcon.localhost/public
$ echo "<?php date();" > index.php

Apache

Let's switch to the default directory where Apache holds the configuration files for the available websites, using the command line: $ cd /etc/apache2/sites-available/. After that, perform the following set of steps:

  1. Using your favorite editor, create a file named learning-phalcon.localhost for apache version < 2.4 or learning-phalcon.localhost.conf for apache version >= 2.4:

    $ vim learning-phalcon.localhost.conf
    
  2. Now, paste the following content to this file:

    <VirtualHost *:80>
        DocumentRoot "/var/www/learning-phalcon.localhost"
        DirectoryIndex index.php
        ServerName learning-phalcon.localhost
        ServerAlias www.learning-phalcon.localhost
    
        <Directory "/var/www/learning-phalcon.localhost/public">
            Options All
            AllowOverride All
            Allow from all
        </Directory>
    </VirtualHost>
  3. Then, switch to the public folder and add a file named .htaccess to it:

    $ cd /var/www/learning-phalcon.localhost/public
    $ vim .htaccess
    
  4. Then, add the following content to the .htaccess file:

    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
    </IfModule>
  5. This will not work unless you have enabled mod_rewrite. To do so, execute this command:

    $ sudo a2enmod rewrite
    
  6. Now that we have configured our virtual host, let's enable it:

    $ sudo a2ensite learning-phalcon.localhost
    $ sudo service apache2 reload
    

The host file

If you open a browser and type http://www.learning-phalcon.localhost/, you'll receive a host not found or connection error. This is because there is no name resolver for this TLD (short for Top Level Domain). To fix this, we edit our host file and add this name:

$ echo "127.0.0.1 learning-phalcon.localhost www.learning-phalcon.localhost" | sudo tee /etc/hosts

Restart your browser and type the address http://www.learning-phalcon.localhost/ again. If everything goes well, you should see the current date/time.

Nginx

If you choose to use Nginx (which I recommend, especially because it can serve more concurrent clients with higher throughput, and it serves static content more efficiently) instead of Apache, here is what you need to do:

Locate the config folder of Nginx (in Ubuntu, it is installed under /etc/nginx/). Create a file named learning-phalcon.localhost in your sites-available folder (by navigating to /etc/nginx/sites-available):

$ cd /etc/nginx/sites-available
$ vim learning-phalcon.localhost

Now, add the following content to it:

server {
    listen 80;
    server_name learning-phalcon.localhost;

    index index.php;
    set $root_path "/var/www/learning-phalcon.localhost/public";
    root $root_path;

    client_max_body_size 10M;

    try_files $uri $uri/ @rewrite;

    location @rewrite {
        rewrite ^/(.*)$ /index.php?_url=/$1;
    }

    location ~ \.php {
        fastcgi_index /index.php;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_intercept_errors on;
        include fastcgi_params;

        fastcgi_split_path_info ^(.+\.php)(/.*)$;

        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_param SCRIPT_FILENAME $realpath_root/index.php;
    }

    location ~* ^/(css|img|js|flv|swf|download)/(.+)$ {
        root $root_path;
    }

    location ~ /\.ht {
        deny all;
    }
}

Note

In some environments, you might need to edit your php.ini file and set cgi.fix_pathinfo = 0.

Then, save the file and restart Nginx:

$ sudo service nginx restart

Please edit and save your host file (check The host file section), then open your browser and type http://www.learning-phalcon.localhost/. At this point, you should see a page that shows the current date/time.

There are many possible methods to install and configure PHP and Apache/Nginx. Feel free to do a simple Google search and choose one that fits you better, if my method is not the optimal one for your needs.

Assuming that everything went well until now, we will go further by learning a little bit about Phalcon's internals.

 

Understanding the framework's internals


In this section, I will try to make a short introduction to the common parts of the framework. Most of the text presented here is part of the official documentation that you should always read. The idea of this section is to make you familiar with the most common methods and components that will help you to understand quickly how the framework works.

Tip

Please note that images in this book might contain the text http://learning-phalcon.dev. You need to ignore that and use http://learning-phalcon.localhost as suggested in the chapter.

The dependency injection

Probably one of the most powerful characteristics of Phalcon is the dependency injection (DI). If you have no idea about dependency injection, you should read at least the wiki page for this design pattern at http://en.wikipedia.org/wiki/Dependency_injection:

"Dependency injection is a software design pattern that implements inversion of control for resolving dependencies. An injection is the passing of a dependency (a service or software module) to a dependent object (a client). The service is made part of the client's state. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.

Dependency injection allows a program design to follow the dependency inversion principle."

The term "Dependency injection" was coined by Martin Fowler.

A real-life example of dependency injection might be the following situation: Suppose you go shopping. At the mall, you will need a bag to put your groceries, but you forgot to take one when you left your home. In this case, you will need to buy a bag. In development, buying this bag can be quite expensive. So, what if your door has a scanner that scans your body for a bag, and will not open unless you have one? This can be called dependency injection.

Phalcon uses the \Phalcon\DI component, which is a component that implements the Inversion of Control pattern. This reduces the overall code complexity.

The framework itself or the developer can register services. Phalcon has many built-in components that are available in the DI container, such as the following ones:

  • Request and response

  • Logger

  • Crypt

  • Flash

  • Router and configuration

  • View

  • Cache

  • Session

Setting up a new component in the DI is as easy as the following code:

<?php

$di = new Phalcon\DI();
// Lazy load
$di['mail'] = function() {
  return new \MyApp\Mail();
};

When you need to access the "mail" component, in a controller for example, you can simply call it:

<?php

$mail = $this->getID()->get('mail');
// or
$mail = $this->getDI()->getMail();

If you need to create your own DI, Phalcon or the DiInterface interface must be implemented to replace the one provided by Phalcon, or you must extend the current one.

These are just a few dummy examples so that you can have an idea about Phalcon's DI by the time we start our project. In the meanwhile, please take your time and read the official documentation that can be found at http://docs.phalconphp.com/en/latest/reference/di.html.

The request component

The request component is probably one of the most used components in any framework. It handles any HTTP request (such as GET, POST, or DELETE, among others) and also provides a few shortcuts for the $_SERVER variable. Most of the time, we will use the request component in the controllers. The Phalcon documentation (http://docs.phalconphp.com/en/latest/reference/mvc.html) states the following:

"The controllers provide the "flow" between models and views. Controllers are responsible for processing the incoming requests from the web browser, interrogating the models for data, and passing that data on to the views for presentation."

In Phalcon, all controllers should extend the \Phalcon\Mvc\Controller component, and the name of the public methods that we want to access via HTTP GET should have the suffix Action. For example:

<?php

class ArticleController extends \Phalcon\Mvc\Controller
{
  // Method for rendering the form to create an article
  public function createAction()
  {
  }

  // Method for searching articles
  public function searchAction()
  {
  }

  // This method will not be accessible via http GET
  public function search()
  {
  }
}

Okay. So, how do we use the request component? Easy! Do you remember that we talked about built-in components in the DI section? The request component is one of them. All we need to do is get the DI. Here is an example of how to get and use the request component:

<?php

class ArticleController extends \Phalcon\Mvc\Controller
{
  public function searchAction()
  {
    $request = $this->getDI()->get('request');
    // You can also use $request = $this->request; but I don't
    // recommend it because $this->request can be easily overwritten
    // by mistake and you will spend time to debug ... nothing.

    $request->getMethod(); // Check the request method
    $request->isAjax(); // Checks if the request is an ajax request
    $request->get(); // Gets everything, from the request (GET, POST, DELETE, PUT)
    $request->getPost(); // Gets all the data submitted via POST method
    $request->getClientAddress(); // Return the client IP
  }
}

These are just a few common methods that are built into the request component. Let's continue with the next important component—Response.

The response component

So, what can this component do? Well, pretty much everything that is response or output related. Using it, we can set headers, do redirects, send cookies, set content, and much more. Here is a list of common methods from this component:

<?php

public function testRedirectAction()
{
  $response = $this->getDI()->get('response');
   // or you can use $this->response directly
  
  // Redirect the user to another url
  $this->view->disable();
  return $response->redirect('http://www.google.com/', true);
}

The redirect method accepts three parameters: a location (string), if it is an external redirect (this is a Boolean type which is by default false), and a status code (http status code range). The following lines of code is the redirect method:

  <?php
  /**
  * Redirect by HTTP to another action or URL
  *
  * @param string $location
  * @param boolean $externalRedirect
  * @param int $statusCode
  * @return \Phalcon\Http\ResponseInterface
  */
  public function redirect($location, $externalRedirect, $statusCode);

Another useful method is the setHeader method:

<?php

public function testSetHeaderAction()
{
  $this->response->setHeader('APIKEY', 'AWQ23XX258561');
}

The preceding example sets a header named APIKEY with the value as AWQ23XX258561. Sending headers is a common approach when you develop APIs. You can send any type of headers and overwrite current headers using this method.

Content related methods: setContent() and setJsonContent(). Let's take for example the following code:

<?php

public function testContentAction()
{
  // First, we disable the view if there is any
  $this->view->disable();
  
  // Set a plain/text or html content
  $this->response->setContent('I love PhalconPHP');

  // OR

  // Set a json content (this will return a json object)
  $this->response->setJsonContent(array(
    'framework' => 'PhalconPHP'
    'versions' => array(
      '1.3.2',
      '1.3.3',
      '2.0.0'
    )
  ));

  // We send the output to the client
  return $this->response->send();
}

When you need to send any JSON content, you should set the header as application/json using the built-in method in the response object:

<?php

$this->response->setContentType('application/json', 'UTF-8');

Now that we know the basics about response/request components, we might find ourselves in a situation where we may need to log different things, such as errors. For this, we need to check the logger component.

The logger component

In a production environment, we cannot afford to throw errors or blank pages at the client. We will avoid this and log the errors in a log file. You will read more about this in the next chapters. To sum it up, we will implement a custom logger to our DI, catch exceptions, and then log them. For example, perform the following set of steps:

  1. Set the custom logger in DI using the following code:

    <?php
    
    $di['logger'] = function() {
      $error_file = __DIR__.'/../logs/'.date("Ymd_error").'log';
      return new \Phalcon\Logger\Adapter\File($error_file, array('mode' => 'a+'));
    };
  2. Create a method that will throw an exception, catch it, and log it, as follows:

    <?php
    
    public function testLoggerAction()
    {
      try {
        $nonExistingComponent = $this->getDI()->get('nonExistingComponent');
        $nonExistingComponent->executeNonExistingMethod();
      } catch (\Exception $e) {
        $this->logger->error($e->getMessage());
        return $this->response->redirect('error/500.html');
      }
    }

In the preceding example, we try to execute a nonexistent method, and our code will throw an exception that we catch. It will log it and then redirect the user to a friendly error page, error/500.html. You will notice that our logger component calls a method named error. There are other methods that are implemented, such as, debug, info, notice, warning, and so on.

The logger component can be transactional. (Phalcon stores the logs temporarily in memory, and later on, it writes the data to the relevant adapter.) For example, consider the following code snippet:

<?php

$this->logger->begin();

$this->logger->error('Ooops ! Error !');
$this->logger->warning('A warning message');

$this->logger->commit();

The crypt component

Crypt is a very useful component if someone needs to encrypt data and decrypt it on your side. One situation where you might want to use the crypt component is to send data over the HTTP get method or save sensitive information in your database.

This component has many built-in methods such as encrypt, decrypt, getAvailableChipers, setKey, getKey, and so on. Here is an example of using the crypt component in the HTTP get method.

First, we overwrite the DI, and then we pass a key to it in order to avoid setting it every time:

<?php

$di['crypt'] = function () {
  $crypt = new \Phalcon\Crypt();
  $crypt->setKey('0urSup3rS3cr3tK3y!?');

  return $crypt;  
};

public function sendActivationAction()
{
  $activation_code = $this->crypt->encryptBase64('1234');
  $this->view->setVar('activation_code', $activation_code);
}

public function getActivationAction($code)
{
  if ('1234' == $this->crypt->decryptBase64($code)) {
    $this->flash->success('The code is valid ');
  } else {
    $this->flash->error('The code is invalid');
  }
}

Of course, you are probably never going to use it this way. The preceding example just demonstrates the power of this component. You might have noticed that there is a new DI method called flash. We are going to talk about it next.

The flash component

This component is used to send notifications to the client and inform him or her about the status of the component's actions. For example, we can send a successful message after a user has completed the registration on our website or submitted a contact form.

There are two kinds of flash messages—direct and session—and both are available in DI. The direct method outputs the message directly and cannot be loaded on a future request. On the contrary, the session method, stores the messages in a session, and they are automatically cleared after they are printed.

Here is a common usage of flash direct and flash session, assuming that you have a page called register, and you post the data on the same page:

public function registerAction()
{
  // … code
  if ($errors) {  
    $this->flash->warning('Please fix the following errors: ');
    foreach($errors as $error) {
      $this->flash->error($error);
    }
  } else {
    $this->flash->success('You have successfully registered on our website');
  }
}  

In our view, we will render the messages using the getContent() method or content() in the template engine Volt (we'll cover this later in the chapter).

If we need to redirect our user to another page (let's call it registerSuccess), then we need to use the flash session method; otherwise, the message will not appear.

<?php

public function registerAction()
{
  // render our template
}

The register template will contain a form with method post and action pointing to the create method. The create method will look something like this:

<?php

public function createAction()
{
  if ($errors) {  
    $this->flashSession->warning('Please fix the following errors: ');
    foreach($errors as $error) {
      $this->flashSession->error($error);
    }
  } else {
    $this->flashSession->success('You have successfully registered on our website');
  }

  return $this->response->redirect('/register');
}

In the preceding example, we set the messages in the session using the flashSession method, and we redirect the user back to the register page. In order to render the messages in our view, we need to call the method flashSession()->output();.

Tip

The recommended way is to forward the request with the help of dispatcher, not using redirects. If you use redirects, the user will lose all the data that he or she filled in the form.

The router component

The router component helps us to map friendly URLs to our controllers and actions.

By default, if the rewrite module is enabled in your web server, you will be able to access a controller named Post and the read action like this: http://www.learning-phalcon.localhost/post/read. Our code can look like this:

<?php

class PostController extends \Phalcon\Mvc\Controller
{
  public function readAction()
  {
    // get the post
  }
}

However, sometimes, this code is not apt if you need to translate the URLs into multiple languages, or if you need to name the URLs in a different way to how they are defined in the code. Here is a usage example for the router component:

<?php

$router = new \Phalcon\Mvc\Router();
// Clear the default routes
$router->clear();

$st_categories = array(
  'entertainment',
  'travel',
  'video'
);

$s_categories = implode('|', $st_categories);

$router->add('#^/('.$s_categories.')[/]{0,1}$#', array(
    'module' => 'frontend',
    'controller' => 'post',
    'action' => 'findByCategorySlug',
    'slug' => 0
));

In the preceding example, we map all the categories to the controller post and action findByCategorySlug. The router component allows us to use regular expressions for our URLs. With preg_match, this can be represented as follows

$url = 'http://www.learning-phalcon.localhost/video';
preg_match('#^/(entertainment|travel|video)[/]{0,1}$#', $url);

By accessing http://www.learning-phalcon.localhost/video, the request will be forwarded to the findByCategorySlug action from the post controller:

<?php

class PostController extends \Phalcon\Mvc\Controller
{
  public function findByCategorySlug()
  {
    $slug = $this->dispatcher->getParam('slug', array('string', 'striptags'), null);

    // We access our model (entity) to get all the posts from this category
    $posts = Posts::findByCategorySlug($slug);

    if ($posts->count() > 0) {
      $this->view->setVar('posts', $posts);
    } else {
      throw new \Exception('There are no posts', 404);
    }
  }
}

The getParam() method has three parameters. The first one is the name that we are searching for, the second parameter is an array of filters that can be applied automatically, and the third parameter is the default value in case the requested name does not exist or is not set.

We will discuss models in the next chapter. This was just a simple example of how you can use the router.

The router also supports a precheck of the request method. You may be used to check whether the method is POST, DELETE, PUT, or GET, like this:

<?php

if ($_SERVER['REQUEST_METHOD'] == 'post') {
  // process the information
}

While this is perfectly correct, it is not very friendly for our code. Phalcon's router has this capability by which you can add the right type of request that you are expecting, without the need to check this in your code:

<?php

// Add a get route for register method within the user controller
$router->addGet('register', 'User::register');

// Add a post route for create method, from the user controller
$router->addPost('create', 'User::create');

This is the basic usage of the router. As always, please read the documentation in order to learn everything about this component.

Tip

You can find out more about routing on the official documentation at http://docs.phalconphp.com/en/latest/reference/routing.html.

The config component

This component can handle configuration files of various formats by using adapters. Phalcon has two built-in adapters for it, which are INI and Array. Using INI files is probably never a good idea. Therefore, I recommend you to make use of native arrays.

What kind of data can or needs to be stored in these files? Well, pretty much everything that will be needed globally in our application, such as database connection parameters. In the old days, we used $_GLOBALS (a big security issue), or we used the define() method, and then gradually we started using it globally.

Here is an example of a config file, and how we can use it:

<?php

$st_settings = array(
  'database' => array(
    'adapter'  => 'Mysql',
    'host'     => 'localhost',
    'username' => 'john',
    'password' => 'johndoe',
    'dbname'     => 'test_database',
  ),
  'app' => array(
    'name' => 'Learning Phalcon'
  )
);

$config = new \Phalcon\Config($st_settings);

// Get our application name:
echo $config->app->name; // Will output Learning Phalcon

The config object can be converted back to an array by using toArray() method:

<?php

$st_config = $config->toArray();
echo $config['app']['name']; // Will output Learning Phalcon

Another useful method for this object is the merge method. If we have multiple configuration files, we can easily merge them into one object:

<?php

$config = array(
  'database' => array(
    'adapter'  => 'Mysql',
    'host'     => 'localhost',
    'dbname'     => 'test_database',
  ),
  'app' => array(
    'name' => 'Learning Phalcon'
  )
);

$config2 = array(
  'database' => array(
    'username' => 'john',
    'password' => 'johndoe',
  )

Now, the $config object will have the same content as it did before.

Tip

There are two other adapters that are not implemented yet (YAML and JSON), but you can use them if you clone Phalcon's incubator repository (https://github.com/phalcon/incubator). This repository contains a collection of adapters/helpers that might be integrated in Phalcon in the near future.

The view component

This component is used to render our templates. By default, the templates have the .phtml extension, and they contain HTML and PHP code. Here are some examples on how to use the view:

  1. First, we set up the view in the DI using the following code snippet:

    <?php
    
    $di['view'] = function () use ($config) {
      $view = \Phacon\Mvc\View();
      // Assuming that we hold our views directory in the configuration file
      $view->setViewsDir($config->view->dir);
    
      return $view;
    };  
  2. Now, we can use this service as follows:

    <?php
    
    class PostControler extends \Phalcon\Mvc\Controller
    {
      public function listAction()
      {
        // Retrieve posts from DB
        $posts = Post:find();
        $this->view->setVar('pageTitle', 'Posts');
        $this->view->setVar('posts', $posts);
      }
    }
  3. Next, we need to create a view template that must look like this:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title><?php echo $pageTitle; ?></title>
    </head>
    <body>
    <?php foreach($posts as $post) { ?>
      <p><?php echo $post->getPostTitle(); ?></p>
      <p><?php echo $post->getPostContent(); ?></p>
    <?php } ?>
    </body>
    </html>

Simple, isn't it? This component also supports hierarchical rendering. You can have a base layout, a general template for posts, and a template for a single post. Let's take, for example, the following directory structure:

app/views/
- index.phtml
- post/detail.phtml

Phalcon will first render app/views/index.phtml. Then, when we request for detailAction() from the post controller, it will render app/views/post/details.phtml. The main layout can contain something similar to this code:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Learning Phalcon</title>
</head>
<body>
<?php echo $this->getContent(); ?>
</body>
</html>

And, the details.phtml template will have the following content:

<?php foreach($posts as $post) { ?>
  <p><?php echo $post->getPostTitle(); ?></p>
  <p><?php echo $post->getPostContent(); ?></p>
<?php } ?>

This component also allows you to pick different templates to set a render level, disable or enable the view, and much more.

Phalcon has a built-in template engine named Volt. If you are familiar with PHP template engines such as Smarty or Twig, you will want to use them for sure. Volt is almost identical to Twig, and you will find it very useful—it is inspired by Jinja (http://jinja.pocoo.org/). You can even use your own template engine, or any other template engine that you can find there.

In order to enable the Volt template engine, we need to make a small modification to our view service, and we need to create a Volt service; here is how to do this:

<?php

$di['voltService'] = function($view, $di) use ($config) {

    $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);

    if (!is_dir($config->view->cache->dir)) {
        mkdir($config->view->cache->dir);
    }

    $volt->setOptions(array(
        "compiledPath" => $config->view->cache->dir,
        "compiledExtension" => ".compiled",
        "compileAlways" => false
    ));

    $compiler = $volt->getCompiler();

    return $volt;
};

// First, we setup the view in the DI
$di['view'] = function () use ($config) {
  $view = \Phacon\Mvc\View();
  $view->setViewsDir($config->view->dir);
  $view->registerEngines(array(
    '.volt' => 'voltService'
  ));

  return $view;
};

By adding this modification and voltService, we can now use this template engine. From the inheritance point of view, Volt acts a little bit differently. We first need to define a main layout with named blocks. Then, the rest of the templates should extend the main layout, and we need to put our content in the same blocks as the main layout. Before we look at some examples, I will tell you a little bit about Volt's syntax, the details are as follows.

  • The syntax for outputting data or for echoing content:

    {{ my_content }}
  • The syntax for defining blocks:

    {% block body %} Content here {% endblock %}
  • The syntax to extend a template (this should be the first line in your template):

    {% extends 'layouts/main.volt' %}
  • The syntax to include a file:

    {% include 'common/sidebar.volt' %}
  • The syntax to include a file and pass variables:

    {% include 'common/sidebar' with{'section':'homepage'} %}

    Tip

    Please note the missing extension. If you pass variables, you MUST omit the extension.

  • The syntax for control structures (for, if, else):

    {% for post in posts %}
      {% if post.getCategorySlug() == 'entertainment' %}
        <h3 class="pink">{{ post.getPostTitle() }}</h3>
      {% else %}
        <h3 class="normal">{{ post.getPostTitle() }}</h3>
      {% endif %}
    {% endfor %}
  • The syntax for the loop context:

    {% for post in posts %}
      {% if loop.first %}
        <h1>{{ post.getPostTitle() }}</h1>
      {% endif %}
    {% endif %}
  • The syntax for assignments:

    {% set title = 'Learning Phalcon' %}
    {% set cars = ['BMW', 'Mercedes', 'Audi'] %}

The list is long. Additionally, you can use expressions, comparison operators, logic operators, filters, and so on. Let's write a simple template to see how it works:

<!-- app/views/index.volt -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block pageTitle %}Learning Phalcon{% endblock%}</title>
</head>
<body>
  <div class='header'>{% block header %}Main layout header{% endblock%}</div>
  <div class='content'>{% block content %}This is the main layout content{% endblock %}</div>
</body>
</html>
 
<!-- app/views/post/detail.volt 
{% extends 'index.volt' %}

{% block pageTitle  %}
  {{ post.getPostTitle() }}
{% endblock %}

{% block header %}
  Post layout
{% endblock %}

{% block content %}
  <p>{{ post.getPostContent() }}</p>
{% endblock%}

Note

You can read the full documentation for the view component at http://docs.phalconphp.com/en/latest/reference/views.html and for Volt at http://docs.phalconphp.com/en/latest/reference/volt.html.

The session component

This component provides object-oriented wrappers to access session data. To start the session, we need to add the service into the DI container:

<?php

$di['session'] = function () {
  $session = new Phalcon\Session\Adapter\Files();
  $session->start();
  return $session;  
};

The following is a code example for working with session:

<?php

public function testSessionAction()
{
  // Set a session variable
  $this->session->set('username', 'john');

  // Check if a session variable is defined
  if ($this->session->has('username')) {
    $this->view->setVar('username', $this->session->get('username'));
  }

  // Remove a session variable
  $this->session->remove('username');
  
  // Destroy the session
  $this->session->destroy();
}

If you check Phalcon's incubator, there are many available adapters, such as Redis, Database, Memcache, and Mongo. You can also implement your own adapter.

Note

You can read the official documentation at http://docs.phalconphp.com/en/latest/reference/session.html.

The cache component

To improve the performance of some applications, you will need to cache data. For example, we can cache the query results for a post. Why? Imagine 1 million views or posts. Normally, you will query the database for it, but this will mean 1 million queries (you can multiply this by at least 3, if you are using it, and for ORM—this means 3 million queries at least). Why? When you query, the ORM will act like this:

  1. It'll check if the table exists, in the information schema:

    SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME`='user'
  2. Then, it'll check whether it's executing a "Describe" of the table:

    DESCRIBE `user`
  3. Then, whether it's executing the actual query:

    SELECT * FROM user.
  4. If the user table has relations, the ORM will repeat each of the preceding steps for each relation.

To solve this problem, we will save the post object into our caching system.

Personally, I use Redis and Igbinary. Redis is probably the most powerful tool, since it stores the data in memory and, saves the data on disk for redundancy. This means that every time you request the data from cache, you will get it from memory. Igbinary (https://pecl.php.net/package/igbinary) is a replacement for the standard php serializer. Here is an example cache service:

<?php

$di['redis'] = function () {
    $redis = new \Redis();
    $redis->connect(
        '127.0.0.1',
        6379
    );

    return $redis;
};

$di['cache'] = function () use ($di, $config) {
    $frontend = new \Phalcon\Cache\Frontend\Igbinary(array(
        'lifetime' => 86400
    ));
    $cache = new \Phalcon\Cache\Backend\Redis($frontend, array(
        'redis' => $di['redis'],
        'prefix' => 'learning_phalcon'
    ));

    return $cache;
};

The cache component has the following methods that are commonly used:

<?php

// Save data in cache
$this-cache->save('post', array(
  'title' => 'Learning Phalcon',
  'slug' => 'learning-phalcon',
  'content' => 'Article content'
));

// Get data from cache
$post = $this->cache->get('post');

// Delete data from cache
$this->cache->delete('post');
 

Summary


In this chapter, we installed the required software, created the configuration files for the web servers, and you learned a little bit about Phalcon's internals. In the next chapters, we will learn by example, and everything will be much clearer.

Take your time, and before going further, read a little bit more about anything in which you don't have experience.

In the following chapter, we will look at how to set up the MVC structure and the environment for our project.

Latest Reviews (1 reviews total)
Learning Phalcon PHP
Unlock this book and the full library FREE for 7 days
Start now