We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Twig and dependency injector

I'm adding Twig support on existing apps that has been written in Volt.

I'm looking to replicate the same behavior of Volt that expose DI services: {{ config }} or {{ this.config }} but I'm not sure how volt do that (even by looking source).

For now my working way is to iterate over $di->getServices() and assign each services to the view object

Is the right way to do that?

Mat

<?php
class Twig extends Engine implements EngineInterface
{
  protected $twig;

  public function __construct($view, $di, $options = [])
  {
    $this->setDI($di);

    $loader     = new \Twig_Loader_Filesystem($di->getView()->getViewsDir());
    $this->twig = new TwigEnvironment($di, $loader, [
      'debug' => $di->getEnv()->development
    ]);

    $this->twig->addExtension( new \Twig_Extension_Debug() );

    // Expose phalcon services to twig
    foreach ($di->getServices() as $name => $obj) {
      $view->$name = $obj;
    }

    parent::__construct($view, $di);

  }

}
edited Mar '17

https://github.com/phalcon/incubator/tree/master/Library/Phalcon/Mvc/View/Engine Engine class extends Injectable, so it will work the same as in volt.

edited Mar '17

Hm I can't get this working (no errors, no warnigs). After looking the constructor, ( https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/view/engine.zep#L40 ), they need ViewBaseInterface and DiInterface.

But in my Twig class, the constructor $view is View and $di is FactoryDefault even from the simple service :

$di->set('view', function() {

    $view = new \Phalcon\Mvc\View();

    $view->setViewsDir('../app/views/');

    $view->registerEngines(
        ['.twig' => 'My\View\Engine\Twig']
    );

    return $view;
});

In the incubator Twig class, they use $view ViewBaseInterface and $di DiInterface => https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Mvc/View/Engine/Twig.php#L28-L30

Well there are not twig tests in incubator, can't you just use classes from incubator and check it out? As i see this code just same as volt should work, so for example to acces service config just {{ config.someKey }}

I can't use the Incubator Twig class because I need to apply some business logic in both constructor and render method.

I'm finally using $this->twig->addGlobal('config', $di->get('config')); and work as expected.

Seems better since I do not need all services, I was just thinking the services will automagically exposed like volt

edited Mar '17

You can always extend them. Well i will need to check incubator then if it works like in volt or not. To be honest it fells more like you should use some twig extension.