Skip to content

Commit 7286f94

Browse files
committed
feature #21751 Bootstrap4 support for Twig form theme (hiddewie, javiereguiluz)
This PR was merged into the 3.4 branch. Discussion ---------- Bootstrap4 support for Twig form theme **This PR is a followup from #19648. That PR was closed because GitHub thought my branch contained no commits after a force push...** | Q | A | | --- | --- | | Branch? | master | | Bug fix? | no | | New feature? | yes | | BC breaks? | no | | Deprecations? | no | | Tests pass? | yes | | Fixed tickets | #16289 | | License | MIT | | Doc PR | - | I have made a port of the Twig form theming code for Bootstrap 3 to the α-5 version of Bootstrap 4. - The (inheritance) structure of the form theming files has changed because a number of blocks are the same between BS 3 and 4. They have been migrated to `bootstrap_base_layout.html.twig`. The new tree is as follows: ``` bootstrap_base_layout.html.twig |-- bootstrap_3_layout.html.twig | `-- bootstrap_3_horizontal_layout.html.twig `-- bootstrap_4_layout.html.twig `-- bootstrap_4_horizontal_layout.html.twig ``` - Any occurances of `.form-horizontal` have been removed from the BS 4 code. - Checkboxes and radio buttons have been stacked using the `.form-check`, `.form-check-label` and `.form-check-input` classes. There is now no distinction between checkboxes and radio buttons in the markdown. - All layout tests have been added and updated for BS4. The inheritance tree is as follows: ``` AbstractLayoutTest `-- AbstractBootstrap3LayoutTest |-- AbstractBootstrap3HorizontalLayoutTest `-- AbstractBootstrap4LayoutTest `-- AbstractBootstrap4HorizontalLayoutTest ``` All tests pass. The classes `FormExtensionBootstrap4LayoutTest` and `FormExtensionBootstrap4HorizontalLayoutTest` have been created similarly to the BS 3 versions. - ~~The label coloring on an validation is not correct. I've made an issue (twbs/bootstrap#20535) of the problem.~~ - No [custom form elements](http://v4-alpha.getbootstrap.com/components/forms/#custom-forms) have been used. - A docs PR can be created if this PR is accepted. - The new code might have to be updated if large changes occur in the BS 4 α. Screenshot of BS3 and 4 comparison for the same form: ![1](https://cloud.githubusercontent.com/assets/1073881/17732594/dfcb50d6-6472-11e6-8e96-c46987809322.PNG) Commits ------- f12e5887ff Removed unneeded wrapping quotes around a Twig key 709f134dc8 Removed unneeded wrapping quotes around a Twig key 4222d54a53 Initial commit for Bootstrap 4 form theme, based on Bootstrap 3 form theme
2 parents e924230 + daac882 commit 7286f94

File tree

2 files changed

+1159
-0
lines changed

2 files changed

+1159
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Tests;
13+
14+
/**
15+
* Abstract class providing test cases for the Bootstrap 4 horizontal Twig form theme.
16+
*
17+
* @author Hidde Wieringa <[email protected]>
18+
*/
19+
abstract class AbstractBootstrap4HorizontalLayoutTest extends AbstractBootstrap4LayoutTest
20+
{
21+
public function testLabelOnForm()
22+
{
23+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\DateType');
24+
$view = $form->createView();
25+
$this->renderWidget($view, array('label' => 'foo'));
26+
$html = $this->renderLabel($view);
27+
28+
$this->assertMatchesXpath($html,
29+
'/label
30+
[@class="col-form-label col-sm-2 form-control-label required"]
31+
[.="[trans]Name[/trans]"]
32+
'
33+
);
34+
}
35+
36+
public function testLabelDoesNotRenderFieldAttributes()
37+
{
38+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
39+
$html = $this->renderLabel($form->createView(), null, array(
40+
'attr' => array(
41+
'class' => 'my&class',
42+
),
43+
));
44+
45+
$this->assertMatchesXpath($html,
46+
'/label
47+
[@for="name"]
48+
[@class="col-form-label col-sm-2 form-control-label required"]
49+
'
50+
);
51+
}
52+
53+
public function testLabelWithCustomAttributesPassedDirectly()
54+
{
55+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
56+
$html = $this->renderLabel($form->createView(), null, array(
57+
'label_attr' => array(
58+
'class' => 'my&class',
59+
),
60+
));
61+
62+
$this->assertMatchesXpath($html,
63+
'/label
64+
[@for="name"]
65+
[@class="my&class col-form-label col-sm-2 form-control-label required"]
66+
'
67+
);
68+
}
69+
70+
public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
71+
{
72+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType');
73+
$html = $this->renderLabel($form->createView(), 'Custom label', array(
74+
'label_attr' => array(
75+
'class' => 'my&class',
76+
),
77+
));
78+
79+
$this->assertMatchesXpath($html,
80+
'/label
81+
[@for="name"]
82+
[@class="my&class col-form-label col-sm-2 form-control-label required"]
83+
[.="[trans]Custom label[/trans]"]
84+
'
85+
);
86+
}
87+
88+
public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly()
89+
{
90+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, array(
91+
'label' => 'Custom label',
92+
));
93+
$html = $this->renderLabel($form->createView(), null, array(
94+
'label_attr' => array(
95+
'class' => 'my&class',
96+
),
97+
));
98+
99+
$this->assertMatchesXpath($html,
100+
'/label
101+
[@for="name"]
102+
[@class="my&class col-form-label col-sm-2 form-control-label required"]
103+
[.="[trans]Custom label[/trans]"]
104+
'
105+
);
106+
}
107+
108+
public function testLegendOnExpandedType()
109+
{
110+
$form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', null, array(
111+
'label' => 'Custom label',
112+
'expanded' => true,
113+
'choices' => array('Choice&A' => '&a', 'Choice&B' => '&b'),
114+
));
115+
$view = $form->createView();
116+
$this->renderWidget($view);
117+
$html = $this->renderLabel($view);
118+
119+
$this->assertMatchesXpath($html,
120+
'/legend
121+
[@class="col-sm-2 col-form-legend form-control-label required"]
122+
[.="[trans]Custom label[/trans]"]
123+
'
124+
);
125+
}
126+
127+
public function testStartTag()
128+
{
129+
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
130+
'method' => 'get',
131+
'action' => 'http://example.com/directory',
132+
));
133+
134+
$html = $this->renderStart($form->createView());
135+
136+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory">', $html);
137+
}
138+
139+
public function testStartTagWithOverriddenVars()
140+
{
141+
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
142+
'method' => 'put',
143+
'action' => 'http://example.com/directory',
144+
));
145+
146+
$html = $this->renderStart($form->createView(), array(
147+
'method' => 'post',
148+
'action' => 'http://foo.com/directory',
149+
));
150+
151+
$this->assertSame('<form name="form" method="post" action="http://foo.com/directory">', $html);
152+
}
153+
154+
public function testStartTagForMultipartForm()
155+
{
156+
$form = $this->factory->createBuilder('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
157+
'method' => 'get',
158+
'action' => 'http://example.com/directory',
159+
))
160+
->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType')
161+
->getForm();
162+
163+
$html = $this->renderStart($form->createView());
164+
165+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
166+
}
167+
168+
public function testStartTagWithExtraAttributes()
169+
{
170+
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
171+
'method' => 'get',
172+
'action' => 'http://example.com/directory',
173+
));
174+
175+
$html = $this->renderStart($form->createView(), array(
176+
'attr' => array('class' => 'foobar'),
177+
));
178+
179+
$this->assertSame('<form name="form" method="get" action="http://example.com/directory" class="foobar">', $html);
180+
}
181+
}

0 commit comments

Comments
 (0)