We are moving our forum in GitHub Discussions. For questions about Phalcon v3/v4 you can visit here and for Phalcon v5 here.

Phalcon with completely custom view system

So after writing some pseudo adapter for View engine to render views from modules directory and converting my templates to not extend twice I have begin to realize this system is not for me. Neither volt nor whole View system suits my needs.

So question is pretty simple, can i completely discard "View" and write my own version that uses twig/volt? Or is there a simpler way to accomplish this?

My requirements are as follows: For View System

  1. Have a total control from where templates are being loaded a) first it should check the active module views dir which is app/modules/Vendor/Module/Views b) if template is not there, check in global templates directory which is app/views c) if template is not there, check core module views directory: app/modules/Vendor/Core/Views
  2. Allow cross module extend/include similar to symfony ex {% extends 'modulefullname:viewSubDir/viewFile' %}
  3. include/extend from templates must follow the same routine For template system
  4. Ability to access all services
  5. Ability to pass variables from controllers
  6. Ability to extend templates as many times as I like
  7. Volt/Twig syntax

From what I have seen, i could simply(???) use symfony/templating but I am kinda new to phalcon and didn't found any examples of such hybrid app. Thanks in advance.

edited Nov '17

That still inherits phalcon view. I ended up writing super simple view adapter and I am not using inheritance.


namespace Vendor\Core\Mvc;

use Phalcon\DiInterface;

class View
    protected $di;
    protected $loader;
    protected $twig;

    public function __construct(DiInterface $di)
        $this->di = $di;
        $config = $di->get('config');

        $this->loader = new \Twig_Loader_Filesystem();

        $twigConfig = [
            'cache' => $config->application->cacheDir,

        if (APPLICATION_ENV == 'dev') {
            $twigConfig['cache'] = false;
            $twigConfig['debug'] = true;

        $this->twig = new \Twig_Environment($this->loader, $twigConfig);

        $router = $di->get('router');
        $function = new \Twig_Function('generateUrl', array($router, 'generateUrl'));

    public function render($name, $params = array())
        return $this->twig->render($name, $params);

    public function addPath($path, $namespace = \Twig_Loader_Filesystem::MAIN_NAMESPACE)
        $this->loader->addPath($path, $namespace);

    public function registerViewPaths($moduleName, $module)
        $dir = $module['directory'] . 'Views/';
        if (is_dir($dir)) {
            $this->addPath($dir, $moduleName);

    public function registerMainViewPaths($currentModule)
        $dir = $currentModule['directory'] . 'Views/';
        if (is_dir($dir)) {
        $this->addPath(APP_PATH . '/views/');

    public function setVar($name, $value)
        $this->twig->addGlobal($name, $value);

It's not fully finished but it does the job. Module directories are namespaces so each of module has its own view directories and can be included like this:

{% include '@moduleName/file/someFile.twig' %}