Skip to content

Commit e31f7c8

Browse files
committedApr 13, 2013
[Form] Implemented support for buttons
1 parent 4ec6343 commit e31f7c8

23 files changed

+1993
-201
lines changed
 

‎Button.php

+412
Large diffs are not rendered by default.

‎ButtonBuilder.php

+823
Large diffs are not rendered by default.

‎ButtonTypeInterface.php

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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;
13+
14+
/**
15+
* A type that should be converted into a {@link Button} instance.
16+
*
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
interface ButtonTypeInterface extends FormTypeInterface
20+
{
21+
}

‎ClickableInterface.php

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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;
13+
14+
/**
15+
* A clickable form element.
16+
*
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
interface ClickableInterface
20+
{
21+
/**
22+
* Returns whether this element was clicked.
23+
*
24+
* @return Boolean Whether this element was clicked.
25+
*/
26+
public function isClicked();
27+
}

‎Extension/Core/CoreExtension.php

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ protected function loadTypes()
5050
new Type\TimezoneType(),
5151
new Type\UrlType(),
5252
new Type\FileType(),
53+
new Type\ButtonType(),
54+
new Type\SubmitType(),
55+
new Type\ResetType(),
5356
);
5457
}
5558
}

‎Extension/Core/Type/BaseType.php

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
use Symfony\Component\Form\AbstractType;
15+
use Symfony\Component\Form\FormBuilderInterface;
16+
use Symfony\Component\Form\FormInterface;
17+
use Symfony\Component\Form\FormView;
18+
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
19+
20+
/**
21+
* Encapsulates common logic of {@link FormType} and {@link ButtonType}.
22+
*
23+
* This type does not appear in the form's type inheritance chain and as such
24+
* cannot be extended (via {@link FormTypeExtension}s) nor themed.
25+
*
26+
* @author Bernhard Schussek <bschussek@gmail.com>
27+
*/
28+
abstract class BaseType extends AbstractType
29+
{
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public function buildForm(FormBuilderInterface $builder, array $options)
34+
{
35+
$builder->setDisabled($options['disabled']);
36+
}
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
public function buildView(FormView $view, FormInterface $form, array $options)
42+
{
43+
/* @var \Symfony\Component\Form\ClickableInterface $form */
44+
45+
$name = $form->getName();
46+
$blockName = $options['block_name'] ?: $form->getName();
47+
$translationDomain = $options['translation_domain'];
48+
49+
if ($view->parent) {
50+
if ('' !== ($parentFullName = $view->parent->vars['full_name'])) {
51+
$id = sprintf('%s_%s', $view->parent->vars['id'], $name);
52+
$fullName = sprintf('%s[%s]', $parentFullName, $name);
53+
$uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName);
54+
} else {
55+
$id = $name;
56+
$fullName = $name;
57+
$uniqueBlockPrefix = '_'.$blockName;
58+
}
59+
60+
if (!$translationDomain) {
61+
$translationDomain = $view->parent->vars['translation_domain'];
62+
}
63+
} else {
64+
$id = $name;
65+
$fullName = $name;
66+
$uniqueBlockPrefix = '_'.$blockName;
67+
68+
// Strip leading underscores and digits. These are allowed in
69+
// form names, but not in HTML4 ID attributes.
70+
// http://www.w3.org/TR/html401/struct/global.html#adef-id
71+
$id = ltrim($id, '_0123456789');
72+
}
73+
74+
$blockPrefixes = array();
75+
for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) {
76+
array_unshift($blockPrefixes, $type->getName());
77+
}
78+
$blockPrefixes[] = $uniqueBlockPrefix;
79+
80+
if (!$translationDomain) {
81+
$translationDomain = 'messages';
82+
}
83+
84+
$view->vars = array_replace($view->vars, array(
85+
'form' => $view,
86+
'id' => $id,
87+
'name' => $name,
88+
'full_name' => $fullName,
89+
'disabled' => $form->isDisabled(),
90+
'label' => $options['label'],
91+
'multipart' => false,
92+
'attr' => $options['attr'],
93+
'block_prefixes' => $blockPrefixes,
94+
'unique_block_prefix' => $uniqueBlockPrefix,
95+
'translation_domain' => $translationDomain,
96+
// Using the block name here speeds up performance in collection
97+
// forms, where each entry has the same full block name.
98+
// Including the type is important too, because if rows of a
99+
// collection form have different types (dynamically), they should
100+
// be rendered differently.
101+
// https://github.com/symfony/symfony/issues/5038
102+
'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(),
103+
));
104+
}
105+
106+
/**
107+
* {@inheritdoc}
108+
*/
109+
public function setDefaultOptions(OptionsResolverInterface $resolver)
110+
{
111+
$resolver->setDefaults(array(
112+
'block_name' => null,
113+
'disabled' => false,
114+
'label' => null,
115+
'attr' => array(),
116+
'translation_domain' => null,
117+
));
118+
119+
$resolver->setAllowedTypes(array(
120+
'attr' => 'array',
121+
));
122+
}
123+
}

‎Extension/Core/Type/ButtonType.php

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
use Symfony\Component\Form\ButtonTypeInterface;
15+
16+
/**
17+
* A form button.
18+
*
19+
* @author Bernhard Schussek <bschussek@gmail.com>
20+
*/
21+
class ButtonType extends BaseType implements ButtonTypeInterface
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function getParent()
27+
{
28+
return null;
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function getName()
35+
{
36+
return 'button';
37+
}
38+
}

‎Extension/Core/Type/FormType.php

+18-73
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\Form\Extension\Core\Type;
1313

14-
use Symfony\Component\Form\AbstractType;
1514
use Symfony\Component\Form\FormBuilderInterface;
1615
use Symfony\Component\Form\FormInterface;
1716
use Symfony\Component\Form\FormView;
@@ -23,7 +22,7 @@
2322
use Symfony\Component\PropertyAccess\PropertyAccess;
2423
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
2524

26-
class FormType extends AbstractType
25+
class FormType extends BaseType
2726
{
2827
/**
2928
* @var PropertyAccessorInterface
@@ -40,9 +39,10 @@ public function __construct(PropertyAccessorInterface $propertyAccessor = null)
4039
*/
4140
public function buildForm(FormBuilderInterface $builder, array $options)
4241
{
42+
parent::buildForm($builder, $options);
43+
4344
$builder
4445
->setRequired($options['required'])
45-
->setDisabled($options['disabled'])
4646
->setErrorBubbling($options['error_bubbling'])
4747
->setEmptyData($options['empty_data'])
4848
->setPropertyPath($options['property_path'])
@@ -65,85 +65,34 @@ public function buildForm(FormBuilderInterface $builder, array $options)
6565
*/
6666
public function buildView(FormView $view, FormInterface $form, array $options)
6767
{
68+
parent::buildView($view, $form, $options);
69+
6870
$name = $form->getName();
69-
$blockName = $options['block_name'] ?: $form->getName();
7071
$readOnly = $options['read_only'];
71-
$translationDomain = $options['translation_domain'];
7272

7373
if ($view->parent) {
7474
if ('' === $name) {
7575
throw new Exception('Form node with empty name can be used only as root form node.');
7676
}
7777

78-
if ('' !== ($parentFullName = $view->parent->vars['full_name'])) {
79-
$id = sprintf('%s_%s', $view->parent->vars['id'], $name);
80-
$fullName = sprintf('%s[%s]', $parentFullName, $name);
81-
$uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName);
82-
} else {
83-
$id = $name;
84-
$fullName = $name;
85-
$uniqueBlockPrefix = '_'.$blockName;
86-
}
87-
8878
// Complex fields are read-only if they themselves or their parents are.
8979
if (!$readOnly) {
9080
$readOnly = $view->parent->vars['read_only'];
9181
}
92-
93-
if (!$translationDomain) {
94-
$translationDomain = $view->parent->vars['translation_domain'];
95-
}
96-
} else {
97-
$id = $name;
98-
$fullName = $name;
99-
$uniqueBlockPrefix = '_'.$blockName;
100-
101-
// Strip leading underscores and digits. These are allowed in
102-
// form names, but not in HTML4 ID attributes.
103-
// http://www.w3.org/TR/html401/struct/global.html#adef-id
104-
$id = ltrim($id, '_0123456789');
105-
}
106-
107-
$blockPrefixes = array();
108-
for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) {
109-
array_unshift($blockPrefixes, $type->getName());
110-
}
111-
$blockPrefixes[] = $uniqueBlockPrefix;
112-
113-
if (!$translationDomain) {
114-
$translationDomain = 'messages';
11582
}
11683

11784
$view->vars = array_replace($view->vars, array(
118-
'form' => $view,
119-
'id' => $id,
120-
'name' => $name,
121-
'full_name' => $fullName,
122-
'read_only' => $readOnly,
123-
'errors' => $form->getErrors(),
124-
'valid' => $form->isBound() ? $form->isValid() : true,
125-
'value' => $form->getViewData(),
126-
'data' => $form->getNormData(),
127-
'disabled' => $form->isDisabled(),
128-
'required' => $form->isRequired(),
129-
'max_length' => $options['max_length'],
130-
'pattern' => $options['pattern'],
131-
'size' => null,
132-
'label' => $options['label'],
133-
'multipart' => false,
134-
'attr' => $options['attr'],
135-
'label_attr' => $options['label_attr'],
136-
'compound' => $form->getConfig()->getCompound(),
137-
'block_prefixes' => $blockPrefixes,
138-
'unique_block_prefix' => $uniqueBlockPrefix,
139-
'translation_domain' => $translationDomain,
140-
// Using the block name here speeds up performance in collection
141-
// forms, where each entry has the same full block name.
142-
// Including the type is important too, because if rows of a
143-
// collection form have different types (dynamically), they should
144-
// be rendered differently.
145-
// https://github.com/symfony/symfony/issues/5038
146-
'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(),
85+
'read_only' => $readOnly,
86+
'errors' => $form->getErrors(),
87+
'valid' => $form->isBound() ? $form->isValid() : true,
88+
'value' => $form->getViewData(),
89+
'data' => $form->getNormData(),
90+
'required' => $form->isRequired(),
91+
'max_length' => $options['max_length'],
92+
'pattern' => $options['pattern'],
93+
'size' => null,
94+
'label_attr' => $options['label_attr'],
95+
'compound' => $form->getConfig()->getCompound(),
14796
));
14897
}
14998

@@ -169,6 +118,8 @@ public function finishView(FormView $view, FormInterface $form, array $options)
169118
*/
170119
public function setDefaultOptions(OptionsResolverInterface $resolver)
171120
{
121+
parent::setDefaultOptions($resolver);
122+
172123
// Derive "data_class" option from passed "data" object
173124
$dataClass = function (Options $options) {
174125
return isset($options['data']) && is_object($options['data']) ? get_class($options['data']) : null;
@@ -202,29 +153,23 @@ public function setDefaultOptions(OptionsResolverInterface $resolver)
202153
));
203154

204155
$resolver->setDefaults(array(
205-
'block_name' => null,
206156
'data_class' => $dataClass,
207157
'empty_data' => $emptyData,
208158
'trim' => true,
209159
'required' => true,
210160
'read_only' => false,
211-
'disabled' => false,
212161
'max_length' => null,
213162
'pattern' => null,
214163
'property_path' => null,
215164
'mapped' => true,
216165
'by_reference' => true,
217166
'error_bubbling' => $errorBubbling,
218-
'label' => null,
219-
'attr' => array(),
220167
'label_attr' => array(),
221168
'virtual' => false,
222169
'compound' => true,
223-
'translation_domain' => null,
224170
));
225171

226172
$resolver->setAllowedTypes(array(
227-
'attr' => 'array',
228173
'label_attr' => 'array',
229174
));
230175
}

‎Extension/Core/Type/ResetType.php

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
use Symfony\Component\Form\AbstractType;
15+
use Symfony\Component\Form\ButtonTypeInterface;
16+
17+
/**
18+
* A reset button.
19+
*
20+
* @author Bernhard Schussek <bschussek@gmail.com>
21+
*/
22+
class ResetType extends AbstractType implements ButtonTypeInterface
23+
{
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function getParent()
28+
{
29+
return 'button';
30+
}
31+
32+
/**
33+
* {@inheritdoc}
34+
*/
35+
public function getName()
36+
{
37+
return 'reset';
38+
}
39+
}

‎Extension/Core/Type/SubmitType.php

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
use Symfony\Component\Form\AbstractType;
15+
use Symfony\Component\Form\FormInterface;
16+
use Symfony\Component\Form\FormView;
17+
use Symfony\Component\Form\SubmitButtonTypeInterface;
18+
19+
/**
20+
* A submit button.
21+
*
22+
* @author Bernhard Schussek <bschussek@gmail.com>
23+
*/
24+
class SubmitType extends AbstractType implements SubmitButtonTypeInterface
25+
{
26+
public function buildView(FormView $view, FormInterface $form, array $options)
27+
{
28+
$view->vars['clicked'] = $form->isClicked();
29+
}
30+
31+
/**
32+
* {@inheritdoc}
33+
*/
34+
public function getParent()
35+
{
36+
return 'button';
37+
}
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function getName()
43+
{
44+
return 'submit';
45+
}
46+
}

‎Extension/Validator/Type/FormTypeValidatorExtension.php

+6-14
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,9 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5353
*/
5454
public function setDefaultOptions(OptionsResolverInterface $resolver)
5555
{
56-
// Make sure that validation groups end up as null, closure or array
57-
$validationGroupsNormalizer = function (Options $options, $groups) {
58-
if (empty($groups)) {
59-
return null;
60-
}
61-
62-
if (is_callable($groups)) {
63-
return $groups;
64-
}
65-
66-
return (array) $groups;
56+
// BC clause
57+
$constraints = function (Options $options) {
58+
return $options['validation_constraint'];
6759
};
6860

6961
// Constraint should always be converted to an array
@@ -73,8 +65,9 @@ public function setDefaultOptions(OptionsResolverInterface $resolver)
7365

7466
$resolver->setDefaults(array(
7567
'error_mapping' => array(),
76-
'validation_groups' => null,
77-
'constraints' => null,
68+
// "validation_constraint" is deprecated. Use "constraints".
69+
'validation_constraint' => null,
70+
'constraints' => $constraints,
7871
'cascade_validation' => false,
7972
'invalid_message' => 'This value is not valid.',
8073
'invalid_message_parameters' => array(),
@@ -83,7 +76,6 @@ public function setDefaultOptions(OptionsResolverInterface $resolver)
8376
));
8477

8578
$resolver->setNormalizers(array(
86-
'validation_groups' => $validationGroupsNormalizer,
8779
'constraints' => $constraintsNormalizer,
8880
));
8981
}

‎FormInterface.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ public function getExtraData();
150150
public function getConfig();
151151

152152
/**
153-
* Returns whether the field is bound.
153+
* Returns whether the form is submitted.
154154
*
155-
* @return Boolean true if the form is bound to input values, false otherwise
155+
* @return Boolean true if the form is submitted, false otherwise
156156
*/
157157
public function isBound();
158158

‎ResolvedFormType.php

+41-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function createBuilder(FormFactoryInterface $factory, $name, array $optio
111111
// Should be decoupled from the specific option at some point
112112
$dataClass = isset($options['data_class']) ? $options['data_class'] : null;
113113

114-
$builder = new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options);
114+
$builder = $this->newBuilder($name, $dataClass, $factory, $options);
115115
$builder->setType($this);
116116
$builder->setParent($parent);
117117

@@ -127,7 +127,7 @@ public function createView(FormInterface $form, FormView $parent = null)
127127
{
128128
$options = $form->getConfig()->getOptions();
129129

130-
$view = new FormView($parent);
130+
$view = $this->newView($parent);
131131

132132
$this->buildView($view, $form, $options);
133133

@@ -243,4 +243,43 @@ public function getOptionsResolver()
243243

244244
return $this->optionsResolver;
245245
}
246+
247+
/**
248+
* Creates a new builder instance.
249+
*
250+
* Override this method if you want to customize the builder class.
251+
*
252+
* @param string $name The name of the builder.
253+
* @param string $dataClass The data class.
254+
* @param FormFactoryInterface $factory The current form factory.
255+
* @param array $options The builder options.
256+
*
257+
* @return FormBuilderInterface The new builder instance.
258+
*/
259+
protected function newBuilder($name, $dataClass, FormFactoryInterface $factory, array $options)
260+
{
261+
if ($this->innerType instanceof ButtonTypeInterface) {
262+
return new ButtonBuilder($name, $options);
263+
}
264+
265+
if ($this->innerType instanceof SubmitButtonTypeInterface) {
266+
return new SubmitButtonBuilder($name, $options);
267+
}
268+
269+
return new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options);
270+
}
271+
272+
/**
273+
* Creates a new view instance.
274+
*
275+
* Override this method if you want to customize the view class.
276+
*
277+
* @param FormView|null $parent The parent view, if available.
278+
*
279+
* @return FormView A new view instance.
280+
*/
281+
protected function newView(FormView $parent = null)
282+
{
283+
return new FormView($parent);
284+
}
246285
}

‎SubmitButton.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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;
13+
14+
/**
15+
* A button that submits the form.
16+
*
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
class SubmitButton extends Button implements ClickableInterface
20+
{
21+
/**
22+
* @var Boolean
23+
*/
24+
private $clicked = false;
25+
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function isClicked()
30+
{
31+
return $this->clicked;
32+
}
33+
34+
/**
35+
* Binds data to the button.
36+
*
37+
* @param null|string $submittedData The data
38+
*
39+
* @return SubmitButton The button instance
40+
*
41+
* @throws Exception\AlreadyBoundException If the form has already been bound.
42+
*/
43+
public function bind($submittedData)
44+
{
45+
parent::bind($submittedData);
46+
47+
$this->clicked = null !== $submittedData;
48+
49+
return $this;
50+
}
51+
}

‎SubmitButtonBuilder.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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;
13+
14+
/**
15+
* A builder for {@link SubmitButton} instances.
16+
*
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
class SubmitButtonBuilder extends ButtonBuilder
20+
{
21+
/**
22+
* Creates the button.
23+
*
24+
* @return Button The button
25+
*/
26+
public function getForm()
27+
{
28+
return new SubmitButton($this->getFormConfig());
29+
}
30+
}

‎SubmitButtonTypeInterface.php

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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;
13+
14+
/**
15+
* A type that should be converted into a {@link SubmitButton} instance.
16+
*
17+
* @author Bernhard Schussek <bschussek@gmail.com>
18+
*/
19+
interface SubmitButtonTypeInterface extends FormTypeInterface
20+
{
21+
}

‎Tests/AbstractDivLayoutTest.php

+16
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ public function testRepeatedRow()
8282
);
8383
}
8484

85+
public function testButtonRow()
86+
{
87+
$form = $this->factory->createNamed('name', 'button');
88+
$view = $form->createView();
89+
$html = $this->renderRow($view);
90+
91+
$this->assertMatchesXpath($html,
92+
'/div
93+
[
94+
./button[@type="button"][@name="name"]
95+
]
96+
[count(//label)=0]
97+
'
98+
);
99+
}
100+
85101
public function testRest()
86102
{
87103
$view = $this->factory->createNamedBuilder('name', 'form')

‎Tests/AbstractLayoutTest.php

+34
Original file line numberDiff line numberDiff line change
@@ -1762,4 +1762,38 @@ public function testEmptyRootFormName()
17621762
//input[@type="text"][@id="child"][@name="child"]'
17631763
, 2);
17641764
}
1765+
1766+
public function testButton()
1767+
{
1768+
$form = $this->factory->createNamed('name', 'button');
1769+
1770+
$this->assertWidgetMatchesXpath($form->createView(), array(),
1771+
'/button[@type="button"][@name="name"]'
1772+
);
1773+
}
1774+
1775+
public function testButtonLabelIsEmpty()
1776+
{
1777+
$form = $this->factory->createNamed('name', 'button');
1778+
1779+
$this->assertSame('', $this->renderLabel($form->createView()));
1780+
}
1781+
1782+
public function testSubmit()
1783+
{
1784+
$form = $this->factory->createNamed('name', 'submit');
1785+
1786+
$this->assertWidgetMatchesXpath($form->createView(), array(),
1787+
'/button[@type="submit"][@name="name"]'
1788+
);
1789+
}
1790+
1791+
public function testReset()
1792+
{
1793+
$form = $this->factory->createNamed('name', 'reset');
1794+
1795+
$this->assertWidgetMatchesXpath($form->createView(), array(),
1796+
'/button[@type="reset"][@name="name"]'
1797+
);
1798+
}
17651799
}

‎Tests/AbstractTableLayoutTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,25 @@ public function testRepeatedRowWithErrors()
125125
);
126126
}
127127

128+
public function testButtonRow()
129+
{
130+
$form = $this->factory->createNamed('name', 'button');
131+
$view = $form->createView();
132+
$html = $this->renderRow($view);
133+
134+
$this->assertMatchesXpath($html,
135+
'/tr
136+
[
137+
./td
138+
[.=""]
139+
/following-sibling::td
140+
[./button[@type="button"][@name="name"]]
141+
]
142+
[count(//label)=0]
143+
'
144+
);
145+
}
146+
128147
public function testRest()
129148
{
130149
$view = $this->factory->createNamedBuilder('name', 'form')
+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
/**
15+
* @author Bernhard Schussek <bschussek@gmail.com>
16+
*/
17+
abstract class BaseTypeTest extends TypeTestCase
18+
{
19+
public function testPassDisabledAsOption()
20+
{
21+
$form = $this->factory->create($this->getTestedType(), null, array('disabled' => true));
22+
23+
$this->assertTrue($form->isDisabled());
24+
}
25+
26+
public function testPassIdAndNameToView()
27+
{
28+
$form = $this->factory->createNamed('name', $this->getTestedType());
29+
$view = $form->createView();
30+
31+
$this->assertEquals('name', $view->vars['id']);
32+
$this->assertEquals('name', $view->vars['name']);
33+
$this->assertEquals('name', $view->vars['full_name']);
34+
}
35+
36+
public function testStripLeadingUnderscoresAndDigitsFromId()
37+
{
38+
$form = $this->factory->createNamed('_09name', $this->getTestedType());
39+
$view = $form->createView();
40+
41+
$this->assertEquals('name', $view->vars['id']);
42+
$this->assertEquals('_09name', $view->vars['name']);
43+
$this->assertEquals('_09name', $view->vars['full_name']);
44+
}
45+
46+
public function testPassIdAndNameToViewWithParent()
47+
{
48+
$parent = $this->factory->createNamed('parent', 'form');
49+
$parent->add($this->factory->createNamed('child', $this->getTestedType()));
50+
$view = $parent->createView();
51+
52+
$this->assertEquals('parent_child', $view['child']->vars['id']);
53+
$this->assertEquals('child', $view['child']->vars['name']);
54+
$this->assertEquals('parent[child]', $view['child']->vars['full_name']);
55+
}
56+
57+
public function testPassIdAndNameToViewWithGrandParent()
58+
{
59+
$parent = $this->factory->createNamed('parent', 'form');
60+
$parent->add($this->factory->createNamed('child', 'form'));
61+
$parent['child']->add($this->factory->createNamed('grand_child', $this->getTestedType()));
62+
$view = $parent->createView();
63+
64+
$this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']);
65+
$this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']);
66+
$this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->vars['full_name']);
67+
}
68+
69+
public function testPassTranslationDomainToView()
70+
{
71+
$form = $this->factory->create($this->getTestedType(), null, array(
72+
'translation_domain' => 'domain',
73+
));
74+
$view = $form->createView();
75+
76+
$this->assertSame('domain', $view->vars['translation_domain']);
77+
}
78+
79+
public function testInheritTranslationDomainFromParent()
80+
{
81+
$parent = $this->factory->createNamed('parent', 'form', null, array(
82+
'translation_domain' => 'domain',
83+
));
84+
$child = $this->factory->createNamed('child', $this->getTestedType());
85+
$view = $parent->add($child)->createView();
86+
87+
$this->assertEquals('domain', $view['child']->vars['translation_domain']);
88+
}
89+
90+
public function testPreferOwnTranslationDomain()
91+
{
92+
$parent = $this->factory->createNamed('parent', 'form', null, array(
93+
'translation_domain' => 'parent_domain',
94+
));
95+
$child = $this->factory->createNamed('child', $this->getTestedType(), null, array(
96+
'translation_domain' => 'domain',
97+
));
98+
$view = $parent->add($child)->createView();
99+
100+
$this->assertEquals('domain', $view['child']->vars['translation_domain']);
101+
}
102+
103+
public function testDefaultTranslationDomain()
104+
{
105+
$parent = $this->factory->createNamed('parent', 'form');
106+
$child = $this->factory->createNamed('child', $this->getTestedType());
107+
$view = $parent->add($child)->createView();
108+
109+
$this->assertEquals('messages', $view['child']->vars['translation_domain']);
110+
}
111+
112+
public function testPassLabelToView()
113+
{
114+
$form = $this->factory->createNamed('__test___field', $this->getTestedType(), null, array('label' => 'My label'));
115+
$view = $form->createView();
116+
117+
$this->assertSame('My label', $view->vars['label']);
118+
}
119+
120+
public function testPassMultipartFalseToView()
121+
{
122+
$form = $this->factory->create($this->getTestedType());
123+
$view = $form->createView();
124+
125+
$this->assertFalse($view->vars['multipart']);
126+
}
127+
128+
abstract protected function getTestedType();
129+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
/**
15+
* @author Bernhard Schussek <bschussek@gmail.com>
16+
*/
17+
class ButtonTypeTest extends BaseTypeTest
18+
{
19+
public function testCreateButtonInstances()
20+
{
21+
$this->assertInstanceOf('Symfony\Component\Form\Button', $this->factory->create('button'));
22+
}
23+
24+
protected function getTestedType()
25+
{
26+
return 'button';
27+
}
28+
}

‎Tests/Extension/Core/Type/FormTypeTest.php

+12-110
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,13 @@ public function setReferenceCopy($reference)
5050
}
5151
}
5252

53-
class FormTypeTest extends TypeTestCase
53+
class FormTypeTest extends BaseTypeTest
5454
{
55+
public function testCreateFormInstances()
56+
{
57+
$this->assertInstanceOf('Symfony\Component\Form\Form', $this->factory->create('form'));
58+
}
59+
5560
public function testPassRequiredAsOption()
5661
{
5762
$form = $this->factory->create('form', null, array('required' => false));
@@ -63,13 +68,6 @@ public function testPassRequiredAsOption()
6368
$this->assertTrue($form->isRequired());
6469
}
6570

66-
public function testPassDisabledAsOption()
67-
{
68-
$form = $this->factory->create('form', null, array('disabled' => true));
69-
70-
$this->assertTrue($form->isDisabled());
71-
}
72-
7371
public function testBoundDataIsTrimmedBeforeTransforming()
7472
{
7573
$form = $this->factory->createBuilder('form')
@@ -102,49 +100,6 @@ public function testBoundDataIsNotTrimmedBeforeTransformingIfNoTrimming()
102100
$this->assertEquals('reverse[ a ]', $form->getData());
103101
}
104102

105-
public function testPassIdAndNameToView()
106-
{
107-
$form = $this->factory->createNamed('name', 'form');
108-
$view = $form->createView();
109-
110-
$this->assertEquals('name', $view->vars['id']);
111-
$this->assertEquals('name', $view->vars['name']);
112-
$this->assertEquals('name', $view->vars['full_name']);
113-
}
114-
115-
public function testStripLeadingUnderscoresAndDigitsFromId()
116-
{
117-
$form = $this->factory->createNamed('_09name', 'form');
118-
$view = $form->createView();
119-
120-
$this->assertEquals('name', $view->vars['id']);
121-
$this->assertEquals('_09name', $view->vars['name']);
122-
$this->assertEquals('_09name', $view->vars['full_name']);
123-
}
124-
125-
public function testPassIdAndNameToViewWithParent()
126-
{
127-
$parent = $this->factory->createNamed('parent', 'form');
128-
$parent->add($this->factory->createNamed('child', 'form'));
129-
$view = $parent->createView();
130-
131-
$this->assertEquals('parent_child', $view['child']->vars['id']);
132-
$this->assertEquals('child', $view['child']->vars['name']);
133-
$this->assertEquals('parent[child]', $view['child']->vars['full_name']);
134-
}
135-
136-
public function testPassIdAndNameToViewWithGrandParent()
137-
{
138-
$parent = $this->factory->createNamed('parent', 'form');
139-
$parent->add($this->factory->createNamed('child', 'form'));
140-
$parent['child']->add($this->factory->createNamed('grand_child', 'form'));
141-
$view = $parent->createView();
142-
143-
$this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']);
144-
$this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']);
145-
$this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->vars['full_name']);
146-
}
147-
148103
public function testNonReadOnlyFormWithReadOnlyParentBeingReadOnly()
149104
{
150105
$parent = $this->factory->createNamed('parent', 'form', null, array('read_only' => true));
@@ -180,57 +135,6 @@ public function testPassMaxLengthToView()
180135
$this->assertSame(10, $view->vars['max_length']);
181136
}
182137

183-
public function testPassTranslationDomainToView()
184-
{
185-
$form = $this->factory->create('form', null, array('translation_domain' => 'test'));
186-
$view = $form->createView();
187-
188-
$this->assertSame('test', $view->vars['translation_domain']);
189-
}
190-
191-
public function testNonTranslationDomainFormWithTranslationDomainParentBeingTranslationDomain()
192-
{
193-
$parent = $this->factory->createNamed('parent', 'form', null, array('translation_domain' => 'test'));
194-
$child = $this->factory->createNamed('child', 'form');
195-
$view = $parent->add($child)->createView();
196-
197-
$this->assertEquals('test', $view['child']->vars['translation_domain']);
198-
}
199-
200-
public function testTranslationDomainFormWithNonTranslationDomainParentBeingTranslationDomain()
201-
{
202-
$parent = $this->factory->createNamed('parent', 'form');
203-
$child = $this->factory->createNamed('child', 'form', null, array('translation_domain' => 'test'));
204-
$view = $parent->add($child)->createView();
205-
206-
$this->assertEquals('test', $view['child']->vars['translation_domain']);
207-
}
208-
209-
public function testNonTranslationDomainFormWithNonTranslationDomainParentBeingTranslationDomainDefault()
210-
{
211-
$parent = $this->factory->createNamed('parent', 'form');
212-
$child = $this->factory->createNamed('child', 'form');
213-
$view = $parent->add($child)->createView();
214-
215-
$this->assertEquals('messages', $view['child']->vars['translation_domain']);
216-
}
217-
218-
public function testPassLabelToView()
219-
{
220-
$form = $this->factory->createNamed('__test___field', 'form', null, array('label' => 'My label'));
221-
$view = $form->createView();
222-
223-
$this->assertSame('My label', $view->vars['label']);
224-
}
225-
226-
public function testDefaultTranslationDomain()
227-
{
228-
$form = $this->factory->create('form');
229-
$view = $form->createView();
230-
231-
$this->assertSame('messages', $view->vars['translation_domain']);
232-
}
233-
234138
public function testBindWithEmptyDataCreatesObjectIfClassAvailable()
235139
{
236140
$form = $this->factory->create('form', null, array(
@@ -404,6 +308,7 @@ public function testNameCanBeEmptyString()
404308

405309
$this->assertEquals('', $form->getName());
406310
}
311+
407312
public function testSubformDoesntCallSetters()
408313
{
409314
$author = new FormTest_AuthorWithoutRefSetter(new Author());
@@ -523,14 +428,6 @@ function ($value) use ($ref2) { // reverseTransform
523428
$this->assertSame($ref2, $author['referenceCopy']);
524429
}
525430

526-
public function testPassMultipartFalseToView()
527-
{
528-
$form = $this->factory->create('form');
529-
$view = $form->createView();
530-
531-
$this->assertFalse($view->vars['multipart']);
532-
}
533-
534431
public function testPassMultipartTrueIfAnyChildIsMultipartToView()
535432
{
536433
$form = $this->factory->create('form');
@@ -661,4 +558,9 @@ public function testPassZeroLabelToView()
661558

662559
$this->assertSame('0', $view->vars['label']);
663560
}
561+
562+
protected function getTestedType()
563+
{
564+
return 'form';
565+
}
664566
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Extension\Core\Type;
13+
14+
/**
15+
* @author Bernhard Schussek <bschussek@gmail.com>
16+
*/
17+
class SubmitTypeTest extends TypeTestCase
18+
{
19+
public function testCreateSubmitButtonInstances()
20+
{
21+
$this->assertInstanceOf('Symfony\Component\Form\SubmitButton', $this->factory->create('submit'));
22+
}
23+
24+
public function testNotClickedByDefault()
25+
{
26+
$button = $this->factory->create('submit');
27+
28+
$this->assertFalse($button->isClicked());
29+
}
30+
31+
public function testNotClickedIfBoundWithNull()
32+
{
33+
$button = $this->factory->create('submit');
34+
$button->bind(null);
35+
36+
$this->assertFalse($button->isClicked());
37+
}
38+
39+
public function testClickedIfBoundWithEmptyString()
40+
{
41+
$button = $this->factory->create('submit');
42+
$button->bind('');
43+
44+
$this->assertTrue($button->isClicked());
45+
}
46+
47+
public function testClickedIfBoundWithUnemptyString()
48+
{
49+
$button = $this->factory->create('submit');
50+
$button->bind('foo');
51+
52+
$this->assertTrue($button->isClicked());
53+
}
54+
}

0 commit comments

Comments
 (0)
Please sign in to comment.