diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig
index e236d12cb709a..e23e6f8a29d09 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig
@@ -28,7 +28,6 @@ col-sm-2
{{- form_label(form) -}}
{{- form_widget(form) -}}
- {{- form_errors(form) -}}
{##}
{%- endif -%}
@@ -40,7 +39,6 @@ col-sm-2
{{- form_label(form) -}}
{{- form_widget(form) -}}
- {{- form_errors(form) -}}
{##}
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
index 15413f1c9a0fe..12981e346232e 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
@@ -39,7 +39,41 @@
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-control is-invalid')|trim}) -%}
{% set valid = true %}
{%- endif -%}
- {{- parent() -}}
+
+ {%- if widget == 'single_text' -%}
+ {{- block('form_widget_simple') -}}
+ {%- else -%}
+ {%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) -%}
+
+
+
+
+
+ {%- if with_years %}{{ form_label(form.years) }} | {% endif -%}
+ {%- if with_months %}{{ form_label(form.months) }} | {% endif -%}
+ {%- if with_weeks %}{{ form_label(form.weeks) }} | {% endif -%}
+ {%- if with_days %}{{ form_label(form.days) }} | {% endif -%}
+ {%- if with_hours %}{{ form_label(form.hours) }} | {% endif -%}
+ {%- if with_minutes %}{{ form_label(form.minutes) }} | {% endif -%}
+ {%- if with_seconds %}{{ form_label(form.seconds) }} | {% endif -%}
+
+
+
+
+ {%- if with_years %}{{ form_widget(form.years) }} | {% endif -%}
+ {%- if with_months %}{{ form_widget(form.months) }} | {% endif -%}
+ {%- if with_weeks %}{{ form_widget(form.weeks) }} | {% endif -%}
+ {%- if with_days %}{{ form_widget(form.days) }} | {% endif -%}
+ {%- if with_hours %}{{ form_widget(form.hours) }} | {% endif -%}
+ {%- if with_minutes %}{{ form_widget(form.minutes) }} | {% endif -%}
+ {%- if with_seconds %}{{ form_widget(form.seconds) }} | {% endif -%}
+
+
+
+
+ {%- if with_invert %}{{ form_widget(form.invert) }}{% endif -%}
+
+ {%- endif -%}
{%- endblock dateinterval_widget %}
{% block percent_widget -%}
@@ -125,13 +159,28 @@
{# Labels #}
{% block form_label -%}
- {%- if compound is defined and compound -%}
- {%- set element = 'legend' -%}
- {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-legend')|trim}) -%}
- {%- else -%}
- {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' form-control-label')|trim}) -%}
+ {% 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-legend')|trim}) -%}
+ {%- else -%}
+ {%- set label_attr = label_attr|merge({for: id, class: (label_attr.class|default('') ~ ' form-control-label')|trim}) -%}
+ {%- 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({}, translation_domain) }}{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %}{{ element|default('label') }}>
{%- endif -%}
- {{- parent() -}}
{%- endblock form_label %}
{% block checkbox_radio_label -%}
@@ -169,7 +218,6 @@
<{{ element|default('div') }} class="form-group">
{{- form_label(form) -}}
{{- form_widget(form) -}}
- {{- form_errors(form) -}}
{{ element|default('div') }}>
{%- endblock form_row %}
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php
index 2833de7d91de0..23e6f141cac9d 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Tests;
+use Symfony\Component\Form\FormError;
+
/**
* Abstract class providing test cases for the Bootstrap 4 horizontal Twig form theme.
*
@@ -18,6 +20,30 @@
*/
abstract class AbstractBootstrap4HorizontalLayoutTest extends AbstractBootstrap4LayoutTest
{
+ public function testRow()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
+ $form->addError(new FormError('[trans]Error![/trans]'));
+ $view = $form->createView();
+ $html = $this->renderRow($view);
+
+ $this->assertMatchesXpath($html,
+ '/div
+ [
+ ./label[@for="name"]
+ [
+ ./div[
+ ./ul
+ [./li[.="[trans]Error![/trans]"]]
+ [count(./li)=1]
+ ]
+ ]
+ /following-sibling::div[./input[@id="name"]]
+ ]
+'
+ );
+ }
+
public function testLabelOnForm()
{
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\DateType');
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
index 88ebd261b2a44..fdaa07e1c15bc 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
@@ -20,6 +20,30 @@
*/
abstract class AbstractBootstrap4LayoutTest extends AbstractBootstrap3LayoutTest
{
+ public function testRow()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
+ $form->addError(new FormError('[trans]Error![/trans]'));
+ $view = $form->createView();
+ $html = $this->renderRow($view);
+
+ $this->assertMatchesXpath($html,
+ '/div
+ [
+ ./label[@for="name"]
+ [
+ ./div[
+ ./ul
+ [./li[.="[trans]Error![/trans]"]]
+ [count(./li)=1]
+ ]
+ ]
+ /following-sibling::input[@id="name"]
+ ]
+'
+ );
+ }
+
public function testLabelOnForm()
{
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\DateType');