symfony 2 form_row with 2 fields - forms

I need something like below:
{% block form_row %}
<div class="form_row">
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_widget(form.field_name + '_previous') }}
{{ form_errors(form) }}
</div>
{% endblock form_row %}
i.e, two form fields in one row; second field name is equal to first_field_name + _previous.
For example, if field name is 'total_cost', then second field will be 'total_cost_previous'.
How can I do that?

i think you can do something like this:
{% set field = field_name ~ '_previous' %}
{{ form_widget(attribute(form, field)) }}

Related

Symfony 6 - Access CollectionType fields in Twig Template

I have a Symfony 6 project, where I us a CollectionType in a Form.
This CollectionType is called "variants" and has three fields. Lets call them:
Field_1
Field_2
Field_3
If I render this CollectionType in my Twig template with {{form_row(form.variants)}} all three fields of the CollectionType are rendered underneith.
However, I would like to to separate each of the fields of the CollectionType in a own column next to each other. But how dow I access the fields?
I have tried to access the fields via {{form_row(form.variants.Field_1)}} but obviously that did not work.
I am happy about any ideas :)
you were close.
CollectionType is an array - as it can hold multiple sets of the type.
If you only have one set try
{{ form_row(form.variants[0].Field_1) }}
{{ form_row(form.variants[0].Field_2) }}
{{ form_row(form.variants[0].Field_3) }}
The for method:
{% for variant in form.variants %}
{{ form_row(variant.Field_1) }}
{{ form_row(variant.Field_2) }}
{{ form_row(variant.Field_3) }}
{% endfor %}
Thanks to Rufinus again.
I used that information and the remark from vinceAmstoutz and did the creation in a foor loop:
{% for variant in form.variants %}
<div class="row">
<div class="col">
{{ form_row(variant.Field_1) }}
</div>
<div class="col">
{{ form_row(variant.Field_2) }}
</div>
<div class="col">
{{ form_row(variant.Field_3) }}
</div>
</div>
{% endfor %}

symfony2 and twig: get properties of form field

I am trying to create a form with sub-fields with symfony2.
In twig I render the form as
{{ form_start(form) }}
{{ form_errors(form) }}
<div>
{{ form_label(form) }}
{{ form_errors(form) }}
{% for field in form %}
{{ form_widget(field) }}
{% endfor %}
</div>
{{ form_end(form) }}
However, I want to add some customization depending on the field I am rendering.
What I want to achieve is something like this:
{{ form_start(form) }}
{{ form_errors(form) }}
<div>
{{ form_label(form) }}
{{ form_errors(form) }}
{% for field in form %}
{% if field.label == "myvalue" %} <-- this code is not working
{# do something here #}
{{ form_widget(field) }}
{% endif %}
{% endfor %}
</div>
{{ form_end(form) }}
I am not able to access the label of each of my sub-fields in twig.
I think it is possible with something like
{{ field.vars.something }}
, but I did not manage to find any clear documentation about this.
Can someone please help?
Thank you!
Edit:
I actually found the answer to my question:
It was indeed just
{{ field.vars.label }}
and
{% if field.vars.label == "myvalue" %}
{# do something here #}
{{ form_widget(field) }}
{% endif %}
did the trick.
However, I am still looking for some good documentation about this "vars" attribute in twig, and what can be retrieved with it.
Thanks!
You'll find more information at http://symfony.com/doc/current/reference/forms/twig_reference.html#more-about-form-variables
On that page you'll find a list of common form vars. You might also create custom vars by implementing the buildView method of a FormType. You can read an example at http://symfony.com/doc/current/cookbook/form/create_form_type_extension.html#adding-the-extension-business-logic
Hope it'll help

symfony2 fosUserbundle input type with bootstrap

I'm quite new to symfony2, i have managed to implement fosUserBundle and Braincrafted bootstrap bundle.
I am trying to style the registration form to use boot strap and the inputs with input-sm class
the username and email are displaying as input-sm but the 2 password fields refuse to resize to the class i have applied.
is there somewhere in the fosUserbundle where the password field widget is configured
{% trans_default_domain 'FOSUserBundle' %}
{{ form_start(form, { 'style': 'horizontal', 'col_size': 'xs', 'label_col': 5, 'widget_col': 7, attr: {class: 'pull-left'}}) }}
{{ form_row(form.username, { attr: {class: 'input-sm'}}) }}
{{ form_row(form.email, { attr: {class: 'input-sm'}}) }}
{{ form_row(form.plainPassword, { attr: {class: 'input-sm'}}) }}
{{ form_row(form.plainPassword.second, { attr: {class: 'input-sm'}}) }}
<div class="col-sm-5"></div>
<div class="col-sm-7">
<input class="btn-primary btn-sm" type="submit" value="{{ 'registration.submit'|trans }}" />
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
FosUserBundle or not, you can overwrite Twig form rendering directly to achieve this, have a look at How to customize form rendering in SF cookbook.
Basically you can either get more precise in your template by splitting form_row into labels, widgets and errors to target the input ("form_widget" below) more specifically and apply the correct classes :
{{ form_errors(form.plainPassword) }}
{{ form_label(form.plainPassword) }}
{{ form_widget(form.plainPassword) }}
You can also generate your own form style for desired type of input by decalring it directly in your template :
{% form_theme form _self %}
{% block integer_widget %}
<div class="integer_widget">
// Your custom layout
</div>
{% endblock %}
{% Block body %}
// Rendering your form, your custom layout will be used.
{% endblock %}
You can also declare it in a separate template if you want to use it somewhere else, refer to the above cookbook page to see how.

How is symfony form rendered in the view

I was sure I understand this process, but when I dug deeper I saw I am wrong ;(
Let's take simple form, please notice that this form contains 3 fields
$form = $this->createFormBuilder($defaultData, ['csrf_protection' => false])
->add('email', 'email')
->add('name', 'text')
->add('message', 'textarea')
->getForm()
->createView();
which is rendered as
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
into
Built in "form" block from vendor\symfony\symfony\src\Symfony\Bridge\Twig\Resources\views\Form\form_div_layout.html.twig looks like:
{% block form %}
{% spaceless %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endspaceless %}
{% endblock form %}
and form_widget(form)
{% block form_widget %}
{% spaceless %}
{% if compound %}
{{ block('form_widget_compound') }}
{% else %}
{{ block('form_widget_simple') }}
{% endif %}
{% endspaceless %}
{% endblock form_widget %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
Let's modify form and form_widget a bit:
{% block form %}
{% spaceless %}
{{ form_start(form) }}
-form_widget before-
{{ form_widget(form) }}
-form_widget after-
{{ form_end(form) }}
{% endspaceless %}
{% endblock form %}
{% block form_widget %}
{% spaceless %}
- form_widget call -
{% if compound %}
- form_widget compound-
{{ block('form_widget_compound') }}
{% else %}
- form_widget simple-
{{ block('form_widget_simple') }}
{% endif %}
{% endspaceless %}
{% endblock form_widget %}
then as an output I got (listing 5):
<form name="form" method="post" action="" novalidate="novalidate">
-form_widget before-
- form_widget call -
- form_widget compound-
<div id="form" novalidate="novalidate">
<div>
<label for="form_email" class="required">Email</label>
<input type="email" id="form_email" name="form[email]" required="required" />
</div>
<div>
<label for="form_name" class="required">Name</label>
- form_widget call -
- form_widget simple-
<input type="text" id="form_name" name="form[name]" required="required" />
</div>
<div>
<label for="form_message" class="required">Message</label>
<textarea id="form_message" name="form[message]" required="required">Type your message here</textarea>
</div>
</div>
-form_widget after-
</form>
we can easly notcie the flow
form -> form_widget (input parameter is the whole form) -> form_widget_compound -> form_rows (iterates form elements into next function) -> form_row -> form_widget (this call form element is passed as parameter)
so here is the time for question, if form_widget is called 4 times (or more), once for form, 3 times for fields then why in listing 5 'form_widget call' text appears only 2 times?
or other words how email and message were rendered?
The form theming in SF2 uses inheritance. That means that if blocks named email_widget and textarea_widget are defined, neither your e-mail nor your textarea fields will use form_widget. They will rather respectively use their own widget blocks: email_widget and textarea_widget.
Well, in form_div_layout.twig, these two widget blocks are defined. Thus form_widget is not called for 2 of your fields. Thus your message is displayed 2 times instead of 4.
If you want to customize the rendering of these fields, you will have to create your own block definitions email_widget and textarea_widget in your custom form theme file.
Edit:
The default form theme files are defined under Symfony\Bridge\Twig\Resources\views\Form. The default file used is form_div_layout.html.twig.
Although the inheritance logic itself is indeed in the PHP code of the TWIG bridge, it does not define which block inherit from which other block.
Inheritance is actually defined in your FormType classes. Each form type class sports a getParent() method that return the name of the form from which it inherits. The name of a form type is the result of the method getName() of its associated form type class. For instance, with a built-in example, Symfony\Component\Form\Extension\Core\Type\TextareaType:
Textarea >> Text >> Field >> Form
All you have to do is to look for the methods getParent() and getName(). Thus, by default, when rendering the textarea row, Twig will search the block textarea_row, text_row, field_row and finally form_row (the base default row). The first of these blocks that is defined in your form theme is rendered.
The definition of the blocks themselves happen in the form theme files.

Symfony2 form layout - variables source

Here's the main form layout twig file:
https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
An example:
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
I wonder where varaibles like "type" or "value" come from?
The goal I'm trying to achieve is to set form row's label as a placeholder in the widget. How can I accomplish this?
Details how to override Template for Form field you will find here.
If you trying to change labels to placeholders all you need is to change way of rendering your forms. Remove form_widget(form) and switch to render every separate form field:
{# ... #}
<div class="form-group">
{{ form_errors(form.email) }}
{{ form_widget(form.email, {'attr': {'class': 'form-control', 'placeholder': 'E-mail address'|trans }}) }}
</div>
{# ... #}
This example generate input for email field and html/css classes for bootstrap.
And shows you how {{ type }} and {{ value }} are passed - by attr array.
Good Luck!