Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrap contextual html around a specific twig variable {{ product.name }}

I want to automatically wrap some html, lets say <span data-id=".."> when I call {{ product.name }} in my twig template.

So when in a twig template, I use {{ product.name }}, I want the output to be: <span data-type="product" data-id="8" data-prop="name">My product name</span>. I cannot use twig filters or macros, since I really need the template syntax to be {{ product.name }}, so the end-user (template designer), does not have to care about it.

The reason I need this is because I am building an on-page editting tool for twig templates, so I need to know the contexts of those variables from within HTML.

I have tried to override the Compiler that the Twig_Environment uses, but I cannot seem to alter the output of the twig variable node.

How can I do this?

EDIT

I wanted to mention that I need this to use the {{ product.name }} syntax, since other designers will work with those templates outside of Symfony 2. I want to make almost all twig variables editable in the front-end, so a solution with filters or macros can indeed work, but it kills the usability and readability of the platform I am writing. There is no public API currently in twig that can achieve what I want, that is why I am fiddling with the twig compiler. I do not have the required knowledge of the Twig internals to achieve this. If someone could point me into a direction that would be great!

UPDATE 2

I have found a place where I can achieve what I want. Every GetAttr node is compiled to $this->getAttribute($someContext, "property"). So if I can change the subclass of compiled twig template, I can achieve what I want. By default all twig templates extend from Twig_Template. I want to extend this method.

How can I change the subclass of all compiled twig templates?

UPDATE 3 I've found a way to use my own base class for all compiled twig templates. I can simply set it as an option on the twig environment, see this link. I hope to get it working tomorrow and I will post a proper answer on how I solved it all together. Not sure how I will handle escaping, since that will happen after the $this->getAttribute() is called.

like image 894
Steffen Brem Avatar asked Dec 10 '15 13:12

Steffen Brem


2 Answers

I think macros are the best candidates for those kind of wrappings.

For example:

main.twig

{% import "macros.twig" as macros %}

{{ macros.display_product(product) }}

macros.twig

{% macro display_product(product) %}

  <span data-id="{{ product.id }}" data-prop="name">{{ product.name }}</span>

{% endmacro %}

Context

product:
     id: 8
     name: My Georgeous Product

Result

<span data-id="8" data-prop="name">My Georgeous Product</span>

See fiddle

like image 109
Alain Tiemblo Avatar answered Oct 16 '22 04:10

Alain Tiemblo


I've solved it by wrapping the PrintNode that is created when parsing a VAR_START token (inside the twig parser) with my own EditablePrintNode. In that node I traverse the expression that is compiled by the print node and get the necessary property path and pass that as an argument to a wrapper function around the default twig escape function that is compiled by the PrintNode.

like image 2
Steffen Brem Avatar answered Oct 16 '22 04:10

Steffen Brem