Twig templates and complex logic architecture?

Due to some discussion I recently have started here it looks that chances are Twig templates become kind of mandatory in the future (Is there a possibility to extend a Twig template with a PHP template?).

As I am new to Pimcore have a few questions regarding the architecture of my application.

As far as I have learned I need to query the data which I need within my views in the corresponding Controllers - e.g. like:

public function detailAction(Request $request)
{
    // "id" is the named parameters in "Static Routes"
    $article = DataObject\BlogArticle::getById($request->get('id'));

    if (!$article instanceof DataObject\BlogArticle || !$article->isPublished()) {
        throw $this->createNotFoundException('Invalid request - no such blog article');
    }

    $this->view->article = $article;
}

Are the Controllers basically the correct place for this? Because Controllers are not a good place for complex logic, so where do I put my “super fancy function which calculates the HTML for a slider using fancybox based on article data containing a lot of metadata and a golden ratio for my two first article images including an external feed and two curl requests”?

One thing I have read about are Twig extensions, but not sure if this is the correct place for a task like described above?

A great answer which tells me to write “Twig functions or filters” was found on SO: https://stackoverflow.com/questions/32920217/how-to-call-static-function-in-symfony2-twig-template. I guess in Pimcore this is the AppBundle\Templating\Helper\ … ? Classes in there extend the (?deprecated?) \Twig_Extension class and seem to provide a get_functions and a get_filter method which can perform arbitrary actions?

Basically the Controller is responsible for business logic. So, you should query your data in the controller like:

public function detailAction(Request $request)
{
    // "id" is the named parameters in "Static Routes"
    $article = DataObject\BlogArticle::getById($request->get('id'));

    if (!$article instanceof DataObject\BlogArticle || !$article->isPublished()) {
        throw $this->createNotFoundException('Invalid request - no such blog article');
    }

    return $this->renderTemplate('article/detail.html.twig', ['article' => $article']);
}

Twig Extensions are meant for things like:

  • Getting fallback values
  • Calculating things like product prices
  • Helper things like some easy php functions+
  • Currency Conversions

Stuff like that, there is no general rule for what a twig extension should be or should not be.

In Pimcore, Twig Extensions should be in the namespace AppBundle\Twig\Extension and should look like this:

<?php
namespace AppBundle\Twig\Extension;

use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

final class MyExtension extends AbstractExtension
{

    /**
     * {@inheritdoc}
     */
    public function getFilters()
    {
        return [
            new TwigFilter('my_filter', [$this->helper, 'myFilter']),
        ];
    }
    
    public function myFilter($subject) {
         //Do something with $subject here
         return $subject;
    }
}

you then use it in twig like

{{ my_var|my_filter }}
3 Likes

Thank you very much for your detailed answer this sheds some light on how to do it (I guess for functions its the same as for filters like described here: https://symfony.com/doc/current/templating/twig_extension.html) :slightly_smiling_face:

Now my only question remaining is what exactly is the exact difference between a custom Templating Helper and a custom Twig Extension?

The Twig Extension is basically a function registered to the Twig templating engine which can be used to call a normal PHP function with parameters via Twig. It extends the Twig\Extension\AbstractExtension class.

Example:

{{ my_custom_twig_function('foo','bar') }} <!-- fomerly registered as a twig extension -->

A Templating helper is (also) a PHP object with the purpose of providing functions and/or data useful in a template context. This is independent of the template rendering engine, but it can be called from Twig as well as PHP templates.

Example:

{% for link, text in get_localized_links(document) %}
 <li>
   <a href="{{ link }}">{{ text }}</a>
  </li>
 {% endfor %}

According to https://github.com/pimcore/demo-basic/blob/master/src/AppBundle/Templating/Helper/LanguageSwitcher.php.

If Twig is used template helpers actually have to be registered as Twig Extensions before using them (in the Pimcore example as used here it was named LanguageSwitcherExtension.

Is this all correct? Why do I even need template helpers in a Twig context then anyway?

Templating Helpers are for the PHP Engine
Twig Extensions are for the Twig Engine

1 Like

Ok so regarding this I was thinking way to complicated. Awesome, thanks for the fast answer :+1: All clear now.