Symfony bootstrap theme - php

How to change default order of symfony form components?
I would like to have following order:
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_help(form) }}
{{ form_errors(form) }}
Currently is:
{{ form_errors(form) }}
{{ form_label(form) }}
{{ form_widget(form) }}
{{ form_help(form) }}
I have tried to modify this file: vendor/symfony/twig-bridge/Resources/views/Form/bootstrap_4_layout.html.twig:
...
{% block form_label -%}
{% if label is same as(false) -%}
{%- if errors|length > 0 -%}
<div id="{{ id }}_errors" class="mb-2">
{{- form_errors(form) -}}
</div>
{%- endif -%}
{%- else -%}
{%- if compound is defined and compound -%}
{%- set element = 'legend' -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
{%- else -%}
{%- set label_attr = label_attr|merge({for: id}) -%}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif -%}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>{{ translation_domain is same as(false) ? label : label|trans(label_translation_parameters, translation_domain) }}{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %}</{{ element|default('label') }}>
{%- endif -%}
{%- endblock form_label %}
...
But without any success.
As you can see I have changed the order and put the errors in the first place, but still, it does not work and display an error in the first position.

First, you need to create a custom form theme for this, as outlined in the docs:
# config/packages/twig.yaml
twig:
form_themes: ['app_form_layout.html.twig']
Within app_form_layout.html.twig, we're going to override a couple of blocks to move the errors in the correct position:
We need to remove the default form_error(form) call from the form_label block, otherwise you'll end up with the form error being visible in two places.
We need to move that call to form_widget (which is a level up in the form template hierarchy tree)
Untested code example:
{% use "bootstrap_4_layout.html.twig" %}
{# this is basically the default form_label block, but with the form_error block definition removed, see line 260 of bootstrap_4_layout.html.twig #}
{% block form_label -%}
{# I think you can safely remove this if-statement, you currently might end up with 2 errors when you have a form with no label defined. #}
{% if label is not same as(false) -%}
{%- if compound is defined and compound -%}
{%- set element = 'legend' -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
{%- else -%}
{%- set label_attr = label_attr|merge({for: id}) -%}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif -%}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>
{%- if translation_domain is same as(false) -%}
{%- if label_html is same as(false) -%}
{{- label -}}
{%- else -%}
{{- label|raw -}}
{%- endif -%}
{%- else -%}
{%- if label_html is same as(false) -%}
{{- label|trans(label_translation_parameters, translation_domain) -}}
{%- else -%}
{{- label|trans(label_translation_parameters, translation_domain)|raw -}}
{%- endif -%}
{%- endif -%}
{# here was the form_errors call which is now gone #}</{{ element|default('label') }}>
{%- else -%}
{%- if errors|length > 0 -%}
<div id="{{ id }}_errors" class="mb-2">
{{- form_errors(form) -}}
</div>
{%- endif -%}
{%- endif -%}
{%- endblock form_label %}
{# here, we're adding the form_errors(form) call we just removed from the form_label block, so the error is in the correct position #}
{% block form_row -%}
{%- if compound is defined and compound -%}
{%- set element = 'fieldset' -%}
{%- endif -%}
{%- set widget_attr = {} -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
{%- endif -%}
<{{ element|default('div') }}{% with {attr: row_attr|merge({class: (row_attr.class|default('') ~ ' form-group')|trim})} %}{{ block('attributes') }}{% endwith %}>
{{- form_label(form) -}}
{{- form_widget(form, widget_attr) -}}
{{- form_help(form) -}}
{{- form_errors(form) -}} {# << here :-) #}
</{{ element|default('div') }}>
{%- endblock form_row %}

Related

Global Symfony twig form_themes switching

I want to override default form_div_layout with form_table_layout
(In docs: type: array of string default: ['form_div_layout.html.twig'])
My config/packages/twig.yaml is
twig:
form_themes: ['form/form_table_layout.html.twig']
default_path: '%kernel.project_dir%/templates'
I copy vendor/symfony/twig-bridge/Resources/views/form/form_table_layout.html.twig to templates/form/form_table/form_table_layout.html.twig
{% use "form_div_layout.html.twig" %}
{%- block form_row -%}
{%- set widget_attr = {} -%}
{%- if help is not empty -%}
{%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%}
{%- endif -%}
<tr{% with {attr: row_attr} %}{{ block('attributes') }}{% endwith %}>
<td>
{{- form_label(form) -}}
</td>
<td>
{{- form_errors(form) -}}
{{- form_widget(form, widget_attr) -}}
{{- form_help(form) -}}
</td>
</tr>
{%- endblock form_row -%}
(etc)
Desired outcome: the forms are in table layout. Reality: they are still in div layout.
debug:config twig shows
form_themes:
- form_div_layout.html.twig
- form/form_table_layout.html.twig
File path is right:
file templates/form/form_table_layout.html.twig
templates/form/form_table_layout.html.twig: HTML document, ASCII text
cache:clear and restarting the server doesn't help...
What can be the issue or I don't understand the way Symfony themes work?

Symfony 3.2 Form Field - Disabling the ID

Is it possible to render an input field without id?
I would like to disable it in the twig file.
I want that because I have a error "non-unique id" in the chrome console.
I have conducted research using the Symfony's documentation and I have found something that should work: "Customizing Form Output all in a Single File with Twig"
The block I want to replace is
{%- block widget_attributes -%}
This block is inside of the form_div_layout.twig.html
I put this inside of my_form.twig.html
{% form_theme form _self %}
{% block form_row %}
{%- block widget_attributes -%}
id="{{ id }}" name="{{ full_name }}"
{%- if disabled %} disabled="disabled"{% endif -%}
{%- if required %} required="required"{% endif -%}
{%- for attrname, attrvalue in attr -%}
{{- " " -}}
{%- if attrname in ['placeholder', 'title'] -%}
{{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans({}, translation_domain) }}"
{%- elseif attrvalue is same as(true) -%}
{{- attrname }}="{{ attrname }}"
{%- elseif attrvalue is not same as(false) -%}
{{- attrname }}="{{ attrvalue }}"
{%- endif -%}
{%- endfor -%}
{%- endblock widget_attributes -%}
{% endblock form_row %}
{{ form_start(form) }}
......
And I get the error:
"Variable "full_name" does not exist. "
I don't want to edit the form_div_layout.html.twig
I did it!
For now, I think I found the solution
{% form_theme form _self %}
{% block form_row %}
{% block input_widget %}
{% set id = random() %} {# Random number for the id #}
{{ block('form_widget') }}
{% endblock input_widget %}
{% endblock form_row %}
{{ form_row(form.my_form) }}
This is not the final solution because I want the "id" not to show in the input form.

How to custom HTML form_errors in Symfony

I would like custom the render of form_errors in Symfony 3, because I would like obtain (in my Twig remplate) :
<div class="alert alert-danger">My error</div>
Instead of :
<ul><li>My error</li></ul>
It's possible ?
I tried this :
{{ form_errors(form.name) ? '<div class="alert alert-danger">' ~ form_errors(form.name) ~ '</div>' : '' }}
But the HTML is not interpreted and it may not be very clean ..
And this (Recovery of vendor\symfony\symfony\src\Symfony\Bridge\Twig\Resources\views\Form\form_div_layout.html.twig line 307):
I overloaded:
{%- block form_errors -%}
{%- if errors|length > 0 -%}
<ul>
{%- for error in errors -%}
<li>{{ error.message }}</li>
{%- endfor -%}
</ul>
{%- endif -%}
{%- endblock form_errors -%}
By :
{%- block form_errors -%}
{%- if errors|length > 0 -%}
<ul>
{%- for error in errors -%}
<li>{{ error.message }}</li>
{%- endfor -%}
</ul>
{%- endif -%}
{%- endblock form_errors -%}
But the variable "error" is not defined
Thanks in advance for your help
Take a look at this website:
https://symfonycasts.com/screencast/symfony-forms/form-theme-create#play
You need to modify below file
vendor/symfony/symfony/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig
and search for the {% block form_errors -%} block to modify it.
you can look here for more informations:
https://codereviewvideos.com/course/beginner-s-guide-to-symfony-3-forms/video/styling-and-customising-using-form-fragments
But this is not the right method, the good one is to override this file by copy that block into another twig template, modify it and call this template into the twig template of your page.
Here are the explanations:
https://symfonycasts.com/screencast/symfony-forms/form-theme-create#play

Adding html code in radio label

I am fighting with customize on symfony forms for twig...
My problem is to add html inside a label for a radio button like <strong>25</strong> but it is escaped by default and I can't find how to unescape. I use the following code.
{% block choice_widget %}
{%
set labels = {
1: { title: '1 ' ~ 'label.credits'|trans ~ ' - <strong>1€</strong>' },
2: { title: '2 ' ~ 'label.credits'|trans ~ ' - <strong>2€</strong>' },
25: { title: '25 ' ~ 'label.credits'|trans ~ ' - <strong>25€</strong>' },
}
%}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{% if child.vars.value matches '/^[1|2|25]{1}/' %}
{% set currentLabel = labels[child.vars.value].title %}
{% else %}
{% set currentLabel = '' %}
{% endif %}
{{ form_widget(child, {'label': currentLabel}) }}
{{ form_label(child) }}
{{ form_errors(child) }}
{% endfor %}
</div>
{% endblock %}
In your case you will need to override the form_label block and incorporate into your own theme (https://symfony.com/doc/current/form/form_customization.html), this is for bootstrap 4 (find the file in vendors folder called bootstrap_4_layout.html.twig, if you need this for bootstrap 3 just do the same but the file is bootstrap_3_layout.html.twig), notice where I've inserted the <strong> and </strong> tags:
{% block form_label -%}
{% if label is not same as(false) -%}
{%- if compound is defined and compound -%}
{%- set element = 'legend' -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
{%- else -%}
{%- set label_attr = label_attr|merge({for: id}) -%}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif -%}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}><strong>{{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }}</strong>{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %}</{{ element|default('label') }}>
{%- else -%}
{%- if errors|length > 0 -%}
<div id="{{ id }}_errors" class="mb-2">
{{- form_errors(form) -}}
</div>
{%- endif -%}
{%- endif -%}
{%- endblock form_label %}
You can try the above by putting it in the actual twig view and putting this statement above it:
{% form_theme form _self %}
Extra (for a checbkox): To achieve this for a checkbox you will need to override the label template, pull out the block for
{% block checkbox_radio_label -%} from bootstrap_4_layout.html.twig or bootstrap_3_layout.html.twig and then incorporate this into your own theme.
Extra extra (for a checkbox): If you also need to customise the widget, pull out the block for {% block checkbox_widget -%} i.e. remove the label rendering from within it (yes, for some internal reason the widget generates the label as well) and customise the way you want it to be. This way even calling form_label on a checkbox will output the label (otherwise form_label will not output anything)
Look here : http://symfony.com/doc/current/reference/forms/types/choice.html#select-tag-checkboxes-or-radio-buttons
You can put the parameter expanded to true and multiple to false in your formType for have radio buttons in your html

Twig - Symfony radio expanded not rendered correctly

I have a form twig template with helpers and form blocks which I want to use to automatically style my form in the way Zurb Foundations expects.
It seems to be working well mostly but I have run into an issue with choice expanded (radio buttons) as you can see below.
Here is the generate markup:
<div class="large-12 columns">
<input type="radio" id="user_gender_0" name="user[gender]" required="required" class="" value="male"> <label class="is-required">Male<input type="radio" id="user_gender_1" name="user[gender]" required="required" class="" value="female"> <label class="is-required">Female</label></label>
</div>
For some reason the label for the "Male" option is wrapping the "Female" option and when corrected in inspect element it's fine.
Here is my twig template where I override blocks:
{#
############# Radio #############
#}
{%- block radio_widget -%}
<input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
{%- endblock radio_widget -%}
{#
############# Labels #############
#}
{%- block form_label -%}
{% if label is not sameas(false) -%}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' is-required')|trim}) %}
{%- endif %}
{% if errors|length > 0 -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' error')|trim}) %}
{% endif %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}
{%- endif -%}
{%- endblock form_label -%}
{%- block button_label -%}{%- endblock -%}
Updated info, the form type option:
->add('gender', 'choice', [
'constraints' => new NotBlank(),
'choices' => Profile::getGenderTypes(),
'expanded' => true,
'multiple' => false,
'mapped' => false,
'attr' => [
'data-user-form' => 'gender'
]
])
Can anyone suggest a better layout to match Foundation 5 Forms.
Kindest Regards
Nathan
In this line
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}
You didn't close the label tag. That's why the Male label is wrapping the Female option.
Solution
Add </label> at the end.
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>

Categories