I have a controller function which return a response with a value, and I want to call this controller from twig so I use:
{% render "UaePortailBundle:Note:isRempli" with { 'module_id' : module.id , 'year' : year } %}
the problem is that I want to set this returned value into a variable "x"
I tried this, but it doesn't work.
{% set x = {% render "UaePortailBundle:Note:isRempli" with { 'module_id' : module.id , 'year' : year } %} %}
According to the documentation, you can do:
{% set x %}
{% render "UaePortailBundle:Note:isRempli" with { 'module_id' : module.id , 'year' : year } %}
{% endset %}
Related
Context
I am actually trying to change the default placeholder for the time input of the OroDateTimeType::class.
I want to have, for example, the text Horaires instead of Temps.
Here is my form field in my FormType :
->add('expirationDate', OroDateTimeType::class, [
'label' => 'app.subscription.fields.expirationDate',
])
And in my twig view :
form_row(form.expirationDate)
Issue
At the beginning, I have tried to used the Symfony 4 placeholder option for DateTime type : https://symfony.com/doc/4.4/reference/forms/types/date.html#placeholder. It doesn't work because OroDateTime use a different datepicker and it override the Symfony values on load :
{# vendor/oro/platform/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig #}
{% block oro_datetime_widget %}
{% set dateValidation = {'Date' : {}} %}
{% set timeValidation = {'Time' : {}} %}
{% if required %}
{% set dateValidation = dateValidation|merge({'NotBlank' : {}}) %}
{% set timeValidation = timeValidation|merge({'NotBlank' : {}}) %}
{% endif %}
{% if attribute(attr, 'class') is defined %}
{% set attrClass = attr['class'] %}
{% else %}
{% set attrClass = '' %}
{% endif %}
{% set options = {
view: 'oroui/js/app/views/datepicker/datetimepicker-view',
nativeMode: isMobileVersion(),
dateInputAttrs: {
placeholder: 'oro.form.choose_date'|trans,
id: id,
name: id,
class: 'input-small datepicker-input ' ~ attrClass,
'data-validation': dateValidation|json_encode(constant('JSON_FORCE_OBJECT')),
'aria-live': 'assertive',
autocomplete: 'off',
autocorrect: 'off',
autocapitalize: 'off'
},
datePickerOptions: {
altFormat: 'yy-mm-dd',
changeMonth: true,
changeYear: true,
yearRange: years|default('-80:+1'),
showButtonPanel: true
},
timeInputAttrs: {
placeholder: 'oro.form.choose_time'|trans,
id: 'time_selector_' ~ id,
name: 'time_selector_' ~ id,
class: 'input-small timepicker-input ' ~ attrClass,
'data-validation': timeValidation|json_encode(constant('JSON_FORCE_OBJECT'))
},
timePickerOptions: {
}
} %}
{% set id = 'hidden_' ~ id %}
{% set attr = attr|merge({
'data-page-component-module': 'oroui/js/app/components/view-component',
'data-page-component-options': options|json_encode(constant('JSON_FORCE_OBJECT'))
}) %}
{{ block('datetime_widget') }}
{% endblock oro_datetime_widget %}
If I change the value timeInputAttrs.placeholder from the options variable. It works.
But, I want to pass this variable to my specific form field, not globally.
UPDATE
I finally choose to change the oro.form.choose_time translation in my project globally.
So, in my Resources/translations/messages.fr_FR.yml I've created these lines :
oro:
form:
choose_time: Horaires
auth:
description:
main: Baltimore
Then, I've understand that translations are generated in a file located in var/cache/dev/translations/catalogue.fr_FR :
<?php
use Symfony\Component\Translation\MessageCatalogue;
$catalogue = new MessageCatalogue('fr_FR', array (
'messages' =>
array (
'oro.form.choose_time' => 'Temps',
'oro.auth.description.main' => 'Baltimore',
Here, I can see that the oro.auth.description.main change is applied, but the value for the key oro.form.choose_time is still the same.
Maybe I have a command to run ?
The easiest way to override any text in the Oro application UI is to override a translation for the message used to render it. As the form placeholder is translated as well, you can use this technic. If it's the only customization you need for the form, follow this guide.
If you want to override an HTML, you can extend the template by following the template overriding guide.
But, as you want to modify the label for a single form, then the best way would be to extend the form type and override the single form field with new options.
I'm trying to override a variable in the included template.
Can I do this in a Symfony3 & Twig?
My twig template looks like this:
{% set foo = 'bar' %}
{% include 'first.html.twig' %}
{% include 'second.html.twig' %}
// first.html.twig
{{ foo }}
{% set foo = 'second' %}
// second.html.twig
{{ foo }}
I get such a result:
bar bar
But I expect:
bar second
The following Twig code:
{% set a = 42 %}
{{ include("first.twig") }}
Will be compiled to this one:
// line 1
$context["a"] = 42;
// line 2
echo twig_include($this->env, $context, "first.twig");
And twig_include prototype is:
# lib/Twig/Extension/Core.php
function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false)
So variables are passed by copy, not by reference in included templates. Thus your changes in included templates won't be reflected to including templates.
Moreover, since Twig 2.0, you can't call TwigEnvironment::addGlobal once twig runtime is initialized, so you can't glitch using simple extensions.
All in all, you can understand that if you need to update variables cross templates, it means some template contains business logic and Twig isn't build for that. You need to prepare the whole context in controllers.
Alternatively you may call a PHP class method from TWIG. Example of a page-counter needed when generating a pdf.
Custom class :
class PageCounter
{
private $pageNumber = 0;
public function incrementPageCounter()
{
$this->pageNumber ++;
return $this->pageNumber;
}
}
Controller:
....
$twigVariables = [
...
'pageCounter' => new PageCounter()
];
return $this->render('template.html.twig', $twigVariables);
Twig template (object pageCounter available from any included template)
{{ pageCounter.incrementPageCounter() }} / {{totalPages}}
You just need to do the check and override the variable with another variable :))
{% if name is defined %}
{% set foo = name %}
{% else %}
{% set foo = 'bar' %}
{% endif %}
{% include 'first.html.twig' %}
{% include 'second.html.twig' %}
// first.html.twig
{% set name = 'first' %}
// second.html.twig
{% set name = 'second' %}
Why not override your variable with your include tag/function like :
{% include 'first.html.twig' with {'foo': 'second'} %}
or :
{ include('first.html.twig', {foo: 'second'}) }}
I am working on a fairly complex multi lingual site that will render different partials based on the html locale.
I have a partial structure that will use the locale appended to the file name to pick the right one. For example;
{% include '#BundleName/Layout/Text/_partial-name.' ~ htmlLocale ~ '.html.twig' with {'title' : resource.title } %}
Whilst this works, there is a risk if the locale selected has not (yet) had its partial created, this will throw an error. What i would like to do is check for the existence of the partial before trying to render it and fall back to a default if it does not yet exist.
{% if '#BundleName/Layout/Text/_partial-name.' ~ htmlLocale ~ '.html.twig' %}
{% include '#BundleName/Layout/Text/_partial-name.' ~ htmlLocale ~ '.html.twig' with {'title' : resource.title } %}
{% else %}
{% include '#BundleName/Layout/Text/_partial-name.html.twig' with {'title' : resource.title } %}
{% endif %}
Obviously that doesn't work, but that's the kind of thing i am after!
Rather than to test if the partial exists you can use ignore missing:
{% include 'partial.html' ignore missing %}
If you do wish to have a fallback when the file is missing you can pass an array to the include function. This will make the include render the first found template in the array
{% include [
('#BundleName/Layout/Text/_partial-name.' ~ htmlLocale ~ '.html.twig'),
'#BundleName/Layout/Text/_partial-name.html.twig'
] with {'title' : resource.title } %}
You can use |default twig filter to determine a default value to a variable if the value is undefined or empty :
htmlLocale|default('en')
You can also check if the variable is empty and/or defined :
{% if htmlLocale is not empty and htmlLocale is defined %}
{% include '#BundleName/Layout/Text/_partial-name.' ~ htmlLocale ~ '.html.twig' with {'title' : resource.title } %}
{% else %}
{% include '#BundleName/Layout/Text/_partial-name.html.twig' with {'title' : resource.title } %}
{% endif %}
This is a follow up question to this one . What I want to know is how to check if the entity variable exist/is defined/not null. I thought I could do this:
{% if entity.orgId is defined %}
{{ render(controller(
'CompanyNameofBundle:OrgMember:test', {'orgid':entity.orgId})) }}
{% endif %}
But if entity.orgId is null I get an exception has been thrown during the rendering of a template ("The product does not exist").
Change your controller to return null instead of exception:
public function testAction($orgid = null) {
if (!$orgid) { return null; }
// Rest of code.
}
You have two options:
Don't call the render controller using the check
{% if entity.orgId is defined and entity.orgId is not null %}
Make the testAction in the OrgMemberController null-safe (check if the parameter orgid is null)
Try this:
{% if entity.orgId is defined %}
{% if entity.orgId is null %}
{# do something #}
{% else %}
{# do anythingelse #}
{% endif %}
{% endif %}
Given an array of variables sent to a twig template, such as:
$form = $this->createForm( new ServiceItemType()
, $entity
, array( 'attr'=>
array(
'em' => $this->EM()
,'group' => true
) ) );
I want to capture the variables for easy access in twig. However:
{% for key, value in form.vars.attr %}
{% set key = value %}
{% endfor %}
remaps the key variable in the for loop.
twig objects to:
{% for key, value in form.vars.attr %}
{% set {{key}} = value %}
{% endfor %}
And stack as I am aware never seems to address set. Would anyone who knows, please indicate how to accomplish this variable assignment?
I know this syntax works
{% render "..." with {(key): value} %}
Did you try the following syntax? As of March, Friday 22nd this syntax didn't work so you need to use a work around.
{% set (key) = value %}
An alternative to that would be to include a template and pass and form.vars.attr.
{% include "YourAwesomeBundle:Controller:template.html.twig" with form.vars.attr %}
You can also merge form.vars.attr with another array using the merge function.
{% set vars = {} %}
{% set vars = vars|merge(form.vars.attr) %}
{% include "YourAwesomeBundle:Controller:template.html.twig" with vars %}
Within the included template you will be able to use the variable em and group.