Symfony2 inherit from two form templates - symfony

I've set my forms to use a custom template (that produces a DL) and that works fine
twig:
form:
resources:
- 'myBundle:Form:row.html.twig'
But then I want to customise one row of one form and I think I have to do this
{% form_theme edit_form _self, ' %}
{% block _startYear_row %}
{% block form_row %}
{{ parent() }}
<div id="startCalendaryear"></div>
{% endblock %}
{% endblock %}
That make the entire form inherit from _self and loses the customisation of row.html.twig.
How can I set a custom template for all forms while still overriding a single row on one of them?

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 simple overriding with include

I have a simple Twig template, were I wan to override a block from the include.
base.html.twig:
{% block razem %}
{% include '_ga.code.html.twig' %}
{% endblock %}
_ga.code.html.twig:
{% block wspolny %}
should be common
{% endblock %}
{% block googleAnalitics %}
for overridden
{% endblock %}
success.html.twig
{% extends 'base.hmtl.twig' %}
{% block razem %}
{{ parent('wspolny') }}
{% block googleAnalitics %}
overriding part
{% endblock %}
{% endblock %}
Where is the error? http://twigfiddle.com/jsuk6a
I expected to render something like this:
should be common
overriding part
In twig you can not override blocks in a include. For this you have to use embed, but have to do this in the using template, not in the base one.
base.html.twig:
{% block razem %}{% endblock %}
_ga.code.html.twig:
{% block wspolny %}
should be common
{% endblock %}
{% block googleAnalitics %}
for overridden
{% endblock %}
success.html.twig
{% extends 'base.hmtl.twig' %}
{% block razem %}
{% embed '_ga.code.html.twig' %}
{% block googleAnalitics %}
overriding part
{% endblock %}
{% endembed %}
{% endblock %}
I think that the best way to override a block and reuse some others is to extend the base template where you want to perform an overriding (maybe adding some code to the pre-existing one) and to apply the so called horizontal reuse:
Horizontal reuse is an advanced Twig feature that is hardly ever needed in regular templates. It is mainly used by projects that need to make template blocks reusable without using inheritance.
Starting from that point, you should simply use the base.html.twig template and extend _ga.code.html.twig as follows:
success.html.twig
{% extends '_ga.code.hmtl.twig' %}
{# Simply use base - without overriding #}
{% use 'base.hmtl.twig' %}
{% block googleAnalitics %}
overriding part
{% endblock %}
If you want to make an overload of a single block you could also use the parent() function; so, you can add some other information to an extended block.
If you need something more complex you should go for dynamic inheritance.
{% extends ['base.html.twig', '_ga.code.html.twig'] %}

Symfony Twig customize an Individual field for a collection

In the documentation there is a way in Symfony to customize a Individual field, based on the name/id of the widget.
{% form_theme form _self %}
{% block _product_name_widget %}
<div class="text_widget">
{{ block('field_widget') }}
</div>
{% endblock %}
{{ form_widget(form.name) }}
Here, the _product_name_widget fragment defines the template to use for the field whose id is product_name (and name is product[name]).
This works for a normal widget, but not if a widget is inside a collection. Because of the extra columns. Like this:
name="productbundle_product_type[foobar][1][value]" id="productbundle_product_type_foobar_1_value"
What is the way to make the Twig customization work inside the collection?
I thought something like this, but that doesn't work:
{% for db in edit_form.list %}
{% block _productbundle_product_type_foobar_{{ db.name }}_widget %}
<div class="text_widget">
{{ block('field_widget') }}
</div>
{% endblock %}
{% endfor %}
Even the following doesn't work:
{% _productbundle_product_type_foobar_1_value_widget %}
What is the way to make it work?
I was working on a project a couple of evenings ago and encountered precisely this problem - the solution I found is a pair of blocks that look like this (stripped of project-specific code):
{# Collection markup #}
{% block my_collection_widget %}
{# Customise collection row prototype for allow_add #}
{% if prototype is defined %}
{% set data_prototype = block('my_collection_item_widget') %}
<div id="my_prototype" data-prototype="{{ data_prototype }}" style="display: none"></div>
{% endif %}
{% for prototype in form %}
{{ block('my_collection_item_widget') }}
{% endfor %}
{% endblock my_collection_widget %}
{# Collection row markup #}
{% block my_collection_item_widget %}
{# Collection contains simple, single type #}
{{ form_errors(prototype) }}
{{ form_label(prototype) }}
{{ form_widget(prototype) }}
{# OR #}
{# Collection contains a compound type, render child types independantly #}
{{ form_errors(prototype.inner_widget) }}
{{ form_label(prototype.inner_widget) }}
{{ form_widget(prototype.inner_widget) }}
{% endblock my_collection_item_widget %}
I know this is old question, but maybe people still happening upon this. This is explained fragment naming for collections.
You use _entry_ in these cases in place of the collection element number. Use the instructions in the link for fragment naming, but this might vary. Sometimes 'type' is part of the fragment's name, sometimes first letter is upper case, sometimes lower case, etc. I would use a browser developer tool to find the actual name to make sure. You might also be able to customize the names used by adding the getBlockPrefix function to the form class.
Therefore, in your case above, the customized block might look something like:
{% block _ProductBundle_product_entry_widget %}
<div> {{ form_row(form.field)}} </div>
{% endblock %}
Where 'field' would be the name of a field in the element of your collection.
A few things here:
1. Documentation Error
The docs seem to be a bit off with CamelCase entities. As for 5.3 it should be: _taskManager_taskLists_entry_widget (instead of _task_manager_task_lists_entry_widget)
You can confirm the naming by dumping the form or form field: {{ dump(form) }} or {{ dump(form.yourField) }} in your template and then look for unique_block_prefix within the vars section.
2. Do NOT use the block overrides, macros are much more easy
It makes things absolutely more complicated than necessary. Simply define a macro:
{% import _self as formMacros %}
{% macro formatCollection(form) %}
<div class="form-group row">
<div>
{{ form_widget(form.field1) }}
{{ form_widget(form.field2) }}
{{ form_widget(form.field3) }}
</div>
</div>
{% endmacro %}
then simply run it on each collection:
{% for item in form.collectionItems %}
{{ formMacros.formatCollection(item) }}
{% endfor %}
3. Prototype
Get the prototype before rendering the collection field. You can store it in a variable.
{% set prototype = form.collection.vars.prototype %}
Then simply render it whenever you like using our macro:
<div data-js="collection" data-prototype="{{ formMacros.formatCollection(prototype)|e('html_attr') }}">

Redefining a block initially defined in an included view in the parent view with twig

I have a view A that includes a view B that defines a block Z. Can I have a view C that extends A and redefines block Z?
Need not be said that if i paste B into A (without using an include) it works.
For a practical example:
A is the base of a project.
B is the header of a project that includes a menu.
C is any page of the project.
I define a {% block active %}{% endblock %} for each item of the menu in B, that i want to redefine by {% block active %} class="active" {% endblock %} in C to apply certain styles to the current active menu item.
If this is not the way to go, which is the best workaround/solution?
Unfortunately, it's not possible or it wouldn't be as easy.
Why not bind a variable to the template from the controller and passing it to the nav through the include?
{% include MyAwesomeBundle:Modules:nav.html.twig with {activeItem: activeItem, activeItemClassName: activeItemClassName} %}
An alternative to what you want
{# in base layout template #}
{% block nav %}
{% include MyAwesomeBundle:Modules:nav.html.twig %}
{% endblock %}
{# in page template #}
{% extends base-layout.html.twig %}
{% block nav %}
{% include MyAwesomeBundle:Modules:nav_for_news.html.twig %} {# nav_for_news.html.twig extends nav.html.twig #}
{% endblock %}
This is the closest you can get from what you want
Check out the parent() twig function it's useful.

Resources