What's the most convenient way to globally set 2 different form themes for external and external applications

So, styling a form in Symfony2 is easy. You create a custom theme file and add it to your config.yml file to load it. Done.

However, I have two different shapes. One for the front-end application and one for the front-end application.

I looked through the documentation ( http://symfony.com/doc/2.3/cookbook/form/form_customization.html ) but couldn't find a good simple way to do it.

When I add a theme to my config.yml file, I have the same theme both in the frontend and at the end. I could also include a form in each view like this

{% form_theme form 'form_table_layout.html.twig' %}


However, this means that I have to do it in every view.

Is there a way to create a separate config file for frontend and frontend? Can I somehow specify in the base template file which should be used in the theme form?

Anything else I could do?


source to share

2 answers

If you are using the Symfony2 default directory structure, meaning you have one core for both frontend and backend, you can (just you mentioned) either set a form theme in each template, or use the same template by setting it to the file config.yml


The alternative solution you mentioned is to create two basic templates, each of which will set a "global" tag form_theme

, which in theory works. Create a basic template front-end.html.twig

for all your front-end pages with the following tag:

{% form_theme form 'form-front-end.html.twig' %}


This will work, but you must have a variable form

in every inherited template. You also won't be able to set a theme for multiple forms on the same page.

You can improve the solution by checking if the form variable is defined before styling it:

{% if form is defined %}
  {% form_theme form 'form-front-end.html.twig' %}
{% endif %}


or even better, if you want to pass multiple forms to the same template, you can do it with an array forms


{% if forms is defined %}
  {% for form in forms %}
    {% form_theme form 'form-front-end.html.twig' %}
  {% endfor %}
{% endif %}


The good thing is that it wouldn't throw an exception even if you don't pass the variable at all, but you have to remember to make sure any forms are mapped to an array forms


Obviously, you are doing the same for the base base template.

There may be better solutions out there, but in the meantime I hope this helps!



I also ran into this issue several times ago, found this post and followed the path as suggested by Andrea Sprega. I recently went out of the way that could save a few duplicate titles.

Warning: this is somewhat "hackish", probably not the best way and does not guarantee work in the next version of the release. You will see why when you read below.

Goal: We want to have different default form templates depending on the application environment (the most common examples would be "frontend" and "backend"). But in principle Symfony is unaware of such a "environment". it is possible to split the project into different environments and load different configurations, this is definitely overkill if we only want to have different form templates.

I think the best way would be to set / override the default form themes in the base template. Thus, we can create theme A in the base template and form theme B in the base base template. This sounds best to me because since the theme of the form is "view" it makes sense to change it in the view. However, the problem is that when the twist (template) code is executed, the form view has already been initialized. Therefore, it would be too late to change the default theme of the form. (I could be wrong here because I didn't dig deep enough to be 100% certain)

So I decided to do it differently. It works like this:

  • First, I made the assumption that all front-end controllers will extend the same base class (for example, "BaseFrontendController"). Likewise, all backend controllers will extend the same BaseBackendController class. Here we distinguish between external and external environment. This is indeed the case in my project.
  • The default template templates will be added to these base controller classes. This can be done using a method or annotation. In this post, I will be using the public method.
  • Before the controller executes, overwrite certain default vortex patterns.
  • When the form view is initialized, it will use the default tweens template defined in the controller.

Here's how it's done:

First, the default form themes defined in yours config.yml

will be passed to the constructor \Symfony\Component\Form\AbstractRendererEngine

and assigned to the local instance $defaultThemes

. This field is protected so that it can be used by its derived classes, but there is no means to change its value.

So, we need to roll our own Symfony\Bridge\Twig\Form\TwigRendererEngine


namespace AppBundle\Form\Twig;

use Symfony\Bridge\Twig\Form\TwigRendererEngine as BaseTwigRendererEngine;

class TwigRendererEngine extends BaseTwigRendererEngine
     * @param array $defaultThemes
    public function addDefaultThemes($defaultThemes)
        $this->defaultThemes = array_merge($this->defaultThemes, $defaultThemes);


This custom rendering engine is simple - just add a new method to add standard themes to existing ones. And that's why I say it's "hackish" - it won't work anymore when the internal change is changed.

Second, define the interface TwigTemplateProvider

to be implemented by the frontend / backend interface classes:

namespace AppBundle\Form\Twig;

interface TwigTemplateProvider
     * @return array|string The form template path
    public function getDefaultFormTwigTemplates();


Third, we need a listener that will run when the controller executes.


namespace AppBundle\EventListener;

use AppBundle\Form\Twig\TwigRendererEngine;
use AppBundle\Form\Twig\TwigTemplateProvider;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class PerControllerFormTemplateListener
     * @var \Twig_Environment
    private $twig;

    public function __construct(\Twig_Environment $twig)
        $this->twig = $twig;

    public function onKernelController(FilterControllerEvent $event)
        $controller = $event->getController();

        if (!is_array($controller)) {

        if ($controller[0] instanceof TwigTemplateProvider) {

            /** @var \Symfony\Bridge\Twig\Extension\FormExtension $formExtension */
            $formExtension = $this->twig->getExtension('form');
            $engine = $formExtension->renderer->getEngine();
            if ($engine instanceof TwigRendererEngine) {
                $templates = (array)$controller[0]->getDefaultFormTwigTemplates();


The listener will receive the name of the form template (in a string or array) provided by controllers that implement the TwigTemplateProvider interface. It will then add it to the default theme list and feed it to the form's rendering engine.

Now connect them together by adding the following items to services.yml


    twig.form.engine.class: AppBundle\Form\Twig\TwigRendererEngine

        class: AppBundle\EventListener\PerControllerFormTemplateListener
        arguments: ["@twig"]
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }


Here we set a parameter to %twig.form.engine.class%

our own implementation and add our event listener to the stack.

The use is very simple. For example, in your base front-end controller, execute TwigTemplateProvider

and add the following method:

public function getDefaultFormTwigTemplates()
    return 'frontend/form_layout.html.twig';


This layout will then be pushed onto the stack of your form template when your front controller is executed.



All Articles