Book Image

Phalcon Cookbook

By : Serghei Iakovlev, David Schissler
1 (2)
Book Image

Phalcon Cookbook

1 (2)
By: Serghei Iakovlev, David Schissler

Overview of this book

Phalcon is a high-performance PHP framework delivered as a PHP extension. This provides new opportunities for speed and application design, which until recently have been unrealized in the PHP ecosystem. Packed with simple learning exercises, technology prototypes, and real-world usable code, this book will guide you from the beginner and setup stage all the way to advanced usage. You will learn how to avoid niche pitfalls, how to use the command-line developer tools, how to integrate with new web standards, as well as how to set up and customize the MVC application structure. You will see how Phalcon can be used to quickly set up a single file web application as well as a complex multi-module application suitable for long-term projects. Some of the recipes focus on abstract concepts that are vital to get a deep comprehension of Phalcon and others are designed as a vehicle to deliver real-world usable classes and code snippets to solve advanced problems. You’ll start out with basic setup and application structure and then move onto the Phalcon MVC and routing implementation, the power of the ORM and Phalcon Query Language, and Phalcon’s own Volt templating system. Finally, you will move on to caching, security, and optimization.
Table of Contents (17 chapters)
Phalcon Cookbook
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Preface
Index

Understanding the request life cycle


A deeper understanding of the request life cycle will lift the veil on the main application mechanisms and offers you the possibility to handle requests more flexibly. This recipe demonstrates how each request usually flows within the framework.

Getting ready

To complete this recipe, you need to have a web server installed and, what is more, you must make the base configuration of your application. Usually, by base configuration, we mean that you have your application deployed and have the services configured in all the ways available. You should understand the main class autoloading principles in Phalcon and know how to configure Phalcon Loader. Besides, you need to configure logging in PHP into a readable file.

How to do it…

Follow these steps to complete this recipe:

  1. Open the application service configuration and create an event manager, which we will use during further steps:

    $em = new Phalcon\Events\Manager();
  2. Then, add the following routing setting:

    $di->setShared('router', function () use($em) {
      $router = new \Phalcon\Mvc\Router();
      $router->add(
        '/:controller/:action/:params',
        [
          'controller' => 1,
          'action'     => 2,
          'params'     => 3
        ]
      );
    
      $em->attach('router', new RouterListener);
      $router->setEventsManager($em);
    
      return $router;
    });
  3. Now we need the router event listener. Create a directory with the name library in your project root directory. Add that directory into the Phalcon autoloader and create a class named RouterListener in it, inserting the following content:

    <?php
    use Phalcon\Mvc\Router;
    use Phalcon\Mvc\Router\Route;
    use Phalcon\Events\Event;
    use Phalcon\Di;
    
    class RouterListener
    {
      public function beforeCheckRoute(Event $event, Router $router)
      {
        $request = Di::getDefault()->getShared('request');
        error_log('[REQUEST] ' . $request->getMethod() . ": " . $request->getURI());
      }
      public function matchedRoute(Event $event, Router $router, Route $route)
      {
        error_log('[ROUTE] matched pattern: ' . $route->getPattern());
    }
  4. Create a ProductsController in the app/controllers file and place the following code there:

    <?php
    class ProductsController extends Phalcon\Mvc\Controller
    {
        public function viewAction($id)
        {
            $this->tag->setTitle('View Product');
            $this->view->setVars([
                'product_id'    => $id,
                'product_name'  => 'Pizza',
                'product_price' => 12,
            ]);
        }
    }
  5. Then, create a view in app/views/products/view.volt and place the following code there:

    {{ content() }}
    <h1>{{ product_name }}</h1>
    <p>
        <strong>ID:</strong> {{ product_id }}<br>
        <strong>Price:</strong>
        <span style="text-decoration: line-through">{{ product_price / 0.25 }}</span>
        <strong style="color:darkred">{{ product_price }}</strong>
    </p>
  6. Add an initial dispatcher setting into the service configuration, as follows:

    $di->setShared('dispatcher', function() use ($em) {
      $dispatcher = new Phalcon\Mvc\Dispatcher;
    
      $em->attach('dispatch', new ActionListener);
      $dispatcher->setEventsManager($em);
    
      return $dispatcher;
    });
  7. Then, we have to create the Event Listener. For this step, create an ActionListener class in the library directory and put the following content into this class:

    <?php
    use Phalcon\Events\Event;
    use Phalcon\Mvc\Dispatcher;
    
    class ActionListener
    {
      public function afterExecuteRoute(Event $event, Dispatcher $dispatcher)
      {
          $report = [
        $dispatcher->getControllerName() => $dispatcher->getControllerClass(),
        $dispatcher->getActionName()     => $dispatcher->getActiveMethod(),
        'params'                         => $dispatcher->getParams()
      ];
      
      error_log('[ACTION] ' . json_encode($report));
      }
    }
  8. Open the application services definition and add a view service into the DI container:

    $di->setShared('view', function () use ($config, $em) {
      $view = new \Phalcon\Mvc\View();
      $view->setViewsDir($config->get('application')->viewsDir);
    
      $view->registerEngines([
        '.volt' => function ($view, $di) use ($config) {
          $volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
          return $volt;
        }
      ]);
    
      $em->attach('view', new ViewListener());
      $view->setEventsManager($em);
    
      return $view;
    });
  9. Finally, create the listener named ViewListener in the library directory and put the following code into it:

    <?php
    use Phalcon\Events\Event;
    use Phalcon\Mvc\View;
    
    class ViewListener
    {
      public function afterRender(Event $event, View $view)
      {
        error_log('[VIEW] ' . $view->getActiveRenderPath());
        return true;
      }
    }

If you've done it all correctly, after you go to http://your_site/products/view/1 in your browser, you will see the product card. Note that we use the hostname your_site in our example; however, you should use your real project hostname instead.

Additionally, if you look at the content of your php-log file, you will see something like this:

[30-Sep-2015 02:06:48 Europe/Berlin] [REQUEST] GET: /products/view/1
[30-Sep-2015 02:06:48 Europe/Berlin] [ROUTE] matched pattern: /:controller/:action/:params
[30-Sep-2015 02:06:48 Europe/Berlin] [ACTION] {"products":"ProductsController","view":"viewAction","params":["1"]}
[30-Sep-2015 02:06:48 Europe/Berlin] [VIEW] /var/www/your_site/app/views/index.volt

How it works...

A request life cycle starts with an entry point (for example, index.php). All requests are directed to it by the web server (such as Apache, Nginx, and others). The entry point usually doesn't contain much code; it defines only the application object and delegates the control to the last one. The application instance, in turn, uses the Dependency Injection Container (DIC) and thereby calls different application components one after the other, delegating them the control and if necessary the request context or its current handling result.

The default request life cycle consists of the following stages:

  • An HTTP Request is handled by the dispatcher and routed to the controller by means of the router pattern.

  • The controller performs the action defined in it and passes data to the View.

  • The View transforms and/or formats the data as appropriate and provides it in a format that is required for the HTTP Response.

There are many ways to change the default request handling logic, including:

  • Multi module applications

  • Halting view rendering

  • Non-use of controllers (for example, in a RESTful application)

  • Working directly with HTTP requests or routers with the immediate return from anonymous functions bound with the defined URIs and even throwing an exception in any of these steps

However, the default request life cycle stages just listed outline the concept of the three main places where we can begin our research.

To demonstrate, we create an event manager, and in it register the listeners of the events we are interested in:

  • RouterListener

  • ActionListener

  • ViewListener

In each listener method, we log the current request state, that is, which line of the URL request is handled by the Request component, which router pattern matches for the address handling, which controller and action are selected by the dispatcher for the request handling, and which view is involved eventually.

Note that we define the routing pattern clearly. We couldn't define the pattern for the handling of the request /products/view/1 in this recipe, because we've created a routing component with default settings:

$router = new \Phalcon\Mvc\Router();

Try to comment the adding of your pattern into the routing component and refresh the page. Then, you'll see a matched pattern log entry, like this:

[ROUTE] matched pattern: #^/([\w0-9\_\-]+)/([\w0-9\.\_]+)(/.*)*$#u

If you take a detailed look at the request Uniform Resource Identifier (URI) and refer it to this regular expression, it will fall in place that those are a perfect match. But we recommend you to define the pattern clearly and not rely on the default one, since it helps with performance and avoids undesired behaviors.

There's more…

You can see more detailed information about the Events Manager at the Phalcon documentation site:

https://docs.phalconphp.com/en/latest/reference/events.html

See also

  • The Easily loading code on demand recipe, in this chapter

  • The Setting up your request entry point recipe, in this chapter