Twig: добавление элемента в массив из встроенного шаблона

Как добавить элемент в массив внутри тега include когда массив определен в основном файле?

Обратите внимание, что этот вопрос явно отличается от других вопросов массива в Twig, потому что я пытаюсь изменить значение из встроенного шаблона в основной файл.

Например:

main.twig

 {% set includes = ["test1"] %} {% include "test.twig" %} {{includes|json_encode}} {# "How do I make this `includes` contain the "test2" array item?" #} 

test.twig

 {% set includes = includes|merge(["test2"]) %} {{includes|json_encode}} 

В настоящее время вывод main.twig дает мне только начальный элемент test1 , а не комбинацию двух тех, которые test.twig пытается изменить.

Возможно, мне придется использовать добавленную функцию. Цель здесь в основном заключается в том, чтобы include d-шаблоны в возможность добавления других CSS, JS и т. Д. В файлы HTML без необходимости изменять родительские шаблоны.

Вот вам скрипка Twig Fiddle , с которой вы можете видеть результат.

Обратите внимание, что для других людей, которые ищут ответ на этот вопрос, что я пытаюсь выполнить, возможно использование расширения Twig с функцией, которая добавляет элементы в массив, и вторую функцию для доступа к ней. Пожалуйста, просмотрите мой ответ ниже, который не помечен как правильный, чтобы увидеть способ потенциально сделать это. Мой вопрос, как было сказано, невозможно, как показано DarkBee.

    Это невозможно сделать в Twig , как видно из скомпилированного источника шаблонов, каждый из которых включает шаблоны, получает свою собственную частную область, поскольку массив контекста основан на значении, а не по ссылке

    $this->loadTemplate("bar.twig", "main.twig", 2)->display($context);

    который затем вызывает doDisplay в включенном шаблоне

    protected function doDisplay(array $context, array $blocks = array())

    заметка

    Вы можете изменить это поведение, создав собственный Twig_Environment и Twig_Template но быстрый взгляд показывает мне, что есть некоторые функции, которые вам нужно переопределить.


    main.twig

     {% set foo = 'bar' %} {% include 'bar.twig' %} Foo in foo: {{ foo }} 

    bar.twig

     {% set foo = 'foo' %} Foo in bar: {{ foo }} 

    Источник main.twig

     /* main.twig */ class __TwigTemplate_4ba23e628289532331bb5889dca1a4ec57774924d21a760ca6fe6f575a3978b5 extends Twig_Template { public function __construct(Twig_Environment $env) { parent::__construct($env); $this->parent = false; $this->blocks = array( ); } protected function doDisplay(array $context, array $blocks = array()) { // line 1 $context["foo"] = "bar"; // line 2 $this->loadTemplate("bar.twig", "main.twig", 2)->display($context); // line 3 echo " Foo in foo: "; // line 4 echo twig_escape_filter($this->env, ($context["foo"] ?? null), "html", null, true); } public function getTemplateName() { return "main.twig"; } public function isTraitable() { return false; } public function getDebugInfo() { return array ( 26 => 4, 23 => 3, 21 => 2, 19 => 1,); } public function getSourceContext() { return new Twig_Source("", "main.twig", "/fuz/twigfiddle.com/files/environment/k85WDdymIFgSoXLc/twig/main.twig"); } } 

    Источник bar.twig

     <?php /* bar.twig */ class __TwigTemplate_16789decfbb837d4631acf2e648380c0658722c50a0b53184b3f3c5f68f9b0ae extends Twig_Template { public function __construct(Twig_Environment $env) { parent::__construct($env); $this->parent = false; $this->blocks = array( ); } protected function doDisplay(array $context, array $blocks = array()) { // line 1 $context["foo"] = "foo"; // line 2 echo "Foo in bar: "; echo twig_escape_filter($this->env, ($context["foo"] ?? null), "html", null, true); } public function getTemplateName() { return "bar.twig"; } public function isTraitable() { return false; } public function getDebugInfo() { return array ( 21 => 2, 19 => 1,); } public function getSourceContext() { return new Twig_Source("", "bar.twig", "/fuz/twigfiddle.com/files/environment/k85WDdymIFgSoXLc/twig/bar.twig"); } } 

    Я нашел способ выполнить то, что искал, однако это не то, что было задано в вопросе, поэтому оно не будет помечено как ответ, но я отправляю быстрый ответ здесь, если кто-то пытается чтобы выяснить, как делать то, что я хотел сделать.

    В частности, я пытался включить JS и CSS-файлы из вложенных шаблонов Twig, и то, как я изначально думал, это было с тегом merge , но, как показано DarkBee в отмеченном ответе, это невозможно.

    В качестве альтернативы я смог создать расширение, которое позволяет мне делать то, что я ищу глобально, с таким количеством имен массивов, сколько мне хотелось бы:

     class arrayDefinitionExtension extends \Twig_Extension { public function getFunctions() { return array( new \Twig_SimpleFunction('addToArray', [$this, "addToArray"]), new \Twig_SimpleFunction('getArray', [$this, "getArray"]), ); } private $arrays = []; public function addToArray($name, $val) { $this->arrays[$name][] = $text; return ""; } public function getArray($name) { if(isset($this->arrays[$name])) { return $this->arrays[$name]; } else { return []; } } } 

    И для использования:

    base.php

     $loader = new \Twig_Loader_Filesystem('/path/to/templates'); $twig = new \Twig_Environment($loader); $twig->addExtension(new \arrayDefinitionExtension()); 

    base.twig

     {% block content %} {% endblock %} {% set includes = getArray("includes") %} {% for include in includes %} <script src="{{include}}" type="application/javascript"></script> {% endfor %} 

    main.twig

     {% extends "base.twig" %} {% block content %} {% include "test.twig" %} {% endblock %} 

    test.twig

     {% do addToArray("includes", "path/to/some/file.js") %} 

    Обратите внимание, что это последовательное, поэтому, если у вас есть блок content размещенный после печати тегов <script> то не будет никакого вывода.