symfony2 form twig input value - forms

I am doing a form with symfony2 and twig, form who get infos from BDD.
I want to customize render in function of some informations.
If my data chanson is empty, I want to show input to set it.
If my data is not empty I want to show a paragraphe who shows data, and a link for modify the value and show the input.
I try something like that :
{% if form_widget(session.chanson).attrvalue!='' %}
<p>{{form_widget(session.chanson).attrvalue}} <a>modify</a></p>
{% else %}
<p>{{ form_label(session.chanson,"Chanson : ") }}
{{ form_errors(session.chanson) }}
{{ form_widget(session.chanson) }}</p>
{% endif %}
It's not working. I try with value instead of attrvalue, it's not working neither.
Here is what symfony say : Item "attrvalue" for "<input type="text" id="form_chanson" name="form[chanson]" required="required" value="La Rage" />" does not exist in CDUserBundle:Prof:edit_session.html.twig at line 19
Did someone know the issue ?
Thank you,

You could check if the app.session.chanson variable is empty instead using:
{% if app.session.chanson %}
<p>{{ app.session.chanson }} modify</p>
{% else %}
<p>{{ form_label(app.session.chanson,"Chanson : ") }}
{{ form_errors(app.session.chanson) }}
{{ form_widget(app.session.chanson) }}</p>
{% endif %}
You then need to plug the action you want on the modify link.
Also note that if your object chanson is stored in a session, the right way to access it in your twig template is by using the app.session object.

Related

Symfony2 disable form label html escape

I have a form label printed like this:
{% set txt = 'Im OK with the terms and conditions' %}
{{ form_label(form.terms, txt) }}
But obviously this will escape the html tag and will print something like this:
<label>Im OK with the <a href="#">terms and conditions</a></label>
Is there a way to disable the html escaping for this label only?
I've already tried:
{{ form_label(form.terms, txt|raw) }}
...
{{ form_label(form.terms, txt)|raw }}
...
{% autoescape false %}
{{ form_label(form.terms, txt) }}
{% endautoescape %}
Any help would be greatly appreciated :)
One solution that works, but I'm not sure is the best one, is to set the label tag manually:
<label for="{{ form.terms.vars.id }}">{{ txt|raw }}</label>

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.

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!

Symfony 2 Forms with Twig: add form variable to existing types

I need my symfony2/twig forms to adhere to a certain condition: All form rows must look similar to this:
{% block form_row %}
<div class="CONSTANT_CLASS class_based_on_field_type class_based_on_error">
{{ form_label(form) }}
{{ form_widget(form) }}
...
</div>
{% endblock form_row %}
Notice that I need to get the field type within the form_row block. Alas, the field type is only defined at the widget level.
I definitely need a way to let my form_row know what type of field it is dealing with.
So i suppose it would be best to somehow override the form_row twig function.
Where can the default twig functions be overridden? And how could this be done?
Remember, this is not about customizing a form. I need to know how to add to existing form variables for existing field types.
#nifr:
The key answer for you seems to be the {% set typeClass ... %}. But there is not a defined variable text anywhere for the template. Look at form_div_layout.html.twig at line 158ff, I think the type really gets set only at the form_widget level and is thus capsulated to be there. That means using the type at the form_row level will aways result in the given default (So it occurred to me while testing). If you can prove this wrong I will happily accept your answer.
How to override the form_row block in Twig adding attributes by field-type?
Though you say this is not about form customization it can be achieved with it ... Quick Introduction for others reading this now.
The default symfony twig form extensions can be found here.
The default twig form theme can be found at Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig.
General information on how to override forms can be found in the How to Customize Form Rendering chapter of the Book but i will sum this up shortly.
form_row Default
{% block form_row %}
{% spaceless %}
<div>
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
Overriding Form Level
Add this to the form template you want to customize:
{% form_theme form _self %}
If you want to put the {% block form_row %} into another bundle/template use this:
{% form_theme form 'AcmeDemoBundle:Form:fields.html.twig' %}
Now insert your custom form_row block after the form_theme declaration or put it into the specified template (in our case this would be AcmeDemoBundle:Form:fields.html.twig).
In my example we will add the class 'error' if there is an error in the form row and a another classname nameely the type name of the current field-type.
{% block form_row %}
{% spaceless %}
{# set class to 'error' if errors exist #}
{% set attr = attr|merge({'class': attr.class|default('') ~ (errors|length > 0 ? ' error' : '') }) %}
{% set typeClass = ' ' ~ type|default('text') %}
{#
you could also implement a logic matching input types with an array of their
desired classname-representations here.
#}
{% set attr = attr|merge({'class': attr.class|default('') ~ type) }) %}
<div class="{% for class in attr.class %}{{ class }}{% endfor %}{{ typeClass }}">
{{ form_label(form) }}
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
if you want to apply your form_row block system-wide add your AcmeDemoBundle:Form:fields.html.twig to your twig.templating.form.resources !
# app/config/config.yml
framework:
templating:
form:
resources:
- 'AcmeDemoBundle:Form'
In the form_row block you can use :
{{ form.vars.block_prefixes[2] }}
form.vars.block_prefixes gives you an array with more information and it might change with versions. But from what I have seen so far it is always index 2

How to customize data-prototype in symfony2 form collections?

I've got a collection of hidden fields in my form.
<ul id="user_roles">
<li><hidden field value="role1"></li>
<li><hidden field value="role2"></li>
(...)
</ul>
I use jQuery (and data-prototype) to add new roles.
The problem is that I would like to render something like this:
<ul id="user_roles">
<li>role1 <hidden field value="role1"></li>
<li>role2 <hidden field value="role2"></li>
(...)
</ul>
No problem with the initial rendering: i just put:
{% for role in roles %}
<li> {{ role }} {{ form_row(role) }} </li>
{% endfor %}
But the default data-prototype will render only {{ form_row(role) }} (a hidden field).
Where am I supposed to change the default data-prototype?
There is no {% block prototype %} in form_div_layout.html that i could customize....
The collection widget is defined as follows:
{% 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 %}
So you can override this to gain control on how you want to rendre the prototype.
You can also access prototype from inside template by calling roles.vars.prototype and use it later in your JS. If you want to put it into data-prototype attribute of div (as it is normally rendered) you have to remember to escape it:
<div data-prototype="{{ form_row(roles.vars.prototype) | escape }}">
{% for role in roles %}
<li> {{ role }} {{ form_row(role) }} </li>
{% endfor %}
</div>
The method recommended in the docs allows you to easily customize each collection independently inside your app, all within the same file.
Create a file prototype_layout.html.twig:
{% block _myform_mycollection_entry_row %}
<div class="row">
<div class="col-sm-6">{{ form_row(form.title) }}</div>
<div class="col-sm-6">{{ form_row(form.author) }}</div>
</div>
{% endblock %}
The name of the block is important. The first part will be _myform if your parent form is called MyformType and the second part _mycollection if your form field owning the collection is called so. The third part must always be _entry_row in order for this to work.
For example, if you have a UserType form with a collection of 'books' the block name might be _user_books_entry_row
To make sure you got the name right, add a subform (by clicking the add button adding subforms with javascript) and inspect the id of the corresponding select html element using the inspector tool of your browser.
If it looks like user_books_0_title, then the block name will be _user_books_entry_row
Declare this file as a global form theme in the twig section of config.yml:
twig:
form_themes:
- 'AppBundle:Form:prototype_layout.html.twig' #adapt this path if you saved your file elsewhere
You can also use the file directly in your form view:
{% use "AppBundle:Form:prototype_layout.html.twig" %}