Can't get global variables in twig to work - symfony

So I have Twig running on top of Symfony 2.7. In the output html I'd like to have a few modules of text and in the last module I want some summary from all the previous ones (some data from all the previous modules' Entities) and I figured I'd append these summaries to a global variable while generating modules themselves to avoid a second loop. The code I'm using:
{% extends 'base.html.twig' %}
{% set list = '' %} {# HERE I SET A GLOBAL VAR #}
{% block body %}
<section>
<h2>{% trans %}MODULES{% endtrans %}</h2>
{% for m in plan.Modules %}
{{- block('module') -}}
{{ list }} {# HERE JUST FOR TESTING - IT'S EMPTY #}
{% endfor %}
</section>
{{ list }} {# HERE I WANT IT DISPLAYED, YET IT'S EMPTY :( #}
{% endblock %}
{% block module %}
<h3>{{ m.Module.title }}</h3>
{# HERE SOME MODULE TEXT I GET FROM COMPLICATED RELATIONS #}
{% if m.Module.list %}
{% set temp %}
{{ m.Module.shortTitle }}<br/>
{% endset %}
{% set list = list~temp %}
{% for l in m.Module.list %}
{% set temp %}
{{ l }}
{% endset %}
{% set list = list~temp %}
{% endif %}
{% endfor %}
{% endif %}
{{ list }} {# HERE IT'S WORKING #}
{% endblock %}
Any ideas?

Related

Is there a way to define logic in a block rather than in a bunch of individual tags?

For Example I have quite a lot of logic that looks like this
{% set allowed_observations = ["PAR;101;ZN_GYM", "PAR;101;ZN_CARDIOGYM", "PAR;101;0;G15"] %}
{% set allowed_observations_names = ["Downstairs Gym", "Upstairs Gym (Cardio)", "Swimming Pool"] %}
{% for observation in observations %}
{% if (observation.location.locationCode in allowed_observations) %}
{% if ("HeadCount" in observation.observationTag) %}
{% set name = "" %}
{% for key,value in allowed_observations %}
{% if (value == observation.location.locationCode) %}
{% set name = allowed_observations_names[key] %}
{% endif %}
{% endfor %}
{% set data = data | push({
name: name,
location: observation.location.locationCode,
value: observation.value
}) %}
{% endif %}
{% endif %}
{% endfor %}
I was wondering if you can just do a single {% ...all code... %} type thing, using ; for line breaks or something?

Influence the twig included file on parent

I have a problem like this
But i can not use {% use %}
for example:
{# file1.twig #}
{% extends "main.twig" %}
{% block content %}content text{% endblock %}
{# main.twig #}
{% block content %}{% endblock %}
{% for widget in widgets %}
{% embed widget %}{% endembed %}
{% endfor %}
{% block js %}{% endblock %}
{# widget1.twig #}
{% block js %}
script1
{% endblock %}
{# widget2.twig #}
{% block js %}
script1
{% endblock %}
I want to be the result:
content text
script1
script2
I have a lot of files like file1.twig and widget1.twig
I can not use all the widgets in the all files.
Also, {{ parent() }} does not work for me
Is there another way?

Simple Twig Logic issue

I'am using following code to set selectedGallery to a defaultValue. The default Value should be galleryData's first Element.
Sadly it doesn't work. selectedGallery does not exist after the snipped run through...
Thanks for help
{% if selectedGallery is not defined %}
{% for gallery in galleryData|keys|slice(0, 1) %}
{% set selectedGallery = gallery %}
//if i access galleryData here, it exists ?!
{% endfor %}
{% endif %}
later the same file:
<div id="{{idPref}}PictureBox" class="backA">
{% block pictureBox %}
{% for picture in galleryData[selectedGallery] %}
{{selectedGallery}}
{% endfor %}
{% endblock %}
Symfony says that the variable doesn't exists.
Try:
First:
{% if selectedGallery is not defined %}
{% set selectedGallery = galleryData|keys|first %}
{# ... #}
http://twig.sensiolabs.org/doc/filters/first.html
Later:
<div id="{{idPref}}PictureBox" class="backA">
{% block pictureBox %}
{% for picture in attribute(galleryData, selectedGallery) %}
{{picture}}
{% endfor %}
{% endblock %}
{# ... #}
http://twig.sensiolabs.org/doc/functions/attribute.html

Custom form field template with twig

I'd like to create a custom template in twig to render a form field.
Example:
{{ form_row(form.field) }}
This can be overriden by form theming
{% block form_row %}
... custom code
{% endblock form_row %}
What I would like to do is this:
{% block custom_row %}
... custom code
{% endblock custom_row %}
and use it like this:
{{ custom_row(form.field }}
however, this throws an exception that method custom_row is not found.
My understanding is that this can be done with Twig extension, but I don't know how to register a block to be a function.
Update
what I actually want:
I use twitter bootstrap and a bundle which overrides all the form themes. And it renders a div around a radio, so it can't be inlined. So I wanted to do something like this:
copy their template and get rid of the div:
{% block inline_radio_row %}
{% spaceless %}
{% set col_size = col_size|default(bootstrap_get_col_size()) %}
{% if attr.label_col is defined and attr.label_col is not empty %}
{% set label_col = attr.label_col %}
{% endif %}
{% if attr.widget_col is defined and attr.widget_col is not empty %}
{% set widget_col = attr.widget_col %}
{% endif %}
{% if attr.col_size is defined and attr.col_size is not empty %}
{% set col_size = attr.col_size %}
{% endif %}
{% if label is not sameas(false) %}
{% if not compound %}
{% set label_attr = label_attr|merge({'for': id}) %}
{% endif %}
{% if required %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{% endif %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' radio-inline')|trim}) %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ block('radio_widget') }}
{{ label|trans({}, translation_domain) }}
</label>
{% else %}
{{ block('radio_widget') }}
{% endif %}
{{ form_errors(form) }}
{% endspaceless %}
{% endblock inline_radio_row %}
and then
{{ inline_radio_row(form.field) }}
I ended up just overriding the whole theme, and added ifs around the div in question, a the class (radio-inline). But I'm still wondering if there's a way to make this work. Seems like it makes you work so hard for something so simple.
Update 2
I found the functionality:
class FormExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
'inline_radio_row' => new \Twig_Function_Node(
'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode',
array('is_safe' => array('html'))
),
);
}
}
This does exactly what I want, but it says it's deprecated. Anyone knows an updated version of how to use this?
Update 3
Similar functionality can be also achieved with http://twig.sensiolabs.org/doc/tags/include.html
You can use the twig functions for each part of a form row:
form_label(form.field)
form_widget(form.field)
form_errors(form.field)
For example:
<div class="form_row">
{{ form_label(form.field) }} {# the name of the field #}
{{ form_errors(form.field) }} {# the field #}
{{ form_widget(form.field) }} {# the errors associated to the field #}
</div>
You can use form theming.
Step by step:
1. Form Type Class
Check the name in your class
public function getName() {
return 'hrQuestionResponse';
}
2. Include a custom theme in your template
{% form_theme form 'InterlatedCamsBundle:Form:fields.html.twig' %}
3. Find the block
Can be quite difficult. For the bootstrap bundle, as you seem to have found it is in ./vendor/braincrafted/bootstrap-bundle/Braincrafted/Bundle/BootstrapBundle/Resources/views/Form/bootstrap.html.twig and you have found the block radio_row. I have been finding the block by putting output in the source template and overriding more blocks than I need. In 2.7 there is a theme 'rendering call graph'.
4. Override the block
Copy the block from the master template and call it replace the standard term with the name of in the FormType found in step 1.
Don't forget to also change the endblock name.
e.g.
{% block hrQuestionResponse_widget %}
hrQuestionResponse_row
{% spaceless %}
{% set class = '' %}
...
{% endspaceless %}
{% endblock hrQuestionResponse_widget %}
In your case because you can only call form_widget() you will need to override _widget. You could extract only the content that you need, or you can override the block chain to radio_row.

Customization of a form widget in Symfony2/Twig

In my form template:
{% block field_label %}
{% spaceless %}
<label {{ block('widget_attributes') }}></label>
{% endspaceless %}
{% endblock %}
I need to add some extra class attributes and, of course, display the label (possibly translated). I've found that {{ block('widget_attributes') }} stores a string of attributes of the actual label.
Any chance to get an array type to easily modify it? Where i can find all block names to customize the appearance to fit my needs? Thanks for helping.
Nevermind Notepad++ helped me to find the file:
vendor\symfony\src\Symfony\Bridge\Twig\Resources\views
Three types of label defined:
{# Labels #}
{% block generic_label %}
{% spaceless %}
{% if required %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
{% endif %}
<label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }}</label>
{% endspaceless %}
{% endblock %}
{% block field_label %}
{% spaceless %}
{% set attr = attr|merge({'for': id}) %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock field_label %}
{% block form_label %}
{% spaceless %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock form_label %}

Resources