Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access parent template from over-ridden version in Symfony / Twig

I have a third party bundle OriginalBundle and I want to customise some of the templates in it.

To achieve this, I have set up a Symfony bundle MyCustomBundle using the override method shown in the Symfony docs.

<?php

namespace My\CustomBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class MyCustomBundle extends Bundle
{
    public function getParent()
    {
        return 'OriginalBundle';
    }
}

I am then using MyCustomBundle to create over-ride versions of some Twig templates from the OriginalBundle. However, I would like to be able to access the original template from my version (e.g. extend it) and just over-ride some of the blocks.

But, if I try to do something like this:

{# MyCustomBundle:Foo:bar.html.twig #}

{% extends 'OriginalBundle:Foo:bar.html.twig' %}

{% block xyz %}
    {# ... code in here ... #}
{% endblock %}

Then I get a white screen of death. I'm guessing it causes a recursion of some kind since Symfony is routing the extends call back to the customised file?

The original bundle's template looks like this:

{# OriginalBundle:Foo:bar.html.twig #}

{% block abc %}
    {% block xyz %}
        {# ... code in here ... #}
    {% endblock %}
{% endblock %}

So the question...

is there any way to access the original template file when an over-ridden version of the same template exists?

I'm basically looking for the Twig/template equivalent of parent::doSomething().

Without this kind of access to the parent I find myself copying the entire original template file verbatim then updating a small part of it, which just feels wrong.

like image 688
caponica Avatar asked Dec 03 '22 19:12

caponica


1 Answers

There is a solution. Symfony by default search for first matching resource and returns it. To change this behaviour you need to specify some additional syntax. I use "!" to reach second match.

{% extends '!OriginalBundle:Foo:bar.html.twig' %}

{% block xyz %}
    {# ... code in here ... #}
{% endblock %}

Overriding file could be in app/Resources/OriginalBundle/views/Foo/bar.html.twig

To activate this system you need to override original Kernel to:

<?php
namespace Webility\Bundle\WebilityBundle\HttpKernel;

use Symfony\Component\HttpKernel\Kernel as BaseKernel;

abstract class Kernel extends BaseKernel
{
    public function getBundle($name, $first = true)
    {
        $get_next = false;
        if($name[0] == '!' && $first){
            $name = substr($name, 1);
            $first = false;
            $get_next = true;
        }

        $bundles = parent::getBundle($name, $first);

        if($get_next){
            return isset($bundles[1]) ? $bundles[1] : $bundles[0];
        } else {
            return $bundles;
        }
    }

    public function locateResource($name, $dir = null, $first = true)
    {
        $get_next = false;
        if($name[0] == '@' && $name[1] == '!' && $first){
            $name = '@'.substr($name, 2);
            $first = false;
            $get_next = true;
        }

        $files = parent::locateResource($name, $dir, $first);

        if($get_next){
            return isset($files[1]) ? $files[1] : $files[0];
        } else {
            return $files;
        }
    }
}

And use it in app/AppKernel.php

class AppKernel extends \Webility\Bundle\WebilityBundle\HttpKernel\Kernel
like image 58
Maciej Pyszyński Avatar answered Dec 30 '22 09:12

Maciej Pyszyński