symfonytwig-extension

Symfony2 call controller-action in twig-extension without service


I'm programming a system that has the following functionality: normal users (no programmer or admins) can create content where they can insert "placeholders". These placeholders will be replaced with different content-types (e.g. a hex-color-code, a slider, an image, ...) when a page is rendered. The replacement of the placeholders is a bit complex and has some additional functionality (e.g. define default-values, replace the placeholder with the content in the correct language, ...). Because of this I have created a twig-extension with a "placeholder-filter". This function should get the correct content to replace the placeholder and handle the additional functionality.

Because the content-types are so different there are some - let it call "plugins" - for each content-type that contains the logic for rendering the contents in a controller.

Now my problem:

The controller-actions of the plugins return the rendered content. Because I replace the placeholder with the content in the twig extension I need a way to call the controller-action in this twig-extension.

My thoughts till now:

I know I can call a controller-action in a template in this way (source: http://symfony.com/doc/current/book/templating.html):

{{ render(controller(
        'AppBundle:Article:recentArticles',
        { 'max': 3 }
    )) }}

So it seems to be no problem to call a controller-action in twig. But I need this function-call in a twig-extension.

I also know that I can call a controller-action when I implement the controller as a service. But I can't define all the plugin-controllers as services, because the plugins are included dynamically in the system. It would be "hard" to handle also the services dynamically when installing a new plugin (I think I have to edit the service.yml with a script - or am I wrong?). This is why I can't use the controller as a service. - But I'm open to other solutions when you can tell me how to implement services dynamically.

What I've tried already was combining the solutions of these two pages: http://symfony.com/doc/current/book/templating.html

echo $view['actions']->render(
    new \Symfony\Component\HttpKernel\Controller\ControllerReference(
        'AppBundle:Article:recentArticles',
        array('max' => 3)
    )
)

and https://www.robinvdvleuten.nl/blog/rendering-templates-in-a-twig-extension/

I have now access to the Twig_Environment in my placeholder-filter in my twig-extension but the following code doesn't work:

$twig->render( new \Symfony\Component\HttpKernel\Controller\ControllerReference(
                            'Extensions'.$namespace.'Bundle:Index:getContent',
                            array('content'=>$contentObject)
                        ), array() );

I get the error that ControllerReference couldn't be converted to string (which make sense because ControllerReference is an object...).

So is there a way to call a controller-action in a twig-extension without defining the controller as a service? Or should I rethink the whole solution?


Solution

  • After some hours "thinking about the problem" i found a simple answer for the main-question. When i include the Twig_environment in my filter-function (see https://www.robinvdvleuten.nl/blog/rendering-templates-in-a-twig-extension/) i have access to the twig render()-function. The function works with templates and strings. So the easiest way to call a controller-action in a twig-extension without services is to use the normal twig-template-syntax:

    // $twig is the Twig_Environment in my filter-function
    $myRenderedContent = $twig->render(
        "{{ render(controller( 'Extensions".$namespace."Bundle:Index:getContent', { 'content': content })) }}", 
        array('content'=>$contentObject)
    );
    

    Additional thoughts:

    As you can see in http://symfony.com/doc/current/book/templating.html calling a controller like this seems to be completely ok in symfony. So i think it is also ok to use this functionality in a twig-extension (because a twig-extension defines additional helper-functions for template-rendering and this is what i want to do with my filter-function to replace special placeholders with special contents).

    Maybe it is not the best practice to doesn't include my plugin-controllers as services but i don't see a disadvantage of handling the plugin-controllers like this till now - when you know one: please tell me because i'm open to learn "how to make it better" ;-)