Symfony2/Twig: Error on conditionally render - php

I'm trying to render a form on a twig template if its is defined in the render call on controller. Something like:
{% if form_to_be_rendered is defined %}
{{ form(form_to_be_rendered) }}
{% endif }
If the controller's render call includes the var of form_to_be_rendered, everything runs well, and the form is rendered. But if I try to render the template without this argument, Twig throws a RuntimeError indicating that the form_to_be_rendered variable is not defined.
Variable "form_to_be_rendered" does not exist in BundleName:Path/to/template:template.html.twig at line 3
500 Internal Server Error - Twig_Error_Runtime
I've tried passing it as a null value and is not null check on condition, but it fails too.
I put this dump on template:
{% dump reset_password_form is defined %}
And it is evaluated as false when I don't pass any arguments to render function.
EDIT
I forgot to post that there is a {% block content %} inside the conditional block which causes the issue. Please view the solution below.
Thanks,

Solved.
It's pretty weird and my fault since I don't post the full code on the OP.
{% if form is defined %}
{% block content%}
{{ form(form)}}
{% end block %}
{% endif %}
The conditional block has inside a {% block content %} that Twig tries to render even the condition is evaluated to false. If I surround the conditional block with the content block, the issue is resolved.
{% block content%}
{% if form is defined %}
{{ form(form)}}
{% endif %}
{% end block %}
Thanks

Twig documentation says:
defined:
defined checks if a variable is defined in the current context.
empty:
evaluates to true if the foo variable is null, false, an empty array, or the empty string.
null:
null returns true if the variable is null.
So figure out, what exactly you want to check, depending on what value "form_to_be_rendered" can have.

Did you try:
{% if form_to_be_renderer|length %}
{{ form(form_to_be_renderer) }}
{% endif %}

Related

Render a block of a "parent" template from a "child" template in Twig

I have two templates:
Fields.html.twig, which includes a child template.
{% block important %}
This block should be renderable from the sub template
{% endblock important %}
{% include 'XButton.html.twig' %}
XButton.html.twig, which needs to render blocks defined in the template that includes it.
block('important')
It seems like an included template isn't able to simply render blocks of whoever included it.
How can the parent template pass the full context to the child, so that the child can access the blocks defined in the parent?
What you're trying to do it's impossible, because the included template has no way to know about blocks defined in other templates...
You'll need to structure your code a bit differently, so that the contents of the block are defined in the parent somehow - you have at least a couple of options:
Using set and include: https://twigfiddle.com/l536np
Fields.html.twig
{% set important %}
You define the child content as a variable in the parent...
{% endset %}
{% include 'XButton.html.twig' %}
XButton.html.twig
{{ important }}
Using embed: https://twigfiddle.com/y9pp6p
Fields.html.twig
{% embed 'XButton.html.twig' %}
{% block important %}
You define the block content in the parent...
{% endblock %}
{% endembed %}
XButton.html.twig
{{ block('important') }}
You can do it with include by passing the parent template name
{% block important %}
This block should be renderable from the sub template
{% endblock important %}
{% include 'XButton.html.twig' with {'parent': _self} %}
And then use it in the include template
{{ block('important', parent) }}
Although this way the content of the block will be rendered twice - once when you define it in the parent, and once again in the child - see https://twigfiddle.com/6t0l6p

How to automatically check if variables are not empty in Symfony 3?

(Sorry for this bad english)
I would like to know if it's possible to automatically check if variables from MySQL request are not empty in Symfony 3. I know that I can put {% if foo is defined %} in Twig or something like this but I didn't find if there's a way to do it automatically. I can test the request in the controller too. But with those solutions I have to do it for every request.
All my website uses "if not empty then show it" that's why I'm trying to find it.
Edit : I know how to check every fields of every request in Twig or in php (Controller) one by one but there is a lot of duplication code, which is "boring". Thats why I am asking you if something automatic exists to check my data. (parameter in Symfony, ...)
Thank you <3
If I understand, your problem :
You want to iterate on each property in an entity. But you can't, then you are searching for a solution to not write :
{% if entity.property1 %}
{{ entity.property1 }}
{% endif %}
{% if entity.property2 %}
{{ entity.property2 }}
{% endif %}
{% if entity.property3 %}
{{ entity.property3 }}
{% endif %}
You have two solutions to make your properties traversable :
Get your entity with a Doctrine query using ->getArrayResult() instead of ->getResult()
Use ReflectionClass to get the properties as an array :
http://php.net/manual/fr/class.reflectionclass.php
So you can iterate on each property, and do something like that :
{# Where you get your entity as an array #}
{% for property in entity %}
{% if not property is null %}
{{ property }}
{% endif %}
{% endfor %}
{# where fields comes from the ReflectionClass #}
{% for field in fields %}
{% if not attribute(entity,field) is null %}
{{ attribute(entity,field)}}
{% endif %}
{% endfor %}
Use the Twig strict_variables config parameter and set it to false (should be the default value):
strict_variables boolean
If set to false, Twig will silently ignore invalid variables
(variables and or attributes/methods that do not exist) and replace
them with a null value. When set to true, Twig throws an exception
instead (default to false).

How to check whether array element is defined or not in twig file?

I am trying to access array but it is not getting accessed.
in my config.yml following is my array :
abc : [xyz]
and in another file i am writing following code to access abc array.
{% if abc[0] is defined) %}
then do something
{% endif %}
but somehow its not working. please help me out i am newbie in this.
It depends if the variable is always declared or not:
If the variable is always declared and the array can be empty
{% if abc is not empty %}
{# then do something #}
{% endif %}
<variable> is not empty in Twig is equivalent to !empty($variable) in PHP. When an array is provided, is not empty will check there is a value and/or a value in the array.
empty test in Twig documentation.
If the variable is not always declared
Check that the abc variable is declared and not empty:
{% if (abc is declared) and (abc is not empty) %}
{# then do something #}
{% endif %}
<variable> is declared in Twig is equivalent to isset($variable) in PHP.
defined test in Twig documentation.
Based on comments I would recommend using foreach loop instead and define your ifs based on index values. Something like this:
{% for abcs in abc %}
{% if (loop.index == 0) %}
then do something
{% endif %}
{% endfor %}
BR's

Difference between customizing form theme and referencing block in Symfony?

what is the difference between referencing a widget block and customizing it : the docs say :
So far, to override a particular form block, the best method is to
copy the default block from form_div_layout.html.twig, paste it into a
different template, and then customize it. In many cases, you can
avoid doing this by referencing the base block when customizing it
But to me it looks the same :
{# app/Resources/views/Form/fields.html.twig #}
{% extends 'form_div_layout.html.twig' %}
{% block integer_widget %}
<div class="integer_widget">
{{ parent() }}
</div>
{% endblock %}
{# app/Resources/views/form/fields.html.twig #}
{% block integer_widget %}
<div class="integer_widget">
{% set type = type|default('number') %}
{{ block('form_widget_simple') }}
</div>
{% endblock %}
What is the difference?
The first example in the documentation that you are referencing shows how to override the entire widget that displays your form element.
The second example in the documentation that you are referencing shows how you can employ code re-use so that you are not rewriting form templating sections that you are not modifying. So, instead of having to declare
{% set type = type|default('number') %}
{{ block('form_widget_simple') }}
all over again in your overriding widget, you can instead reference the base block that already has this. If you are referencing base blocks from an external template, you can call the parent block via {{ parent() }}, and if you are referencing blocks from inside the same template as the form, you can call the base block via {{ block('base_integer_widget') }}
If you look at it from a PHP/Symfony point of view with inheritance that can help explain it as well. Say you have one PHP class that extends another and you want to override a function named doSomething() - you might rewrite the entire function as you need it. But, say that doSomething() has a block of common code that you always want to run, then you might perform your actions and call parent::doSomething() at the end of it. Or, if you're accessing a different Symfony service you might call $this->get('some.service')->doSomething() instead.
That's the same concept here, you can either override the entire widget or you can override parts of it - perhaps putting a surrounding <div></div> but calling {{ parent() }} from within that since you're changing nothing else about the widget.
I do have one example where I overrode standard button behavior in Symfony and used both cases. I have a separate template file in `app/Resources/views/Form/navigationButton.html.twig' with the following code:
{% use 'form_div_layout.html.twig' %}
{% block button_widget -%}
{% set attr = attr|merge({class: (attr.class|default(''))|trim}) %}
{{- parent() -}}
{%- endblock %}
{% block button_row -%}
{{- form_widget(form) -}}
{%- endblock button_row %}
I am overriding the button widget by allowing additional classes to be passed as attributes and then calling the parent widget to produce it as normal. I then override the button row widget to not put surrounding <div></div> tags since I didn't want that in my template (see the originals here and here).
Then to use in one of my templates I simply do:
{% form_theme form ':Form:navigationButton.html.twig' %}

Twig return value from a template?

sub.html
{% set xx = 10 %}
main.html
{% set xx = '20' %}
{% include 'sub.html' %}
{{ xx }}
Which would give:
20
Seems variables in a twig template are scoped within that particular template and not accessible from outside scope.
Is there any way to make it give 10?
I ask this because it can be useful to do basic variable assignments / calculations inside Twig templates so as to simplify / normalize the parameters we need to provide to Twig_Template::render().
These variable assignments / calculations operations are usually shared by multiple Twig templates and it makes sense to group them in one place like a function that can be re-used from multiple templates.
Is there any way to return a value from a macro or an included template? Or make them use outside variables by reference?
I had similar problem. It's not what you want in general, but could be useful.
Base template base.html.twig:
{% block navbar %}
{% if navbar_style is not defined %}
{% set navbar_style = 'navbar-inverse navbar-transparent' %}
{% endif %}
{% include 'LibraryBundle:BaseComponents:header.html.twig' %}
{% endblock %}
Some page template:
{% extends 'base.html.twig' %}
{% set navbar_style='navbar-ct-blue' %}
...
So you can make some decision based on variable in inherited template.

Categories