Rodik
Rodik

Reputation: 4092

Twig: Cannot override a block that's defined in a macro

I am importing a macro from a layout file, and inside that macro I define a few twig blocks.

When I extend my 'base' layout file in a new 'view' file, I cannot override the content of the blocks that I defined in the macro.

Here is a very simplified, minimal version of my use-case.

Structure:

base.twig

{% import 'macros' as macros %}
<section>
    {{ macros.render_sections() }}

    {% block working %}
       content1-default
    {% endblock %}
</section>

macro.twig

{% macro render_sections() %}
    <section>
      {% block notworking %}
         content2-default
      {% endblock %}
    </section>
{% endmacro %}

view.twig

{% extends "base" %}

{% block working %}
   content1-override
{% endblock %}

{% block notworking %}
    content2-override
{% endblock %}

Expected behavior: I expect to see "content1-override content2-override" in my html.

What actually happens: I see 'content1-override content2-default'

Is there a way to pass the blocks scope to a macro?

I have tried defining the macro inside the base.twig file, as to rule out the import function, but that didn't help. and obviously everything else works because I can see the block that does get overriden.

Upvotes: 3

Views: 3892

Answers (1)

Alain
Alain

Reputation: 36954

You should learn about Twig's internals:

  • all Twig files are converted to PHP classes

  • {% extends %} is the equivalent for the litteral PHP extends (used for inheritance).

  • {% import %} assign a property of your context to an object of type "the twig file you're importing"

  • blocks are no more than php methods, and the native php inheritance let you overwrite Twig blocks sweetly.

So, taking this into account, your converted twig code will look like this:

class base {

   public function display() {
      $context['macros'] = new macros();
      $context['macros']->render_sections();
      echo '<section>';
      echo $this->blockWorking();
      echo '</section>';
   }

   public function blockWorking() {
     echo "content1-default";
   }

}

class macros {

  public function render_sections() {
     echo '<section>';
     echo $this->blockNotWorking();
     echo '</section>';
  }

  public function blockNotWorking() {
     echo "content2-defualt";
  }

}

class view extends base {

   public function blockWorking() {
     echo "content1-override";
   }

   public function blockNotWorking() {
     echo "content2-override";
   }

}

$view = new view();
$view->display();

You can clearly see here that the blockNotWorking() method of the view class can never overwrite the macro.

Upvotes: 15

Related Questions