Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Learning Phalcon PHP
Learning Phalcon PHP

Learning Phalcon PHP: Learn Phalcon interactively and build high-performance web applications

eBook
$38.99 $43.99
Paperback
$54.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Learning Phalcon PHP

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.

Left arrow icon Right arrow icon

Description

Phalcon is a full-stack PHP framework implemented as a C extension. Building applications with Phalcon will offer you lower resource consumption and high performance whether your application runs on a Linux machine or a Windows one. Phalcon is loosely coupled, allowing you to use its objects as glue components based on the needs of your application. Phalcon PHP's mission is to give you an advanced tool to develop faster websites and applications. This book covers the most common and useful parts of PhalconPHP, which will guide you to make the right decisions while developing a Phalcon-driven application. You will begin the journey by installing and setting up Phalcon for your environment followed by the development of each module. You will be introduced to Phalcon's ORM and ODM. Furthermore, you will also be able to create the first models and database architecture for your project. You will then cover command-line applications, API module, volt syntax, and hierarchical views. Installing and working with Node and Bower for assets management will also be covered. Finally, you will gain insights into creating the backoffice and frontend module along with best practices and resources for development with Phalcon PHP. By the end of this book, you will be able to confidently develop any kind of application using the Phalcon PHP framework in a short time.

Who is this book for?

If you are a web developer and want to build effective web applications with Phalcon PHP, then this book is ideal for you. The book does not assume detailed knowledge of PHP frameworks.
Estimated delivery fee Deliver to United States

Economy delivery 10 - 13 business days

Free $6.95

Premium delivery 6 - 9 business days

$21.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 26, 2015
Length: 328 pages
Edition : 1st
Language : English
ISBN-13 : 9781783555093
Languages :

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to United States

Economy delivery 10 - 13 business days

Free $6.95

Premium delivery 6 - 9 business days

$21.95
(Includes tracking information)

Product Details

Publication date : Aug 26, 2015
Length: 328 pages
Edition : 1st
Language : English
ISBN-13 : 9781783555093
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 98.98
Phalcon Cookbook
$43.99
Learning Phalcon PHP
$54.99
Total $ 98.98 Stars icon

Table of Contents

11 Chapters
1. Getting Started with Phalcon Chevron down icon Chevron up icon
2. Setting Up the MVC Structure and the Environment for Our Project Chevron down icon Chevron up icon
3. Learning Phalcon's ORM and ODM Chevron down icon Chevron up icon
4. Database Architecture, Models, and CLI Applications Chevron down icon Chevron up icon
5. The API Module Chevron down icon Chevron up icon
6. Assets, Authentication, and ACL Chevron down icon Chevron up icon
7. The Backoffice Module (Part 1) Chevron down icon Chevron up icon
8. The Backoffice Module (Part 2) Chevron down icon Chevron up icon
9. The Frontend Module Chevron down icon Chevron up icon
10. Going Further Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the digital copy I get with my Print order? Chevron down icon Chevron up icon

When you buy any Print edition of our Books, you can redeem (for free) the eBook edition of the Print Book you’ve purchased. This gives you instant access to your book when you make an order via PDF, EPUB or our online Reader experience.

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela