Views


    Views represent the user interface of your application. Views are often HTML files with embedded PHP code that perform tasks related solely to the presentation of the data. Views handle the job of providing data to the web browser or other tool that is used to make requests from your application.

    Phalcon\Mvc\View and are responsible for the managing the view layer of your MVC application.

    Integrating Views with Controllers

    Phalcon automatically passes the execution to the view component as soon as a particular controller has completed its cycle. The view component will look in the views folder for a folder named as the same name of the last controller executed and then for a file named as the last action executed. For instance, if a request is made to the URL , Phalcon will parse the URL as follows:

    The dispatcher will look for a and its action showAction. A simple controller file for this example:

    The setVar() method allows us to create view variables on demand so that they can be used in the view template. The example above demonstrates how to pass the $postId parameter to the respective view template.

    Hierarchical Rendering

    supports a hierarchy of files and is the default component for view rendering in Phalcon. This hierarchy allows for common layout points (commonly used views), as well as controller named folders defining respective view templates.

    This component uses by default PHP itself as the template engine, therefore views should have the .phtml extension. If the views directory is app/views then view component will find automatically for these 3 view files.

    You are not required to implement all of the files mentioned above. Phalcon\Mvc\View will simply move to the next view level in the hierarchy of files. If all three view files are implemented, they will be processed as follows:

    1. <!-- app/views/posts/show.phtml -->
    2. <h3>This is show view!</h3>
    3. <p>I have received the parameter <?php echo $postId; ?></p>
    1. <!-- app/views/layouts/posts.phtml -->
    2. <h2>This is the "posts" controller layout!</h2>
    3. <?php echo $this->getContent(); ?>
    1. <!-- app/views/index.phtml -->
    2. <html>
    3. <head>
    4. <title>Example</title>
    5. </head>
    6. <body>
    7. <h1>This is main layout!</h1>
    8. <?php echo $this->getContent(); ?>
    9. </body>
    10. </html>

    Note the lines where the method $this->getContent() was called. This method instructs on where to inject the contents of the previous view executed in the hierarchy. For the example above, the output will be:

    .. figure:: ../_static/img/views-1.png:align: center

    The generated HTML by the request will be:

    1. <!-- app/views/index.phtml -->
    2. <html>
    3. <head>
    4. <title>Example</title>
    5. </head>
    6. <body>
    7. <h1>This is main layout!</h1>
    8. <!-- app/views/layouts/posts.phtml -->
    9. <h2>This is the "posts" controller layout!</h2>
    10. <!-- app/views/posts/show.phtml -->
    11. <h3>This is show view!</h3>
    12. <p>I have received the parameter 101</p>
    13. </body>
    14. </html>

    Templates are views that can be used to share common view code. They act as controller layouts, so you need to place them in the layouts directory.

    Templates can be rendered before the layout (using $this->view->setTemplateBefore()) or they can be rendered after the layout (using this->view->setTemplateAfter()). In the following example the template (layouts/common.phtml) is rendered after the main layout (layouts/posts.phtml):

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class PostsController extends Controller
    4. {
    5. public function initialize()
    6. {
    7. $this->view->setTemplateAfter('common');
    8. }
    9. public function lastAction()
    10. {
    11. $this->flash->notice(
    12. 'These are the latest posts'
    13. );
    14. }
    15. }
    1. <!-- app/views/index.phtml -->
    2. <!DOCTYPE html>
    3. <html>
    4. <head>
    5. <title>Blog's title</title>
    6. </head>
    7. <body>
    8. <?php echo $this->getContent(); ?>
    9. </body>
    10. </html>
    1. <!-- app/views/layouts/common.phtml -->
    2. <ul class='menu'>
    3. <li><a href='/'>Home</a></li>
    4. <li><a href='/articles'>Articles</a></li>
    5. <li><a href='/contact'>Contact us</a></li>
    6. </ul>
    7. <div class='content'><?php echo $this->getContent(); ?></div>
    1. <!-- app/views/layouts/posts.phtml -->
    2. <h1>Blog Title</h1>
    3. <?php echo $this->getContent(); ?>
    1. <!-- app/views/posts/last.phtml -->
    2. <article>
    3. <h2>This is a title</h2>
    4. <p>This is the post content</p>
    5. </article>
    6. <article>
    7. <h2>This is another title</h2>
    8. <p>This is another post content</p>
    9. </article>

    The final output will be the following:

    1. <!-- app/views/index.phtml -->
    2. <!DOCTYPE html>
    3. <html>
    4. <head>
    5. <title>Blog's title</title>
    6. </head>
    7. <body>
    8. <!-- app/views/layouts/common.phtml -->
    9. <ul class='menu'>
    10. <li><a href='/'>Home</a></li>
    11. <li><a href='/articles'>Articles</a></li>
    12. <li><a href='/contact'>Contact us</a></li>
    13. </ul>
    14. <div class='content'>
    15. <!-- app/views/layouts/posts.phtml -->
    16. <h1>Blog Title</h1>
    17. <!-- app/views/posts/last.phtml -->
    18. <article>
    19. <h2>This is a title</h2>
    20. <p>This is the post content</p>
    21. </article>
    22. <article>
    23. <h2>This is another title</h2>
    24. <p>This is another post content</p>
    25. </article>
    26. </div>
    27. </body>
    28. </html>

    If we had used $this->view->setTemplateBefore('common'), this would be the final output:

    1. <!-- app/views/index.phtml -->
    2. <!DOCTYPE html>
    3. <html>
    4. <head>
    5. <title>Blog's title</title>
    6. </head>
    7. <body>
    8. <!-- app/views/layouts/posts.phtml -->
    9. <h1>Blog Title</h1>
    10. <!-- app/views/layouts/common.phtml -->
    11. <ul class='menu'>
    12. <li><a href='/'>Home</a></li>
    13. <li><a href='/articles'>Articles</a></li>
    14. <li><a href='/contact'>Contact us</a></li>
    15. </ul>
    16. <div class='content'>
    17. <!-- app/views/posts/last.phtml -->
    18. <article>
    19. <h2>This is a title</h2>
    20. <p>This is the post content</p>
    21. </article>
    22. <article>
    23. <h2>This is another title</h2>
    24. <p>This is another post content</p>
    25. </article>
    26. </div>
    27. </body>
    28. </html>

    Control Rendering Levels

    As seen above, supports a view hierarchy. You might need to control the level of rendering produced by the view component. The method Phalcon\Mvc\View::setRenderLevel() offers this functionality.

    This method can be invoked from the controller or from a superior view layer to interfere with the rendering process.

    The available render levels are:

    Disabling render levels

    You can permanently or temporarily disable render levels. A level could be permanently disabled if it isn’t used at all in the whole application:

    1. <?php
    2. use Phalcon\Mvc\View;
    3. $di->set(
    4. 'view',
    5. function () {
    6. $view = new View();
    7. // Disable several levels
    8. $view->disableLevel(
    9. [
    10. View::LEVEL_LAYOUT => true,
    11. View::LEVEL_MAIN_LAYOUT => true,
    12. ]
    13. );
    14. return $view;
    15. true
    16. );
    1. <?php
    2. use Phalcon\Mvc\View;
    3. use Phalcon\Mvc\Controller;
    4. class PostsController extends Controller
    5. {
    6. public function indexAction()
    7. {
    8. }
    9. public function findAction()
    10. {
    11. $this->view->disableLevel(
    12. View::LEVEL_MAIN_LAYOUT
    13. );
    14. }
    15. }

    As mentioned above, when is managed by Phalcon\Mvc\Application the view rendered is the one related with the last controller and action executed. You could override this by using the Phalcon\Mvc\View::pick() method:

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class ProductsController extends Controller
    4. {
    5. public function listAction()
    6. {
    7. // Pick 'views-dir/products/search' as view to render
    8. $this->view->pick('products/search');
    9. // Pick 'views-dir/books/list' as view to render
    10. $this->view->pick(
    11. [
    12. 'books',
    13. ]
    14. );
    15. // Pick 'views-dir/products/search' as view to render
    16. $this->view->pick(
    17. [
    18. 1 => 'search',
    19. ]
    20. );
    21. }
    22. }

    Disabling the view

    If your controller does not produce any output in the view (or not even have one) you may disable the view component avoiding unnecessary processing:

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class UsersController extends Controller
    4. {
    5. public function closeSessionAction()
    6. {
    7. // Close session
    8. // ...
    9. // Disable the view to avoid rendering
    10. $this->view->disable();
    11. }
    12. }

    Alternatively, you can return false to produce the same effect:

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class UsersController extends Controller
    4. {
    5. public function closeSessionAction()
    6. {
    7. // ...
    8. // Disable the view to avoid rendering
    9. return false;
    10. }
    11. }

    You can return a response object to avoid disable the view manually:

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class UsersController extends Controller
    4. {
    5. public function closeSessionAction()
    6. {
    7. // Close session
    8. // ...
    9. // A HTTP Redirect
    10. return $this->response->redirect('index/index');
    11. }
    12. }

    Phalcon\Mvc\View\Simple is an alternative component to . It keeps most of the philosophy of Phalcon\Mvc\View but lacks of a hierarchy of files which is, in fact, the main feature of its counterpart.

    This component allows the developer to have control of when a view is rendered and its location. In addition, this component can leverage of view inheritance available in template engines such as Volt and others.

    The default component must be replaced in the service container:

    1. <?php
    2. use Phalcon\Mvc\View\Simple as SimpleView;
    3. $di->set(
    4. 'view',
    5. function () {
    6. $view = new SimpleView();
    7. $view->setViewsDir('../app/views/');
    8. return $view;
    9. },
    10. true
    11. );

    Automatic rendering must be disabled in (if needed):

    1. <?php
    2. use Exception;
    3. use Phalcon\Mvc\Application;
    4. try {
    5. $application = new Application($di);
    6. $application->useImplicitView(false);
    7. $response = $application->handle(
    8. $_SERVER["REQUEST_URI"]
    9. );
    10. $response->send();
    11. } catch (Exception $e) {
    12. echo $e->getMessage();
    13. }

    To render a view it’s necessary to call the render method explicitly indicating the relative path to the view you want to display:

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class PostsController extends Controller
    4. {
    5. public function indexAction()
    6. {
    7. // Render 'views-dir/index.phtml'
    8. echo $this->view->render('index');
    9. // Render 'views-dir/posts/show.phtml'
    10. echo $this->view->render('posts/show');
    11. // Render 'views-dir/index.phtml' passing variables
    12. echo $this->view->render(
    13. 'index',
    14. [
    15. 'posts' => Posts::find(),
    16. ]
    17. );
    18. // Render 'views-dir/posts/show.phtml' passing variables
    19. echo $this->view->render(
    20. 'posts/show',
    21. [
    22. 'posts' => Posts::find(),
    23. ]
    24. );
    25. }
    26. }

    This is different to Phalcon\Mvc\View who’s render() method uses controllers and actions as parameters:

    1. <?php
    2. $params = [
    3. 'posts' => Posts::find(),
    4. ];
    5. // Phalcon\Mvc\View
    6. $view = new \Phalcon\Mvc\View();
    7. echo $view->render('posts', 'show', $params);
    8. // Phalcon\Mvc\View\Simple
    9. $simpleView = new \Phalcon\Mvc\View\Simple();
    10. echo $simpleView->render('posts/show', $params);

    Using Partials

    Partial templates are another way of breaking the rendering process into simpler more manageable chunks that can be reused by different parts of the application. With a partial, you can move the code for rendering a particular piece of a response to its own file.

    One way to use partials is to treat them as the equivalent of subroutines: as a way to move details out of a view so that your code can be more easily understood. For example, you might have a view that looks like this:

    1. <div class='top'><?php $this->partial('shared/ad_banner'); ?></div>
    2. <div class='content'>
    3. <h1>Robots</h1>
    4. <p>Check out our specials for robots:</p>
    5. ...
    6. </div>
    7. <div class='footer'><?php $this->partial('shared/footer'); ?></div>

    The partial() method does accept a second parameter as an array of variables/parameters that only will exists in the scope of the partial:

    Transfer values from the controller to views

    is available in each controller using the view variable ($this->view). You can use that object to set variables directly to the view from a controller action by using the setVar() method.

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class PostsController extends Controller
    4. {
    5. public function indexAction()
    6. {
    7. }
    8. public function showAction()
    9. {
    10. $user = Users::findFirst();
    11. $posts = $user->getPosts();
    12. // Pass all the username and the posts to the views
    13. $this->view->setVar('username', $user->username);
    14. $this->view->setVar('posts', $posts);
    15. // Using the magic setter
    16. $this->view->username = $user->username;
    17. $this->view->posts = $posts;
    18. // Passing more than one variable at the same time
    19. $this->view->setVars(
    20. [
    21. 'username' => $user->username,
    22. 'posts' => $posts,
    23. ]
    24. );
    25. }
    26. }

    A variable with the name of the first parameter of setVar() will be created in the view, ready to be used. The variable can be of any type, from a simple string, integer etc. variable to a more complex structure such as array, collection etc.

    1. 's Posts
    2. </h1>
    3. <div class='post'>
    4. <?php
    5. foreach ($posts as $post) {
    6. echo '<h2>', $post->title, '</h2>';
    7. }
    8. ?>
    9. </div>

    Sometimes when you develop dynamic websites and some areas of them are not updated very often, the output is exactly the same between requests. Phalcon\Mvc\View offers caching a part or the whole rendered output to increase performance.

    integrates with to provide an easier way to cache output fragments. You could manually set the cache handler or set a global handler:

    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class PostsController extends Controller
    4. {
    5. public function showAction()
    6. {
    7. // Cache the view using the default settings
    8. $this->view->cache(true);
    9. }
    10. public function showArticleAction()
    11. {
    12. // Cache this view for 1 hour
    13. $this->view->cache(
    14. [
    15. 'lifetime' => 3600,
    16. ]
    17. );
    18. }
    19. public function resumeAction()
    20. {
    21. // Cache this view for 1 day with the key 'resume-cache'
    22. $this->view->cache(
    23. [
    24. 'lifetime' => 86400,
    25. 'key' => 'resume-cache',
    26. ]
    27. );
    28. }
    29. public function downloadAction()
    30. {
    31. // Passing a custom service
    32. $this->view->cache(
    33. [
    34. 'service' => 'myCache',
    35. 'lifetime' => 86400,
    36. 'key' => 'resume-cache',
    37. ]
    38. );
    39. }
    40. }

    When we do not define a key to the cache, the component automatically creates one using an MD5 hash of the name of the controller and view currently being rendered in the format of controller/view. It is a good practice to define a key for each action so you can easily identify the cache associated with each view. When the View component needs to cache something it will request a cache service from the services container. The service name convention for this service is viewCache:

    1. <?php
    2. use Phalcon\Cache\Frontend\Output as OutputFrontend;
    3. use Phalcon\Cache\Backend\Memcache as MemcacheBackend;
    4. // Set the views cache service
    5. $di->set(
    6. 'viewCache',
    7. function () {
    8. // Cache data for one day by default
    9. $frontCache = new OutputFrontend(
    10. [
    11. 'lifetime' => 86400,
    12. ]
    13. );
    14. // Memcached connection settings
    15. $cache = new MemcacheBackend(
    16. $frontCache,
    17. [
    18. 'host' => 'localhost',
    19. 'port' => '11211',
    20. ]
    21. );
    22. return $cache;
    23. }
    24. );
    1. <?php
    2. use Phalcon\Mvc\Controller;
    3. class DownloadController extends Controller
    4. {
    5. public function indexAction()
    6. {
    7. // Check whether the cache with key 'downloads' exists or has expired
    8. if ($this->view->getCache()->exists('downloads')) {
    9. // Query the latest downloads
    10. $latest = Downloads::find(
    11. [
    12. 'order' => 'created_at DESC',
    13. ]
    14. );
    15. $this->view->latest = $latest;
    16. }
    17. // Enable the cache with the same key 'downloads'
    18. $this->view->cache(
    19. [
    20. 'key' => 'downloads',
    21. ]
    22. );
    23. }
    24. }

    Template Engines

    Template Engines help designers to create views without the use of a complicated syntax. Phalcon includes a powerful and fast templating engine called Volt. Phalcon\Mvc\View allows you to use other template engines instead of plain PHP or Volt.

    Using a different template engine, usually requires complex text parsing using external PHP libraries in order to generate the final output for the user. This usually increases the number of resources that your application will use.

    If an external template engine is used, provides exactly the same view hierarchy and it’s still possible to access the API inside these templates with a little more effort.

    This component uses adapters, these help Phalcon to speak with those external template engines in a unified way, let’s see how to do that integration.

    Creating your own Template Engine Adapter

    There are many template engines, which you might want to integrate or create one of your own. The first step to start using an external template engine is create an adapter for it.

    A template engine adapter is a class that acts as bridge between and the template engine itself. Usually it only needs two methods implemented: __construct() and render(). The first one receives the Phalcon\Mvc\View instance that creates the engine adapter and the DI container used by the application.

    The method render() accepts an absolute path to the view file and the view parameters set using $this->view->setVar(). You could read or require it when it’s necessary.

    1. <?php
    2. use Phalcon\Di\DiInterface;
    3. use Phalcon\Mvc\Engine;
    4. class MyTemplateAdapter extends Engine
    5. {
    6. /**
    7. * Adapter constructor
    8. *
    9. * @param \Phalcon\Mvc\View $view
    10. * @param \Phalcon\Di $di
    11. */
    12. public function __construct($view, DiInterface $di)
    13. {
    14. // Initialize here the adapter
    15. parent::__construct($view, $di);
    16. }
    17. /**
    18. * Renders a view using the template engine
    19. *
    20. * @param string $path
    21. * @param array $params
    22. */
    23. public function render(string $path, $params)
    24. {
    25. // Access view
    26. $view = $this->_view;
    27. // Access options
    28. $options = $this->_options;
    29. // Render the view
    30. // ...
    31. }
    32. }

    You can replace the template engine completely or use more than one template engine at the same time. The method Phalcon\Mvc\View::registerEngines() accepts an array containing data that define the template engines. The key of each engine is an extension that aids in distinguishing one from another. Template files related to the particular engine must have those extensions.

    The order that the template engines are defined with Phalcon\Mvc\View::registerEngines() defines the relevance of execution. If finds two views with the same name but different extensions, it will only render the first one.

    If you want to register a template engine or a set of them for each request in the application. You could register it when the view service is created:

    1. <?php
    2. use Phalcon\Mvc\View;
    3. // Setting up the view component
    4. $di->set(
    5. 'view',
    6. function () {
    7. $view = new View();
    8. $view->setViewsDir('../app/views/');
    9. // Set the engine
    10. $view->registerEngines(
    11. [
    12. '.my-html' => \MyTemplateAdapter::class,
    13. ]
    14. );
    15. // Using more than one template engine
    16. $view->registerEngines(
    17. [
    18. '.my-html' => \MyTemplateAdapter::class,
    19. '.phtml' => \Phalcon\Mvc\View\Engine\Php::class,
    20. ]
    21. );
    22. return $view;
    23. },
    24. true
    25. );

    There are adapters available for several template engines on the Phalcon Incubator

    Injecting services in View

    Every view executed is included inside a Phalcon\Di\Injectable instance, providing easy access to the application’s service container.

    The following example shows how to write a jQuery using a URL with the framework conventions. The service url (usually Phalcon\Url) is injected in the view by accessing a property with the same name:

    1. <script type='text/javascript'>
    2. $.ajax({
    3. url: '<?php echo $this->url->get('cities/get'); ?>'
    4. })
    5. .done(function () {
    6. alert('Done!');
    7. });
    8. </script>

    All the components in Phalcon can be used as glue components individually because they are loosely coupled to each other:

    Hierarchical Rendering

    Using Phalcon\Mvc\View in a stand-alone mode can be demonstrated below:

    1. <?php
    2. use Phalcon\Mvc\View;
    3. $view = new View();
    4. $view->setViewsDir('../app/views/');
    5. // Passing variables to the views, these will be created as local variables
    6. $view->setVar('someProducts', $products);
    7. $view->setVar('someFeatureEnabled', true);
    8. // Start the output buffering
    9. $view->start();
    10. // Render all the view hierarchy related to the view products/list.phtml
    11. $view->render('products', 'list');
    12. // Finish the output buffering
    13. $view->finish();
    14. echo $view->getContent();

    A short syntax is also available:

    <?php
    
    use Phalcon\Mvc\View;
    
    $view = new View();
    
    echo $view->getRender(
        'products',
        'list',
        [
            'someProducts'       => $products,
            'someFeatureEnabled' => true,
        ],
        function ($view) {
            // Set any extra options here
    
            $view->setViewsDir('../app/views/');
    
            $view->setRenderLevel(
                View::LEVEL_LAYOUT
            );
        }
    );
    

    Simple Rendering

    Using Phalcon\Mvc\View\Simple in a stand-alone mode can be demonstrated below:

    <?php
    
    use Phalcon\Mvc\View\Simple as SimpleView;
    
    $view = new SimpleView();
    
    $view->setViewsDir('../app/views/');
    
    // Render a view and return its contents as a string
    echo $view->render('templates/welcomeMail');
    
    // Render a view passing parameters
    echo $view->render(
        'templates/welcomeMail',
        [
            'email'   => $email,
            'content' => $content,
        ]
    );
    

    View Events

    Phalcon\Mvc\View and are able to send events to an EventsManager if it is present. Events are triggered using the type view. Some events when returning boolean false could stop the active operation. The following events are supported:

    The following example demonstrates how to attach listeners to this component: