Include twig file and transfer variables from separate file?

I have container.twig including component.twig and a passing object named 'mock'.

In the container.twig file:

{% set mock = { title : "This is my title" } %} {% include 'component.twig' with mock %} 

This works fine, but I want to move the mock data to my own file. This does not work:

Container.twig

 {% include 'component.twig' with 'mock.twig' %} 

In mock.twig

 {% set mock = { title : "This is my title" } %} 

Im uses gulp -twig, but in most cases it works like a standard branch. https://github.com/zimmen/gulp-twig

+8
twig gulp
source share
2 answers

Problem

The Twig context is never stored in the template object, so it will be very difficult to find a clean way for this. For example, the following Twig code:

 {% set test = 'Hello, world' %} 

Compiles for:

 <?php class __TwigTemplate_20df0122e7c88760565e671dea7b7d68c33516f833acc39288f926e234b08380 extends Twig_Template { /* ... */ protected function doDisplay(array $context, array $blocks = array()) { // line 1 $context["test"] = "Hello, world"; } /* ... */ } 

As you can see, the inherited context is not passed to the doDisplay method by reference and is never stored in the object itself (for example, $this->context = $context ). This deisgn allows templates to be reusable and easy to read.

Solution 1: using global variables

I don't know if you know about Global Variables in Twig. You can make a bunch of hacks with them.

The easiest use is to load all of your global variables inside your environment.

 $loader = new Twig_Loader_Filesystem(__DIR__.'/view'); $env = new Twig_Environment($loader); $env->addGlobal('foo', 'bar'); $env->addGlobal('Hello', 'world!'); 

Then you can use {{ foo }} and {{ Hello }} in your application.

But there are two problems here:

  • As you try to load variables from twig files, I assume that you have many variables to initialize depending on your function and do not want to load all the time.

  • you are loading variables from PHP scripts, not from Twig, and your question wants to import variables from a twig file.

Solution 2: use the Twig extension

You can also create a storage extension that provides a save function to save some template context somewhere and a restore function to merge this saved context into another.

proof_of_concept.php

 <?php require __DIR__.'/vendor/autoload.php'; class StorageTwigExtension extends Twig_Extension { protected $storage = []; public function getFunctions() { return [ new Twig_SimpleFunction('save', [$this, 'save'], ['needs_context' => true]), new Twig_SimpleFunction('restore', [$this, 'restore'], ['needs_context' => true]), ]; } public function save($context, $name) { $this->storage = array_merge($this->storage, $context); } public function restore(&$context, $name) { $context = array_merge($context, $this->storage); } public function getName() { return 'storage'; } } /* usage example */ $loader = new Twig_Loader_Filesystem(__DIR__.'/view'); $env = new Twig_Environment($loader); $env->addExtension(new StorageTwigExtension()); echo $env->render('test.twig'), PHP_EOL; 

twig / variables.twig

 {% set foo = 'bar' %} {% set Hello = 'world!' %} {{ save('test') }} 

twig / test.twig

 {% include 'variables.twig' %} {{ restore('test') }} {{ foo }} 

Note. If you want to import variables without actually rendering inside twig / variables.twig , you can also use:

 {% set tmp = include('variables.twig') %} {{ restore('test') }} {{ foo }} 

Final note

I'm not used to the twig JavaScript portlet, but it looks like you can extend it anyway, which is your move :)

+2
source share

Due to Twig validation rules (which I suppose are replicated by the gulp version), you cannot pass variables from a child template without creating a helper function. The closest thing you can do is use inheritance to replicate it.

This way your mock.twig file will become

 {% set mock = { title : "This is my title" } %} {% block content %}{% endblock %} 

Now your container.twig will become

 {% extends 'mock.twig' %} {% block content %} {% include 'component.twig' with mock %} {% endblock %} 

This allows you to completely separate the content layout from the templates and, using dynamic extensions, you can do something like

 {% extends usemock == 'true' ? 'contentdumper.twig' : 'mock.twig' %} 

with the contentdumper.twig file, which is just a stub like

  {% block content %}{% endblock %} 

and then set the usemock variable to determine if you will use layout data or not.

Hope this helps, although it doesn’t really solve the exact problem you are facing.

+3
source share

All Articles