Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify alternative fallback paths for Symfony to find twig templates for bundles

Tags:

twig

symfony

Basic Question

How can you make symfony look in non-standard directories to find the "best" (custom) Twig template to load for a bundle view?

The Symfony docs say by default it looks in two locations to override a Twig template

When the AcmeBlogBundle:Blog:index.html.twig is rendered, Symfony actually looks in two different locations for the template:

app/Resources/AcmeBlogBundle/views/Blog/index.html.twig src/Acme/BlogBundle/Resources/views/Blog/index.html.twig

But this is discussing how you would override a vendor bundle. In my case, I have native bundles in my /src/ that I want to overwrite on a per Design Template or Client specific basis. It needs to look in:

Client:    /var/www/vhosts/{ID}/src 
Template:  /var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/src

Twig Loader has a convenient method to add paths:

$templatePath = '/var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/Resources/views';
$this->container->get('twig.loader')->prependPath($templatePath, 'template');

This allows me to register an alternative path to the template resources, so that I can render the template shell like this:

{% extends '@template/shell/shell.html.twig' %}

But what about when I want to overwrite a bundle template, e.g.

Original: /var/www/core/cms/src/Gutensite/MenuBundle/Resources/views/Menu.html.twig
Custom:   /var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/src/Gutensite/MenuBundle/Resources/views/Menu.html.twig

How do I register a generic /src/ file so that Symfony looks in there for all references to Vendor Bundle paths, e.g. trying to render @GutensiteMenu/Menu.html.twig will first look in the custom directory for 1) Client , 2) Template, 3) default bundle directory by that name.

Need Assets

Because my TemplateBundle/Templates/Admin/Resources/ are in a non-standard location, assetic won't dump them to the public directory (or create symlinks)... so I'm not sure how to dynamically make assetic find these files.

I'm also not sure how to load the assets that are in these other locations, e.g. this doesn't work:

{% stylesheets '@GutensiteTemplateBundle/Templates/Admin/Resources/public/css/site.css' %}
<link rel="stylesheet" href="{{ asset_url }}">
{% endstylesheets %}

Presumably because it's not dumped.

Why do I need this?

I am building a hosted CMS that is a core vendor which contain various bundles with controllers and templates, e.g. /Gutensite/CmsBundle, Gutensite/ArticleBundle.

Based on the selected "Design Template" for a site, a design template is referenced in a TemplateBundle, e.g. /TemplateBundle/Templates/Admin (a template called "Admin"). The TemplateBundle need to be able to override the core controllers or views.

I have registered the Gutensite/TemplateBundle/Templates/Admin/src/ folder as an alternative namespace for the Composer app/autoload.php, so that controllers can be overwritten as long as they have the same Gutensite namespace (and this works great):

// in my primary controller:
$loader = $GLOBALS['loader'];
$loader->add('Gutensite', '/var/www/core/cms/src/Gutensite/TemplateBundle/Templates/Admin/src', true);

NOTE: I could register every single template as a bundle, and that would theoretically allow me to override controllers and bundles using symfony's built in methods. But this would add a lot of "bundles" that aren't really traditional bundles. Also I need the above solution to point to alternative template paths, because I also need the ability to point to client's custom files located outside the normal symfony root directory (which I successfully do with the namespace auto loader paths for controllers).

like image 279
Chadwick Meyer Avatar asked Jan 01 '15 21:01

Chadwick Meyer


1 Answers

You can use the path option in the twig configuration, with the same namespace for 2 paths.

twig:
    # ...
    paths:
        "%kernel.root_dir%/../src/Gutensite/MenuBundle/Resources/views": templates
        "%kernel.root_dir%/../src/Gutensite/TemplateBundle/Templates/Admin/src/Gutensite/MenuBundle/Resources/views": templates

Then, using @templates/Menu.html.twig will first look for Menu.html.twig in MenuBundle, then in TemplateBundle.

That's this way that the TwigExtension is registering paths so the loader is looking in app/Resources/views and then in the bundle's views.

like image 120
Alain Tiemblo Avatar answered Oct 08 '22 12:10

Alain Tiemblo