Overriding twig blocks: the content of the overriden block is rendered as part of the document also - symfony

I'm reading this section about forms customization.
Now I want to custom a widget by myself so I have written the code below to overwrite the {% block money_widget %}. It works ok, but the content of my new block is also shown as you can see in the image. Why?
{% use 'form_div_layout.html.twig' %}
{% form_theme form _self %}
{% block money_widget %}
here my the content of the block
{% endblock %}
{% block content %}
{{ form(form) }}
{% endblock %}
This is the form type:
$builder
->add('user', null, array('label' => 'Cliente'))
->add('numberPlate', null, array('label' => 'NĂºmero matrĂ­cula', 'data' => 'prueba'))
->add('subtotal', MoneyType::class)
->add('tax', MoneyType::class, array('label' => 'I.V.A.'))
->add('total', MoneyType::class, array('label' => 'Total'))
->add('Guardar', SubmitType::class)
;
EDIT: I've found when this "problem" exactly happens: when the block to override the widget is inside template that is is being included using include. But why? Anyway, for this not to happen, I've created a template that works as a form theme, and add it this way for example:
{% form_theme form 'here_is_the_block_to_override_the_widget.html.twig' %}
in the template that I'm including using include

original widget in form_div_layout:
{%- block money_widget -%}
{{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }}
{%- endblock money_widget -%}
your block:
{% block money_widget %}
here my the content of the block
{% endblock %}
When you override the original block in your own template, the block from your template will be shown whenever money widget needs to be rendered. So in your final page you see here my the content of the block, as expected. BTW, in your tutorial page there is no use statement, maybe that makes it confusing.

Because your template must extend a base template referencing block content.
Create a minimal base template in app/Ressources/views/base.html.twig with :
{% block content %}
{% endblock content %}
and extends it in your template like this:
{% extends '::baseEmail.html.twig' %}
{% use 'form_div_layout.html.twig' %}
{% form_theme form _self %}
{% block money_widget %}
here my the content of the block
{% endblock %}
{% block content %}
{{ form(form) }}
{% endblock %}

Related

SonataAdminBundle templates - list and show fields template content duplication

My list and show fields contain the same content, but due the extending of base_list_field and base_show_field templates I have to create two separate templates.
list/location.html.twig:
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
{{ object.getCity }}, {{ object.getCountry.getName }}
{% endblock %}
show/location.html.twig:
{% extends 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
{% block field %}
{{ object.getCity }}, {{ object.getCountry.getName }}
{% endblock %}
As you can see huge part of code is duplicated. Is there a way to check the page I am currently in in twig and then extend certain base template? In this case I would be able to use one file instead of two for same content.
In twig it's possible to extend/include a dynamic template :
{# do test here on which page you are or pass through controller #}
{% if true %}
{% set template = 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
{% else %}
{% set template = 'SonataAdminBundle:CRUD:base_list_field.html.twig' %
{% endif %}
{% extends template %}
{% block field %}
{{ object.getCity }}, {{ object.getCountry.getName }}
{% endblock %}
(edit) if you don't want the hardcoded if I would pass the template variable through the controller and change the twig template to something like
{% extends template|default('SonataAdminBundle:CRUD:base_show_field.html.twig') %}

extends in symfony from multiple children

I have a base.html.twig with the basic html.
In the 'base' I have a {% block body %}{% endblock %} and a {% block javascript %}{% endblock %}
I call a 'form.html.twig' file from the Controller and the template extends the base.html.twig.
The 'form' contains the <form> and </form> tags and can contain a random numbers of sub templates/form elements:
'{% block body %}
{% for template in templates %}
{% embed template %}{% endembed %}
{% endfor %}
{% endblock %}'
The 'template' is perhaps a customer.html.twig, confirm.html.twig, vehicle.html.twig etc. etc. and they all have {% block body %} and {% block javascript %} - now for the question:
The content in the template files aren't moved to the blocks body/javascript. How do I get twig/symfony to move the content in the template files to the respective areas in the 'base.html.twig'?
Thank you for your time.
You want to use the use twig tag instead of the embed tag like this
{% use template %}
See more info here:
http://twig.sensiolabs.org/doc/tags/use.html

Twig variable doesn't exist in form_theme

I'm trying to override default Symfony2 form to implement the code below that will allow me to turn off html5 validation on and off by just passing a variable.
html5validation.toggle.html.twig
{% extends 'form_div_layout.html.twig' %}
{% block form_start -%}
{% if html5validation %}
{{ parent() }}
{% else %}
{{ parent
(
companyform, {'attr': {'novalidate': 'novalidate'}}
)
}}
{% endif %}
{%- endblock form_start %}
index.html.twig
form_theme company_form 'AcmeDemoBundle:html5validation.toggle.html.twig'
form(companyform)
In my controller I have:
$this->render('AcmeDemoBundle:Index:index.html.twig', array('html5validation' => false, 'companyform' => ...
If I try to dump(html5validation) inside index.html.twig I get bool(false).
But when I try to include the form_theme company_form AcmeDemoBundle:html5validation.toggle.html.twig
I get the error:
Variable "html5validation" does not exist
Can controller variables not be used inside themes?
Turns out only global variables are allowed to be used in form_theme(s) :(
Toggle html validation globally

Twig / Symfony2 Dynamic Template

I want to do this kind of thing so that if a template doesn't exist it just renders the content. The below code won't work though as you can't code it like this.
{% if app.request.attributes.get('twig_parent_template') != "" %}
{% extends app.request.attributes.get('twig_parent_template') %}
{% block title "The Title Here" %}
{% endif %}
{% block content %}
Content here
{% endblock %}
Can I do this kind of thing somehow?
Twig extends has a good documentation on this topic.
Since you need to specify a template to extend, my thoughts go on creating a default template.
#Bundle/Resources/views/yourview.html.twig
{% set extender = app.request.attributes.get('twig_parent_template') ? : 'Bundle::default.html.twig' %}
{% extends extender %}
{% block title "Your title" %}
{% block content %}
Your content
{% endblock %}
#Bundle/Resources/views/default.html.twig
{% block content %}{% endblock %}
#Bundle/Resources/views/parent.html.twig
{% block title %}{% endblock %}
{% block content %}{% endblock %}
Doing such, if app.request.attributes.get('twig_parent_template') is set, it will render the template given in its value.
Otherwise, it will render default.html.twig containing only the content block

symfony2: Applying theme to individual field for collection type

Just applying a theme to form field is easy e.g.:
{% form_theme form _self %}
{% block _product_name_widget %}
{{ block('field_widget') }}
{% endblock %}
but what if the form field is of collection type? E.g.: product['models'][1][comment,
I have no ideas how to customize it. (This may be the first kind question here)
UPDATE: anwser here: Symfony2: collection form field type with data-prototype
As of Symfony 2.1 (it may work as well for 2.0 but not sure) to apply theme for collection you do this way:
Lets say we have a collection of products (we have multiple Product entities)
Controller:
$repository = $this->getDoctrine()->getRepository('ExampleBundle:Product');
$products = $repository->findAll();
$productCollection = new Products;
foreach ($products as $product) {
$productCollection->getProducts()->add($product);
}
$collection = $this->createForm(new ProductsType, $productCollection);
return $this->render('ExampleBundle:Default:index.html.twig', array(
'collection' => $collection->createView()
));
Your theme can look like this:
{% block _productsType_products_entry_name_row %}
<div class="yourDivName">{{ block('form_widget') }}</div>
{% endblock %}
{% block _productsType_products_entry_description_row %}
<div class="yourDivDescription">{{ block('form_widget') }}</div>
{% endblock %}
The trick is with "entry" where twig will do the job for you to apply above changes to each row and for each field you specify
Hope that helps!
You can do with override collection_widget block:
{% block collection_widget %}
{% spaceless %}
{% if prototype is defined %}
{% set attr = attr|merge({'data-prototype': form_row(prototype) }) %}
{% endif %}
{{ block('form_widget') }}
{% endspaceless %}
{% endblock collection_widget %}
If you want how to customize form collection type try to look at this Product Bundle
You can override the collection_widget theme for a single field by referencing the widget like this as well.
For example, if "categories" is a "collection" widget on a ProductType form, you can do this.
{% block _product_categories_widget %}
{% for child in form %}
{{- form_row(child) -}}
<hr>
{% endfor %}
{% endblock %}

Resources