diff --git a/UPGRADE-2.3.md b/UPGRADE-2.3.md new file mode 100644 index 0000000000000..5e83e86ac24a5 --- /dev/null +++ b/UPGRADE-2.3.md @@ -0,0 +1,37 @@ +UPGRADE FROM 2.2 to 2.3 +======================= + +### Form + + * Although this was not officially supported nor documented, it was possible to + set the option "validation_groups" to false, resulting in the group "Default" + being validated. Now, if you set "validation_groups" to false, the validation + of a form will be skipped (except for a few integrity checks on the form). + + If you want to validate a form in group "Default", you should either + explicitly set "validation_groups" to "Default" or alternatively set it to + null. + + Before: + + ``` + // equivalent notations for validating in group "Default" + "validation_groups" => null + "validation_groups" => "Default" + "validation_groups" => false + + // notation for skipping validation + "validation_groups" => array() + ``` + + After: + + ``` + // equivalent notations for validating in group "Default" + "validation_groups" => null + "validation_groups" => "Default" + + // equivalent notations for skipping validation + "validation_groups" => false + "validation_groups" => array() + ``` diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 3ab047c494ad8..3fe56557467c3 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -218,6 +218,29 @@ {% endspaceless %} {% endblock email_widget %} +{% block button_widget %} +{% spaceless %} + {% if label is empty %} + {% set label = name|humanize %} + {% endif %} + +{% endspaceless %} +{% endblock button_widget %} + +{% block submit_widget %} +{% spaceless %} + {% set type = type|default('submit') %} + {{ block('button_widget') }} +{% endspaceless %} +{% endblock submit_widget %} + +{% block reset_widget %} +{% spaceless %} + {% set type = type|default('reset') %} + {{ block('button_widget') }} +{% endspaceless %} +{% endblock reset_widget %} + {# Labels #} {% block form_label %} @@ -237,6 +260,8 @@ {% endspaceless %} {% endblock form_label %} +{% block button_label %}{% endblock %} + {# Rows #} {% block repeated_row %} @@ -259,6 +284,14 @@ {% endspaceless %} {% endblock form_row %} +{% block button_row %} +{% spaceless %} +
+ {{ form_widget(form) }} +
+{% endspaceless %} +{% endblock button_row %} + {% block hidden_row %} {{ form_widget(form) }} {% endblock hidden_row %} @@ -317,14 +350,9 @@ {% endspaceless %} {% endblock widget_container_attributes %} -{# Deprecated in Symfony 2.1, to be removed in 2.3 #} - -{% block generic_label %}{{ block('form_label') }}{% endblock %} -{% block widget_choice_options %}{{ block('choice_widget_options') }}{% endblock %} -{% block field_widget %}{{ block('form_widget_simple') }}{% endblock %} -{% block field_label %}{{ block('form_label') }}{% endblock %} -{% block field_row %}{{ block('form_row') }}{% endblock %} -{% block field_enctype %}{{ block('form_enctype') }}{% endblock %} -{% block field_errors %}{{ block('form_errors') }}{% endblock %} -{% block field_rest %}{{ block('form_rest') }}{% endblock %} -{% block field_rows %}{{ block('form_rows') }}{% endblock %} +{% block button_attributes %} +{% spaceless %} + id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %} + {% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %} +{% endspaceless %} +{% endblock button_attributes %} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig index 63bd7d2787137..1f339763c7258 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig @@ -14,6 +14,17 @@ {% endspaceless %} {% endblock form_row %} +{% block button_row %} +{% spaceless %} + + + + {{ form_widget(form) }} + + +{% endspaceless %} +{% endblock button_row %} + {% block hidden_row %} {% spaceless %} diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml index d614e4dc50757..17e459b9ea464 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml @@ -140,6 +140,15 @@ + + + + + + + + + @@ -154,5 +163,8 @@ + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php new file mode 100644 index 0000000000000..63d16bd357dc6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_attributes.html.php @@ -0,0 +1,6 @@ +id="escape($id) ?>" +name="escape($full_name) ?>" +disabled="disabled" + $v): ?> + escape($k), $view->escape($v)) ?> + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_label.html.php new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_row.html.php new file mode 100644 index 0000000000000..b52e92984533d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_row.html.php @@ -0,0 +1,3 @@ +
+ widget($form) ?> +
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php new file mode 100644 index 0000000000000..4f789273822ba --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php @@ -0,0 +1,4 @@ +humanize($name); } ?> + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php deleted file mode 100644 index 2e107a7b26be0..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_enctype.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_enctype') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php deleted file mode 100644 index ffed7cf43cad0..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_errors.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_errors') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php deleted file mode 100644 index 0b59dfb301bc5..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_label.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_label') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php deleted file mode 100644 index ee1bc31333ed1..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rest.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_rest') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php deleted file mode 100644 index 971d8ac5a9d76..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_row.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_row') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php deleted file mode 100644 index d4af23d712320..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_rows.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_rows') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php deleted file mode 100644 index 91e5ef1e1c144..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_widget.html.php +++ /dev/null @@ -1 +0,0 @@ -block($form, 'form_widget_simple') ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php new file mode 100644 index 0000000000000..1575e8292801e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php @@ -0,0 +1 @@ +block($form, 'button_widget', array('type' => isset($type) ? $type : 'reset')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php new file mode 100644 index 0000000000000..d42bb2a78ffe9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php @@ -0,0 +1 @@ +block($form, 'button_widget', array('type' => isset($type) ? $type : 'submit')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/button_row.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/button_row.html.php new file mode 100644 index 0000000000000..ef4d22b975081 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/button_row.html.php @@ -0,0 +1,6 @@ + + + + widget($form) ?> + + diff --git a/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php b/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php index 6d241cad5725a..34a2aece5edb5 100644 --- a/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/ArrayNodeTest.php @@ -25,7 +25,7 @@ public function testNormalizeThrowsExceptionWhenFalseIsNotAllowed() } /** - * @expectedException Symfony\Component\Config\Definition\Exception\InvalidConfigurationException + * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException * @expectedExceptionMessage Unrecognized options "foo" under "root" */ public function testExceptionThrownOnUnrecognizedChild() diff --git a/src/Symfony/Component/Form/Button.php b/src/Symfony/Component/Form/Button.php new file mode 100644 index 0000000000000..23c47755300be --- /dev/null +++ b/src/Symfony/Component/Form/Button.php @@ -0,0 +1,412 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +use Symfony\Component\Form\Exception\AlreadyBoundException; + +/** + * A form button. + * + * @author Bernhard Schussek + */ +class Button implements \IteratorAggregate, FormInterface +{ + /** + * @var FormInterface + */ + private $parent; + + /** + * @var FormConfigInterface + */ + private $config; + + /** + * @var Boolean + */ + private $bound = false; + + /** + * Creates a new button from a form configuration. + * + * @param FormConfigInterface $config The button's configuration. + */ + public function __construct(FormConfigInterface $config) + { + $this->config = $config; + } + + /** + * Unsupported method. + * + * @param mixed $offset + * + * @return Boolean Always returns false. + */ + public function offsetExists($offset) + { + return false; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param mixed $offset + * + * @throws \BadMethodCallException + */ + public function offsetGet($offset) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param mixed $offset + * @param mixed $value + * + * @throws \BadMethodCallException + */ + public function offsetSet($offset, $value) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param mixed $offset + * + * @throws \BadMethodCallException + */ + public function offsetUnset($offset) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * {@inheritdoc} + */ + public function setParent(FormInterface $parent = null) + { + $this->parent = $parent; + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return $this->parent; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param int|string|FormInterface $child + * @param null $type + * @param array $options + * + * @throws \BadMethodCallException + */ + public function add($child, $type = null, array $options = array()) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $name + * + * @throws \BadMethodCallException + */ + public function get($name) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * @param string $name + * + * @return Boolean Always returns false. + */ + public function has($name) + { + return false; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $name + * + * @throws \BadMethodCallException + */ + public function remove($name) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * {@inheritdoc} + */ + public function all() + { + return array(); + } + + /** + * {@inheritdoc} + */ + public function getErrors() + { + return array(); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $modelData + * + * @throws \BadMethodCallException + */ + public function setData($modelData) + { + throw new \BadMethodCallException('Buttons cannot have data.'); + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getData() + { + return null; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getNormData() + { + return null; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getViewData() + { + return null; + } + + /** + * Unsupported method. + * + * @return array Always returns an empty array. + */ + public function getExtraData() + { + return array(); + } + + /** + * Returns the button's configuration. + * + * @return FormConfigInterface The configuration. + */ + public function getConfig() + { + return $this->config; + } + + /** + * Returns whether the button is submitted. + * + * @return Boolean true if the button was submitted. + */ + public function isBound() + { + return $this->bound; + } + + /** + * Returns the name by which the button is identified in forms. + * + * @return string The name of the button. + */ + public function getName() + { + return $this->config->getName(); + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getPropertyPath() + { + return null; + } + + /** + * Unsupported method. + * + * @param FormError $error + * + * @throws \BadMethodCallException + */ + public function addError(FormError $error) + { + throw new \BadMethodCallException('Buttons cannot have errors.'); + } + + /** + * Unsupported method. + * + * @return Boolean Always returns true. + */ + public function isValid() + { + return true; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function isRequired() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function isDisabled() + { + return $this->config->getDisabled(); + } + + /** + * Unsupported method. + * + * @return Boolean Always returns true. + */ + public function isEmpty() + { + return true; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns true. + */ + public function isSynchronized() + { + return true; + } + + /** + * Binds data to the button. + * + * @param null|string $submittedData The data + * + * @return Button The button instance + * + * @throws Exception\AlreadyBoundException If the form has already been bound. + */ + public function bind($submittedData) + { + if ($this->bound) { + throw new AlreadyBoundException('A form can only be bound once'); + } + + $this->bound = true; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getRoot() + { + return $this->parent ? $this->parent->getRoot() : $this; + } + + /** + * {@inheritdoc} + */ + public function isRoot() + { + return null === $this->parent; + } + + /** + * {@inheritdoc} + */ + public function createView(FormView $parent = null) + { + if (null === $parent && $this->parent) { + $parent = $this->parent->createView(); + } + + return $this->config->getType()->createView($this, $parent); + } + + /** + * Unsupported method. + * + * @return integer Always returns 0. + */ + public function count() + { + return 0; + } + + /** + * Unsupported method. + * + * @return \EmptyIterator Always returns an empty iterator. + */ + public function getIterator() + { + return new \EmptyIterator(); + } +} diff --git a/src/Symfony/Component/Form/ButtonBuilder.php b/src/Symfony/Component/Form/ButtonBuilder.php new file mode 100644 index 0000000000000..9e61cbf403cfa --- /dev/null +++ b/src/Symfony/Component/Form/ButtonBuilder.php @@ -0,0 +1,750 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Form\Exception\FormException; +use Symfony\Component\Form\Exception\InvalidArgumentException; + +/** + * A builder for {@link Button} instances. + * + * @author Bernhard Schussek + */ +class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface +{ + /** + * @var Boolean + */ + protected $locked = false; + + /** + * @var Boolean + */ + private $disabled; + + /** + * @var ResolvedFormTypeInterface + */ + private $type; + + /** + * @var string + */ + private $name; + + /** + * @var array + */ + private $attributes = array(); + + /** + * @var array + */ + private $options; + + /** + * Creates a new button builder. + * + * @param string $name The name of the button. + * @param array $options The button's options. + * + * @throws FormException If the name is empty. + */ + public function __construct($name, array $options) + { + if (empty($name) && 0 != $name) { + throw new InvalidArgumentException('Buttons cannot have empty names.'); + } + + $this->name = (string) $name; + $this->options = $options; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string|integer|FormBuilderInterface $child + * @param string|FormTypeInterface $type + * @param array $options + * + * @throws \BadMethodCallException + */ + public function add($child, $type = null, array $options = array()) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $name + * @param string|FormTypeInterface $type + * @param array $options + * + * @throws \BadMethodCallException + */ + public function create($name, $type = null, array $options = array()) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $name + * + * @throws \BadMethodCallException + */ + public function get($name) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $name + * + * @throws \BadMethodCallException + */ + public function remove($name) + { + throw new \BadMethodCallException('Buttons cannot have children.'); + } + + /** + * Unsupported method. + * + * @param string $name + * + * @return Boolean Always returns false. + */ + public function has($name) + { + return false; + } + + /** + * Returns the children. + * + * @return array Always returns an empty array. + */ + public function all() + { + return array(); + } + + /** + * Creates the button. + * + * @return Button The button + */ + public function getForm() + { + return new Button($this->getFormConfig()); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param string $eventName + * @param callable $listener + * @param integer $priority + * + * @throws \BadMethodCallException + */ + public function addEventListener($eventName, $listener, $priority = 0) + { + throw new \BadMethodCallException('Buttons do not support event listeners.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param EventSubscriberInterface $subscriber + * + * @throws \BadMethodCallException + */ + public function addEventSubscriber(EventSubscriberInterface $subscriber) + { + throw new \BadMethodCallException('Buttons do not support event subscribers.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param DataTransformerInterface $viewTransformer + * @param Boolean $forcePrepend + * + * @throws \BadMethodCallException + */ + public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false) + { + throw new \BadMethodCallException('Buttons do not support data transformers.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @throws \BadMethodCallException + */ + public function resetViewTransformers() + { + throw new \BadMethodCallException('Buttons do not support data transformers.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param DataTransformerInterface $modelTransformer + * @param Boolean $forceAppend + * + * @throws \BadMethodCallException + */ + public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false) + { + throw new \BadMethodCallException('Buttons do not support data transformers.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @throws \BadMethodCallException + */ + public function resetModelTransformers() + { + throw new \BadMethodCallException('Buttons do not support data transformers.'); + } + + /** + * {@inheritdoc} + */ + public function setAttribute($name, $value) + { + $this->attributes[$name] = $value; + } + + /** + * {@inheritdoc} + */ + public function setAttributes(array $attributes) + { + $this->attributes = $attributes; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param DataMapperInterface $dataMapper + * + * @throws \BadMethodCallException + */ + public function setDataMapper(DataMapperInterface $dataMapper = null) + { + throw new \BadMethodCallException('Buttons do not support data mappers.'); + } + + /** + * Set whether the button is disabled. + * + * @param Boolean $disabled Whether the button is disabled + * + * @return ButtonBuilder The button builder. + */ + public function setDisabled($disabled) + { + $this->disabled = $disabled; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param mixed $emptyData + * + * @throws \BadMethodCallException + */ + public function setEmptyData($emptyData) + { + throw new \BadMethodCallException('Buttons do not support empty data.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $errorBubbling + * + * @throws \BadMethodCallException + */ + public function setErrorBubbling($errorBubbling) + { + throw new \BadMethodCallException('Buttons do not support error bubbling.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $required + * + * @throws \BadMethodCallException + */ + public function setRequired($required) + { + throw new \BadMethodCallException('Buttons cannot be required.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param null $propertyPath + * + * @throws \BadMethodCallException + */ + public function setPropertyPath($propertyPath) + { + throw new \BadMethodCallException('Buttons do not support property paths.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $mapped + * + * @throws \BadMethodCallException + */ + public function setMapped($mapped) + { + throw new \BadMethodCallException('Buttons do not support data mapping.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $byReference + * + * @throws \BadMethodCallException + */ + public function setByReference($byReference) + { + throw new \BadMethodCallException('Buttons do not support data mapping.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $virtual + * + * @throws \BadMethodCallException + */ + public function setVirtual($virtual) + { + throw new \BadMethodCallException('Buttons cannot be virtual.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $compound + * + * @throws \BadMethodCallException + */ + public function setCompound($compound) + { + throw new \BadMethodCallException('Buttons cannot be compound.'); + } + + /** + * Sets the type of the button. + * + * @param ResolvedFormTypeInterface $type The type of the button. + * + * @return ButtonBuilder The button builder. + */ + public function setType(ResolvedFormTypeInterface $type) + { + $this->type = $type; + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param array $data + * + * @throws \BadMethodCallException + */ + public function setData($data) + { + throw new \BadMethodCallException('Buttons do not support data.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param Boolean $locked + * + * @throws \BadMethodCallException + */ + public function setDataLocked($locked) + { + throw new \BadMethodCallException('Buttons do not support data locking.'); + } + + /** + * Unsupported method. + * + * This method should not be invoked. + * + * @param FormFactoryInterface $formFactory + * + * @return void + * + * @throws \BadMethodCallException + */ + public function setFormFactory(FormFactoryInterface $formFactory) + { + throw new \BadMethodCallException('Buttons do not support form factories.'); + } + + /** + * Builds and returns the button configuration. + * + * @return FormConfigInterface + */ + public function getFormConfig() + { + // This method should be idempotent, so clone the builder + $config = clone $this; + $config->locked = true; + + return $config; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getEventDispatcher() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getPropertyPath() + { + return null; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getMapped() + { + return false; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getByReference() + { + return false; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getVirtual() + { + return false; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getCompound() + { + return false; + } + + /** + * Returns the form type used to construct the button. + * + * @return ResolvedFormTypeInterface The button's type. + */ + public function getType() + { + return $this->type; + } + + /** + * Unsupported method. + * + * @return array Always returns an empty array. + */ + public function getViewTransformers() + { + return array(); + } + + /** + * Unsupported method. + * + * @return array Always returns an empty array. + */ + public function getModelTransformers() + { + return array(); + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getDataMapper() + { + return null; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getRequired() + { + return false; + } + + /** + * Returns whether the button is disabled. + * + * @return Boolean Whether the button is disabled. + */ + public function getDisabled() + { + return $this->disabled; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getErrorBubbling() + { + return false; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getEmptyData() + { + return null; + } + + /** + * Returns additional attributes of the button. + * + * @return array An array of key-value combinations. + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Returns whether the attribute with the given name exists. + * + * @param string $name The attribute name. + * + * @return Boolean Whether the attribute exists. + */ + public function hasAttribute($name) + { + return array_key_exists($name, $this->attributes); + } + + /** + * Returns the value of the given attribute. + * + * @param string $name The attribute name. + * @param mixed $default The value returned if the attribute does not exist. + * + * @return mixed The attribute value. + */ + public function getAttribute($name, $default = null) + { + return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getData() + { + return null; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getDataClass() + { + return null; + } + + /** + * Unsupported method. + * + * @return Boolean Always returns false. + */ + public function getDataLocked() + { + return false; + } + + /** + * Unsupported method. + * + * @return null Always returns null. + */ + public function getFormFactory() + { + return null; + } + + /** + * Returns all options passed during the construction of the button. + * + * @return array The passed options. + */ + public function getOptions() + { + return $this->options; + } + + /** + * Returns whether a specific option exists. + * + * @param string $name The option name, + * + * @return Boolean Whether the option exists. + */ + public function hasOption($name) + { + return array_key_exists($name, $this->options); + } + + /** + * Returns the value of a specific option. + * + * @param string $name The option name. + * @param mixed $default The value returned if the option does not exist. + * + * @return mixed The option value. + */ + public function getOption($name, $default = null) + { + return array_key_exists($name, $this->options) ? $this->options[$name] : $default; + } + + /** + * Unsupported method. + * + * @return integer Always returns 0. + */ + public function count() + { + return 0; + } + + /** + * Unsupported method. + * + * @return \EmptyIterator Always returns an empty iterator. + */ + public function getIterator() + { + return new \EmptyIterator(); + } +} diff --git a/src/Symfony/Component/Form/ButtonTypeInterface.php b/src/Symfony/Component/Form/ButtonTypeInterface.php new file mode 100644 index 0000000000000..dd5117c4da777 --- /dev/null +++ b/src/Symfony/Component/Form/ButtonTypeInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +/** + * A type that should be converted into a {@link Button} instance. + * + * @author Bernhard Schussek + */ +interface ButtonTypeInterface extends FormTypeInterface +{ +} diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 08f1aec42f2be..b315af5cbc128 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -28,6 +28,8 @@ CHANGELOG * added an optional PropertyAccessorInterface parameter to FormType, ObjectChoiceList and PropertyPathMapper * [BC BREAK] PropertyPathMapper and FormType now have a constructor + * [BC BREAK] setting the option "validation_groups" to ``false`` now disables validation + instead of assuming group "Default" 2.1.0 ----- diff --git a/src/Symfony/Component/Form/ClickableInterface.php b/src/Symfony/Component/Form/ClickableInterface.php new file mode 100644 index 0000000000000..893f02df0aa70 --- /dev/null +++ b/src/Symfony/Component/Form/ClickableInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +/** + * A clickable form element. + * + * @author Bernhard Schussek + */ +interface ClickableInterface +{ + /** + * Returns whether this element was clicked. + * + * @return Boolean Whether this element was clicked. + */ + public function isClicked(); +} diff --git a/src/Symfony/Component/Form/Exception/InvalidArgumentException.php b/src/Symfony/Component/Form/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000000..a270e0ce9e0bd --- /dev/null +++ b/src/Symfony/Component/Form/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Exception; + +/** + * Base InvalidArgumentException for the Form component. + * + * @author Bernhard Schussek + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php index ff7a1a3e0e688..3934d38261ba2 100644 --- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php +++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php @@ -50,6 +50,9 @@ protected function loadTypes() new Type\TimezoneType(), new Type\UrlType(), new Type\FileType(), + new Type\ButtonType(), + new Type\SubmitType(), + new Type\ResetType(), ); } } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php new file mode 100644 index 0000000000000..79333a6799982 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Encapsulates common logic of {@link FormType} and {@link ButtonType}. + * + * This type does not appear in the form's type inheritance chain and as such + * cannot be extended (via {@link FormTypeExtension}s) nor themed. + * + * @author Bernhard Schussek + */ +abstract class BaseType extends AbstractType +{ + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->setDisabled($options['disabled']); + } + + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + $name = $form->getName(); + $blockName = $options['block_name'] ?: $form->getName(); + $translationDomain = $options['translation_domain']; + + if ($view->parent) { + if ('' !== ($parentFullName = $view->parent->vars['full_name'])) { + $id = sprintf('%s_%s', $view->parent->vars['id'], $name); + $fullName = sprintf('%s[%s]', $parentFullName, $name); + $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName); + } else { + $id = $name; + $fullName = $name; + $uniqueBlockPrefix = '_'.$blockName; + } + + if (!$translationDomain) { + $translationDomain = $view->parent->vars['translation_domain']; + } + } else { + $id = $name; + $fullName = $name; + $uniqueBlockPrefix = '_'.$blockName; + + // Strip leading underscores and digits. These are allowed in + // form names, but not in HTML4 ID attributes. + // http://www.w3.org/TR/html401/struct/global.html#adef-id + $id = ltrim($id, '_0123456789'); + } + + $blockPrefixes = array(); + for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) { + array_unshift($blockPrefixes, $type->getName()); + } + $blockPrefixes[] = $uniqueBlockPrefix; + + if (!$translationDomain) { + $translationDomain = 'messages'; + } + + $view->vars = array_replace($view->vars, array( + 'form' => $view, + 'id' => $id, + 'name' => $name, + 'full_name' => $fullName, + 'disabled' => $form->isDisabled(), + 'label' => $options['label'], + 'multipart' => false, + 'attr' => $options['attr'], + 'block_prefixes' => $blockPrefixes, + 'unique_block_prefix' => $uniqueBlockPrefix, + 'translation_domain' => $translationDomain, + // Using the block name here speeds up performance in collection + // forms, where each entry has the same full block name. + // Including the type is important too, because if rows of a + // collection form have different types (dynamically), they should + // be rendered differently. + // https://github.com/symfony/symfony/issues/5038 + 'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(), + )); + } + + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'block_name' => null, + 'disabled' => false, + 'label' => null, + 'attr' => array(), + 'translation_domain' => null, + )); + + $resolver->setAllowedTypes(array( + 'attr' => 'array', + )); + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php b/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php new file mode 100644 index 0000000000000..3569963bc4a9e --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/Type/ButtonType.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\Type; + +use Symfony\Component\Form\ButtonTypeInterface; + +/** + * A form button. + * + * @author Bernhard Schussek + */ +class ButtonType extends BaseType implements ButtonTypeInterface +{ + /** + * {@inheritdoc} + */ + public function getParent() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'button'; + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 16e7bbc7a0f3c..bd01f8f0407ae 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Form\Extension\Core\Type; -use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; @@ -23,7 +22,7 @@ use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; -class FormType extends AbstractType +class FormType extends BaseType { /** * @var PropertyAccessorInterface @@ -40,9 +39,10 @@ public function __construct(PropertyAccessorInterface $propertyAccessor = null) */ public function buildForm(FormBuilderInterface $builder, array $options) { + parent::buildForm($builder, $options); + $builder ->setRequired($options['required']) - ->setDisabled($options['disabled']) ->setErrorBubbling($options['error_bubbling']) ->setEmptyData($options['empty_data']) ->setPropertyPath($options['property_path']) @@ -65,85 +65,34 @@ public function buildForm(FormBuilderInterface $builder, array $options) */ public function buildView(FormView $view, FormInterface $form, array $options) { + parent::buildView($view, $form, $options); + $name = $form->getName(); - $blockName = $options['block_name'] ?: $form->getName(); $readOnly = $options['read_only']; - $translationDomain = $options['translation_domain']; if ($view->parent) { if ('' === $name) { throw new Exception('Form node with empty name can be used only as root form node.'); } - if ('' !== ($parentFullName = $view->parent->vars['full_name'])) { - $id = sprintf('%s_%s', $view->parent->vars['id'], $name); - $fullName = sprintf('%s[%s]', $parentFullName, $name); - $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName); - } else { - $id = $name; - $fullName = $name; - $uniqueBlockPrefix = '_'.$blockName; - } - // Complex fields are read-only if they themselves or their parents are. if (!$readOnly) { $readOnly = $view->parent->vars['read_only']; } - - if (!$translationDomain) { - $translationDomain = $view->parent->vars['translation_domain']; - } - } else { - $id = $name; - $fullName = $name; - $uniqueBlockPrefix = '_'.$blockName; - - // Strip leading underscores and digits. These are allowed in - // form names, but not in HTML4 ID attributes. - // http://www.w3.org/TR/html401/struct/global.html#adef-id - $id = ltrim($id, '_0123456789'); - } - - $blockPrefixes = array(); - for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) { - array_unshift($blockPrefixes, $type->getName()); - } - $blockPrefixes[] = $uniqueBlockPrefix; - - if (!$translationDomain) { - $translationDomain = 'messages'; } $view->vars = array_replace($view->vars, array( - 'form' => $view, - 'id' => $id, - 'name' => $name, - 'full_name' => $fullName, - 'read_only' => $readOnly, - 'errors' => $form->getErrors(), - 'valid' => $form->isBound() ? $form->isValid() : true, - 'value' => $form->getViewData(), - 'data' => $form->getNormData(), - 'disabled' => $form->isDisabled(), - 'required' => $form->isRequired(), - 'max_length' => $options['max_length'], - 'pattern' => $options['pattern'], - 'size' => null, - 'label' => $options['label'], - 'multipart' => false, - 'attr' => $options['attr'], - 'label_attr' => $options['label_attr'], - 'compound' => $form->getConfig()->getCompound(), - 'block_prefixes' => $blockPrefixes, - 'unique_block_prefix' => $uniqueBlockPrefix, - 'translation_domain' => $translationDomain, - // Using the block name here speeds up performance in collection - // forms, where each entry has the same full block name. - // Including the type is important too, because if rows of a - // collection form have different types (dynamically), they should - // be rendered differently. - // https://github.com/symfony/symfony/issues/5038 - 'cache_key' => $uniqueBlockPrefix.'_'.$form->getConfig()->getType()->getName(), + 'read_only' => $readOnly, + 'errors' => $form->getErrors(), + 'valid' => $form->isBound() ? $form->isValid() : true, + 'value' => $form->getViewData(), + 'data' => $form->getNormData(), + 'required' => $form->isRequired(), + 'max_length' => $options['max_length'], + 'pattern' => $options['pattern'], + 'size' => null, + 'label_attr' => $options['label_attr'], + 'compound' => $form->getConfig()->getCompound(), )); } @@ -169,6 +118,8 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function setDefaultOptions(OptionsResolverInterface $resolver) { + parent::setDefaultOptions($resolver); + // Derive "data_class" option from passed "data" object $dataClass = function (Options $options) { return isset($options['data']) && is_object($options['data']) ? get_class($options['data']) : null; @@ -202,29 +153,23 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) )); $resolver->setDefaults(array( - 'block_name' => null, 'data_class' => $dataClass, 'empty_data' => $emptyData, 'trim' => true, 'required' => true, 'read_only' => false, - 'disabled' => false, 'max_length' => null, 'pattern' => null, 'property_path' => null, 'mapped' => true, 'by_reference' => true, 'error_bubbling' => $errorBubbling, - 'label' => null, - 'attr' => array(), 'label_attr' => array(), 'virtual' => false, 'compound' => true, - 'translation_domain' => null, )); $resolver->setAllowedTypes(array( - 'attr' => 'array', 'label_attr' => 'array', )); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php b/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php new file mode 100644 index 0000000000000..cf55f7c5910a1 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\ButtonTypeInterface; + +/** + * A reset button. + * + * @author Bernhard Schussek + */ +class ResetType extends AbstractType implements ButtonTypeInterface +{ + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'button'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'reset'; + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php b/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php new file mode 100644 index 0000000000000..6d160b969214b --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Core\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\Form\SubmitButtonTypeInterface; + +/** + * A submit button. + * + * @author Bernhard Schussek + */ +class SubmitType extends AbstractType implements SubmitButtonTypeInterface +{ + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['clicked'] = $form->isClicked(); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'button'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'submit'; + } +} diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 167fcd95e9755..610329c030e7a 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Extension\Validator\Constraints; +use Symfony\Component\Form\ClickableInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Extension\Validator\Util\ServerParams; use Symfony\Component\Validator\Constraint; @@ -171,15 +172,21 @@ private static function allowDataWalking(FormInterface $form) */ private static function getValidationGroups(FormInterface $form) { + $button = self::findClickedButton($form->getRoot()); + + if (null !== $button) { + $groups = $button->getConfig()->getOption('validation_groups'); + + if (null !== $groups) { + return self::resolveValidationGroups($groups, $form); + } + } + do { $groups = $form->getConfig()->getOption('validation_groups'); if (null !== $groups) { - if (is_callable($groups)) { - $groups = call_user_func($groups, $form); - } - - return (array) $groups; + return self::resolveValidationGroups($groups, $form); } $form = $form->getParent(); @@ -187,4 +194,43 @@ private static function getValidationGroups(FormInterface $form) return array(Constraint::DEFAULT_GROUP); } + + /** + * Extracts a clicked button from a form tree, if one exists. + * + * @param FormInterface $form The root form. + * + * @return ClickableInterface|null The clicked button or null. + */ + private static function findClickedButton(FormInterface $form) + { + if ($form instanceof ClickableInterface && $form->isClicked()) { + return $form; + } + + foreach ($form as $child) { + if (null !== ($button = self::findClickedButton($child))) { + return $button; + } + } + + return null; + } + + /** + * Post-processes the validation groups option for a given form. + * + * @param array|callable $groups The validation groups. + * @param FormInterface $form The validated form. + * + * @return array The validation groups. + */ + private static function resolveValidationGroups($groups, FormInterface $form) + { + if (is_callable($groups)) { + $groups = call_user_func($groups, $form); + } + + return (array) $groups; + } } diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php new file mode 100644 index 0000000000000..7c5e6784ae7bc --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Validator/Type/BaseValidatorExtension.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Validator\Type; + +use Symfony\Component\Form\AbstractTypeExtension; +use Symfony\Component\OptionsResolver\Options; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Encapsulates common logic of {@link FormTypeValidatorExtension} and + * {@link SubmitTypeValidatorExtension}. + * + * @author Bernhard Schussek + */ +abstract class BaseValidatorExtension extends AbstractTypeExtension +{ + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + // Make sure that validation groups end up as null, closure or array + $validationGroupsNormalizer = function (Options $options, $groups) { + if (false === $groups) { + return array(); + } + + if (empty($groups)) { + return null; + } + + if (is_callable($groups)) { + return $groups; + } + + return (array) $groups; + }; + + $resolver->setDefaults(array( + 'validation_groups' => null, + )); + + $resolver->setNormalizers(array( + 'validation_groups' => $validationGroupsNormalizer, + )); + } +} diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php index 6b9ac4e4f03ca..99ef51f2bfed5 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php +++ b/src/Symfony/Component/Form/Extension/Validator/Type/FormTypeValidatorExtension.php @@ -22,7 +22,7 @@ /** * @author Bernhard Schussek */ -class FormTypeValidatorExtension extends AbstractTypeExtension +class FormTypeValidatorExtension extends BaseValidatorExtension { /** * @var ValidatorInterface @@ -53,18 +53,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) */ public function setDefaultOptions(OptionsResolverInterface $resolver) { - // Make sure that validation groups end up as null, closure or array - $validationGroupsNormalizer = function (Options $options, $groups) { - if (empty($groups)) { - return null; - } - - if (is_callable($groups)) { - return $groups; - } - - return (array) $groups; - }; + parent::setDefaultOptions($resolver); // Constraint should always be converted to an array $constraintsNormalizer = function (Options $options, $constraints) { @@ -73,8 +62,8 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) $resolver->setDefaults(array( 'error_mapping' => array(), - 'validation_groups' => null, - 'constraints' => null, + 'validation_constraint' => null, + 'constraints' => array(), 'cascade_validation' => false, 'invalid_message' => 'This value is not valid.', 'invalid_message_parameters' => array(), @@ -83,7 +72,6 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) )); $resolver->setNormalizers(array( - 'validation_groups' => $validationGroupsNormalizer, 'constraints' => $constraintsNormalizer, )); } diff --git a/src/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php new file mode 100644 index 0000000000000..5aad67fb3ad3d --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Validator/Type/SubmitTypeValidatorExtension.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Validator\Type; + +use Symfony\Component\Form\AbstractTypeExtension; + +/** + * @author Bernhard Schussek + */ +class SubmitTypeValidatorExtension extends AbstractTypeExtension +{ + /** + * {@inheritdoc} + */ + public function getExtendedType() + { + return 'submit'; + } +} diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php index e6d6fea415a38..9cff22a276575 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php @@ -51,6 +51,7 @@ protected function loadTypeExtensions() return array( new Type\FormTypeValidatorExtension($this->validator), new Type\RepeatedTypeValidatorExtension(), + new Type\SubmitTypeValidatorExtension(), ); } } diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index a626980c59a13..a778c9e09df8f 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -37,13 +37,6 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB */ private $unresolvedChildren = array(); - /** - * The parent of this builder. - * - * @var FormBuilder - */ - private $parent; - /** * Creates a new form builder. * @@ -70,7 +63,6 @@ public function add($child, $type = null, array $options = array()) } if ($child instanceof self) { - $child->setParent($this); $this->children[$child->getName()] = $child; // In case an unresolved child with the same name exists @@ -111,10 +103,10 @@ public function create($name, $type = null, array $options = array()) } if (null !== $type) { - return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options, $this); + return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options); } - return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options, $this); + return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options); } /** @@ -149,9 +141,6 @@ public function remove($name) unset($this->unresolvedChildren[$name]); if (array_key_exists($name, $this->children)) { - if ($this->children[$name] instanceof self) { - $this->children[$name]->setParent(null); - } unset($this->children[$name]); } @@ -211,7 +200,6 @@ public function getFormConfig() { $config = parent::getFormConfig(); - $config->parent = null; $config->children = array(); $config->unresolvedChildren = array(); @@ -238,44 +226,6 @@ public function getForm() return $form; } - /** - * {@inheritdoc} - */ - public function getParent() - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - return $this->parent; - } - - /** - * {@inheritdoc} - */ - public function setParent(FormBuilderInterface $parent = null) - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - $this->parent = $parent; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function hasParent() - { - if ($this->locked) { - throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); - } - - return null !== $this->parent; - } - /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index 7d297ed33d3cb..c52b4169e8a0d 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -392,7 +392,7 @@ public function getAttributes() */ public function hasAttribute($name) { - return isset($this->attributes[$name]); + return array_key_exists($name, $this->attributes); } /** @@ -400,7 +400,7 @@ public function hasAttribute($name) */ public function getAttribute($name, $default = null) { - return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; + return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** @@ -448,7 +448,7 @@ public function getOptions() */ public function hasOption($name) { - return isset($this->options[$name]); + return array_key_exists($name, $this->options); } /** @@ -456,7 +456,7 @@ public function hasOption($name) */ public function getOption($name, $default = null) { - return isset($this->options[$name]) ? $this->options[$name] : $default; + return array_key_exists($name, $this->options) ? $this->options[$name] : $default; } /** diff --git a/src/Symfony/Component/Form/FormEvents.php b/src/Symfony/Component/Form/FormEvents.php index 114bfcd226345..c46faf36abe36 100644 --- a/src/Symfony/Component/Form/FormEvents.php +++ b/src/Symfony/Component/Form/FormEvents.php @@ -1,5 +1,4 @@ createBuilder($type, $data, $options, $parent)->getForm(); + return $this->createBuilder($type, $data, $options)->getForm(); } /** * {@inheritdoc} */ - public function createNamed($name, $type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null) + public function createNamed($name, $type = 'form', $data = null, array $options = array()) { - return $this->createNamedBuilder($name, $type, $data, $options, $parent)->getForm(); + return $this->createNamedBuilder($name, $type, $data, $options)->getForm(); } /** * {@inheritdoc} */ - public function createForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null) + public function createForProperty($class, $property, $data = null, array $options = array()) { - return $this->createBuilderForProperty($class, $property, $data, $options, $parent)->getForm(); + return $this->createBuilderForProperty($class, $property, $data, $options)->getForm(); } /** * {@inheritdoc} */ - public function createBuilder($type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null) + public function createBuilder($type = 'form', $data = null, array $options = array()) { $name = $type instanceof FormTypeInterface || $type instanceof ResolvedFormTypeInterface ? $type->getName() : $type; - return $this->createNamedBuilder($name, $type, $data, $options, $parent); + return $this->createNamedBuilder($name, $type, $data, $options); } /** * {@inheritdoc} */ - public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null) + public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array()) { if (null !== $data && !array_key_exists('data', $options)) { $options['data'] = $data; @@ -84,16 +84,16 @@ public function createNamedBuilder($name, $type = 'form', $data = null, array $o throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface'); } - return $type->createBuilder($this, $name, $options, $parent); + return $type->createBuilder($this, $name, $options); } /** * {@inheritdoc} */ - public function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null) + public function createBuilderForProperty($class, $property, $data = null, array $options = array()) { if (null === $guesser = $this->registry->getTypeGuesser()) { - return $this->createNamedBuilder($property, 'text', $data, $options, $parent); + return $this->createNamedBuilder($property, 'text', $data, $options); } $typeGuess = $guesser->guessType($class, $property); @@ -123,7 +123,7 @@ public function createBuilderForProperty($class, $property, $data = null, array $options = array_merge($typeGuess->getOptions(), $options); } - return $this->createNamedBuilder($property, $type, $data, $options, $parent); + return $this->createNamedBuilder($property, $type, $data, $options); } /** diff --git a/src/Symfony/Component/Form/FormFactoryInterface.php b/src/Symfony/Component/Form/FormFactoryInterface.php index 98c53d9b530e0..8edfa95e521df 100644 --- a/src/Symfony/Component/Form/FormFactoryInterface.php +++ b/src/Symfony/Component/Form/FormFactoryInterface.php @@ -24,13 +24,12 @@ interface FormFactoryInterface * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options - * @param FormBuilderInterface $parent The parent builder * * @return FormInterface The form named after the type * * @throws Exception\FormException if any given option is not applicable to the given type */ - public function create($type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null); + public function create($type = 'form', $data = null, array $options = array()); /** * Returns a form. @@ -41,30 +40,28 @@ public function create($type = 'form', $data = null, array $options = array(), F * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options - * @param FormBuilderInterface $parent The parent builder * * @return FormInterface The form * * @throws Exception\FormException if any given option is not applicable to the given type */ - public function createNamed($name, $type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null); + public function createNamed($name, $type = 'form', $data = null, array $options = array()); /** * Returns a form for a property of a class. * * @see createBuilderForProperty() * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param mixed $data The initial data - * @param array $options The options for the builder - * @param FormBuilderInterface $parent The parent builder + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param mixed $data The initial data + * @param array $options The options for the builder * * @return FormInterface The form named after the property * * @throws Exception\FormException if any given option is not applicable to the form type */ - public function createForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null); + public function createForProperty($class, $property, $data = null, array $options = array()); /** * Returns a form builder. @@ -72,13 +69,12 @@ public function createForProperty($class, $property, $data = null, array $option * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options - * @param FormBuilderInterface $parent The parent builder * * @return FormBuilderInterface The form builder * * @throws Exception\FormException if any given option is not applicable to the given type */ - public function createBuilder($type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null); + public function createBuilder($type = 'form', $data = null, array $options = array()); /** * Returns a form builder. @@ -87,13 +83,12 @@ public function createBuilder($type = 'form', $data = null, array $options = arr * @param string|FormTypeInterface $type The type of the form * @param mixed $data The initial data * @param array $options The options - * @param FormBuilderInterface $parent The parent builder * * @return FormBuilderInterface The form builder * * @throws Exception\FormException if any given option is not applicable to the given type */ - public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array(), FormBuilderInterface $parent = null); + public function createNamedBuilder($name, $type = 'form', $data = null, array $options = array()); /** * Returns a form builder for a property of a class. @@ -101,15 +96,14 @@ public function createNamedBuilder($name, $type = 'form', $data = null, array $o * If any of the 'max_length', 'required' and type options can be guessed, * and are not provided in the options argument, the guessed value is used. * - * @param string $class The fully qualified class name - * @param string $property The name of the property to guess for - * @param mixed $data The initial data - * @param array $options The options for the builder - * @param FormBuilderInterface $parent The parent builder + * @param string $class The fully qualified class name + * @param string $property The name of the property to guess for + * @param mixed $data The initial data + * @param array $options The options for the builder * * @return FormBuilderInterface The form builder named after the property * * @throws Exception\FormException if any given option is not applicable to the form type */ - public function createBuilderForProperty($class, $property, $data = null, array $options = array(), FormBuilderInterface $parent = null); + public function createBuilderForProperty($class, $property, $data = null, array $options = array()); } diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php index 94f6b3e29dc1a..3e8fe525ecc08 100644 --- a/src/Symfony/Component/Form/FormInterface.php +++ b/src/Symfony/Component/Form/FormInterface.php @@ -150,9 +150,9 @@ public function getExtraData(); public function getConfig(); /** - * Returns whether the field is bound. + * Returns whether the form is submitted. * - * @return Boolean true if the form is bound to input values, false otherwise + * @return Boolean true if the form is submitted, false otherwise */ public function isBound(); diff --git a/src/Symfony/Component/Form/ResolvedFormType.php b/src/Symfony/Component/Form/ResolvedFormType.php index f2ef06c8b8a49..e48ea5e64d277 100644 --- a/src/Symfony/Component/Form/ResolvedFormType.php +++ b/src/Symfony/Component/Form/ResolvedFormType.php @@ -104,16 +104,15 @@ public function getTypeExtensions() /** * {@inheritdoc} */ - public function createBuilder(FormFactoryInterface $factory, $name, array $options = array(), FormBuilderInterface $parent = null) + public function createBuilder(FormFactoryInterface $factory, $name, array $options = array()) { $options = $this->getOptionsResolver()->resolve($options); // Should be decoupled from the specific option at some point $dataClass = isset($options['data_class']) ? $options['data_class'] : null; - $builder = new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options); + $builder = $this->newBuilder($name, $dataClass, $factory, $options); $builder->setType($this); - $builder->setParent($parent); $this->buildForm($builder, $options); @@ -127,7 +126,7 @@ public function createView(FormInterface $form, FormView $parent = null) { $options = $form->getConfig()->getOptions(); - $view = new FormView($parent); + $view = $this->newView($parent); $this->buildView($view, $form, $options); @@ -243,4 +242,43 @@ public function getOptionsResolver() return $this->optionsResolver; } + + /** + * Creates a new builder instance. + * + * Override this method if you want to customize the builder class. + * + * @param string $name The name of the builder. + * @param string $dataClass The data class. + * @param FormFactoryInterface $factory The current form factory. + * @param array $options The builder options. + * + * @return FormBuilderInterface The new builder instance. + */ + protected function newBuilder($name, $dataClass, FormFactoryInterface $factory, array $options) + { + if ($this->innerType instanceof ButtonTypeInterface) { + return new ButtonBuilder($name, $options); + } + + if ($this->innerType instanceof SubmitButtonTypeInterface) { + return new SubmitButtonBuilder($name, $options); + } + + return new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options); + } + + /** + * Creates a new view instance. + * + * Override this method if you want to customize the view class. + * + * @param FormView|null $parent The parent view, if available. + * + * @return FormView A new view instance. + */ + protected function newView(FormView $parent = null) + { + return new FormView($parent); + } } diff --git a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php index 611bd3a25f81d..c999bcdc6d833 100644 --- a/src/Symfony/Component/Form/ResolvedFormTypeInterface.php +++ b/src/Symfony/Component/Form/ResolvedFormTypeInterface.php @@ -52,11 +52,10 @@ public function getTypeExtensions(); * @param FormFactoryInterface $factory The form factory. * @param string $name The name for the builder. * @param array $options The builder options. - * @param FormBuilderInterface $parent The parent builder object or null. * * @return FormBuilderInterface The created form builder. */ - public function createBuilder(FormFactoryInterface $factory, $name, array $options = array(), FormBuilderInterface $parent = null); + public function createBuilder(FormFactoryInterface $factory, $name, array $options = array()); /** * Creates a new form view for a form of this type. diff --git a/src/Symfony/Component/Form/SubmitButton.php b/src/Symfony/Component/Form/SubmitButton.php new file mode 100644 index 0000000000000..01af5c2e72128 --- /dev/null +++ b/src/Symfony/Component/Form/SubmitButton.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +/** + * A button that submits the form. + * + * @author Bernhard Schussek + */ +class SubmitButton extends Button implements ClickableInterface +{ + /** + * @var Boolean + */ + private $clicked = false; + + /** + * {@inheritdoc} + */ + public function isClicked() + { + return $this->clicked; + } + + /** + * Binds data to the button. + * + * @param null|string $submittedData The data + * + * @return SubmitButton The button instance + * + * @throws Exception\AlreadyBoundException If the form has already been bound. + */ + public function bind($submittedData) + { + parent::bind($submittedData); + + $this->clicked = null !== $submittedData; + + return $this; + } +} diff --git a/src/Symfony/Component/Form/SubmitButtonBuilder.php b/src/Symfony/Component/Form/SubmitButtonBuilder.php new file mode 100644 index 0000000000000..088fb74819a60 --- /dev/null +++ b/src/Symfony/Component/Form/SubmitButtonBuilder.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +/** + * A builder for {@link SubmitButton} instances. + * + * @author Bernhard Schussek + */ +class SubmitButtonBuilder extends ButtonBuilder +{ + /** + * Creates the button. + * + * @return Button The button + */ + public function getForm() + { + return new SubmitButton($this->getFormConfig()); + } +} diff --git a/src/Symfony/Component/Form/SubmitButtonTypeInterface.php b/src/Symfony/Component/Form/SubmitButtonTypeInterface.php new file mode 100644 index 0000000000000..f7ac13f7ec92e --- /dev/null +++ b/src/Symfony/Component/Form/SubmitButtonTypeInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form; + +/** + * A type that should be converted into a {@link SubmitButton} instance. + * + * @author Bernhard Schussek + */ +interface SubmitButtonTypeInterface extends FormTypeInterface +{ +} diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php index 7fd743006e27c..391e81173ea0c 100644 --- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php @@ -82,6 +82,22 @@ public function testRepeatedRow() ); } + public function testButtonRow() + { + $form = $this->factory->createNamed('name', 'button'); + $view = $form->createView(); + $html = $this->renderRow($view); + + $this->assertMatchesXpath($html, +'/div + [ + ./button[@type="button"][@name="name"] + ] + [count(//label)=0] +' + ); + } + public function testRest() { $view = $this->factory->createNamedBuilder('name', 'form') diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index bf2c29e8e1842..bad30f06798cc 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -1762,4 +1762,38 @@ public function testEmptyRootFormName() //input[@type="text"][@id="child"][@name="child"]' , 2); } + + public function testButton() + { + $form = $this->factory->createNamed('name', 'button'); + + $this->assertWidgetMatchesXpath($form->createView(), array(), + '/button[@type="button"][@name="name"]' + ); + } + + public function testButtonLabelIsEmpty() + { + $form = $this->factory->createNamed('name', 'button'); + + $this->assertSame('', $this->renderLabel($form->createView())); + } + + public function testSubmit() + { + $form = $this->factory->createNamed('name', 'submit'); + + $this->assertWidgetMatchesXpath($form->createView(), array(), + '/button[@type="submit"][@name="name"]' + ); + } + + public function testReset() + { + $form = $this->factory->createNamed('name', 'reset'); + + $this->assertWidgetMatchesXpath($form->createView(), array(), + '/button[@type="reset"][@name="name"]' + ); + } } diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php index e0f62c4ab1a70..28fdba2dda167 100644 --- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php @@ -125,6 +125,25 @@ public function testRepeatedRowWithErrors() ); } + public function testButtonRow() + { + $form = $this->factory->createNamed('name', 'button'); + $view = $form->createView(); + $html = $this->renderRow($view); + + $this->assertMatchesXpath($html, +'/tr + [ + ./td + [.=""] + /following-sibling::td + [./button[@type="button"][@name="name"]] + ] + [count(//label)=0] +' + ); + } + public function testRest() { $view = $this->factory->createNamedBuilder('name', 'form') diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php new file mode 100644 index 0000000000000..d56355c64490d --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Core\Type; + +/** + * @author Bernhard Schussek + */ +abstract class BaseTypeTest extends TypeTestCase +{ + public function testPassDisabledAsOption() + { + $form = $this->factory->create($this->getTestedType(), null, array('disabled' => true)); + + $this->assertTrue($form->isDisabled()); + } + + public function testPassIdAndNameToView() + { + $form = $this->factory->createNamed('name', $this->getTestedType()); + $view = $form->createView(); + + $this->assertEquals('name', $view->vars['id']); + $this->assertEquals('name', $view->vars['name']); + $this->assertEquals('name', $view->vars['full_name']); + } + + public function testStripLeadingUnderscoresAndDigitsFromId() + { + $form = $this->factory->createNamed('_09name', $this->getTestedType()); + $view = $form->createView(); + + $this->assertEquals('name', $view->vars['id']); + $this->assertEquals('_09name', $view->vars['name']); + $this->assertEquals('_09name', $view->vars['full_name']); + } + + public function testPassIdAndNameToViewWithParent() + { + $parent = $this->factory->createNamed('parent', 'form'); + $parent->add($this->factory->createNamed('child', $this->getTestedType())); + $view = $parent->createView(); + + $this->assertEquals('parent_child', $view['child']->vars['id']); + $this->assertEquals('child', $view['child']->vars['name']); + $this->assertEquals('parent[child]', $view['child']->vars['full_name']); + } + + public function testPassIdAndNameToViewWithGrandParent() + { + $parent = $this->factory->createNamed('parent', 'form'); + $parent->add($this->factory->createNamed('child', 'form')); + $parent['child']->add($this->factory->createNamed('grand_child', $this->getTestedType())); + $view = $parent->createView(); + + $this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']); + $this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']); + $this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->vars['full_name']); + } + + public function testPassTranslationDomainToView() + { + $form = $this->factory->create($this->getTestedType(), null, array( + 'translation_domain' => 'domain', + )); + $view = $form->createView(); + + $this->assertSame('domain', $view->vars['translation_domain']); + } + + public function testInheritTranslationDomainFromParent() + { + $parent = $this->factory->createNamed('parent', 'form', null, array( + 'translation_domain' => 'domain', + )); + $child = $this->factory->createNamed('child', $this->getTestedType()); + $view = $parent->add($child)->createView(); + + $this->assertEquals('domain', $view['child']->vars['translation_domain']); + } + + public function testPreferOwnTranslationDomain() + { + $parent = $this->factory->createNamed('parent', 'form', null, array( + 'translation_domain' => 'parent_domain', + )); + $child = $this->factory->createNamed('child', $this->getTestedType(), null, array( + 'translation_domain' => 'domain', + )); + $view = $parent->add($child)->createView(); + + $this->assertEquals('domain', $view['child']->vars['translation_domain']); + } + + public function testDefaultTranslationDomain() + { + $parent = $this->factory->createNamed('parent', 'form'); + $child = $this->factory->createNamed('child', $this->getTestedType()); + $view = $parent->add($child)->createView(); + + $this->assertEquals('messages', $view['child']->vars['translation_domain']); + } + + public function testPassLabelToView() + { + $form = $this->factory->createNamed('__test___field', $this->getTestedType(), null, array('label' => 'My label')); + $view = $form->createView(); + + $this->assertSame('My label', $view->vars['label']); + } + + public function testPassMultipartFalseToView() + { + $form = $this->factory->create($this->getTestedType()); + $view = $form->createView(); + + $this->assertFalse($view->vars['multipart']); + } + + abstract protected function getTestedType(); +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php new file mode 100644 index 0000000000000..55835e77feb73 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Core\Type; + +/** + * @author Bernhard Schussek + */ +class ButtonTypeTest extends BaseTypeTest +{ + public function testCreateButtonInstances() + { + $this->assertInstanceOf('Symfony\Component\Form\Button', $this->factory->create('button')); + } + + protected function getTestedType() + { + return 'button'; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 6b906ea4f34bc..f6663d6b65614 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -50,8 +50,13 @@ public function setReferenceCopy($reference) } } -class FormTypeTest extends TypeTestCase +class FormTypeTest extends BaseTypeTest { + public function testCreateFormInstances() + { + $this->assertInstanceOf('Symfony\Component\Form\Form', $this->factory->create('form')); + } + public function testPassRequiredAsOption() { $form = $this->factory->create('form', null, array('required' => false)); @@ -63,13 +68,6 @@ public function testPassRequiredAsOption() $this->assertTrue($form->isRequired()); } - public function testPassDisabledAsOption() - { - $form = $this->factory->create('form', null, array('disabled' => true)); - - $this->assertTrue($form->isDisabled()); - } - public function testBoundDataIsTrimmedBeforeTransforming() { $form = $this->factory->createBuilder('form') @@ -102,49 +100,6 @@ public function testBoundDataIsNotTrimmedBeforeTransformingIfNoTrimming() $this->assertEquals('reverse[ a ]', $form->getData()); } - public function testPassIdAndNameToView() - { - $form = $this->factory->createNamed('name', 'form'); - $view = $form->createView(); - - $this->assertEquals('name', $view->vars['id']); - $this->assertEquals('name', $view->vars['name']); - $this->assertEquals('name', $view->vars['full_name']); - } - - public function testStripLeadingUnderscoresAndDigitsFromId() - { - $form = $this->factory->createNamed('_09name', 'form'); - $view = $form->createView(); - - $this->assertEquals('name', $view->vars['id']); - $this->assertEquals('_09name', $view->vars['name']); - $this->assertEquals('_09name', $view->vars['full_name']); - } - - public function testPassIdAndNameToViewWithParent() - { - $parent = $this->factory->createNamed('parent', 'form'); - $parent->add($this->factory->createNamed('child', 'form')); - $view = $parent->createView(); - - $this->assertEquals('parent_child', $view['child']->vars['id']); - $this->assertEquals('child', $view['child']->vars['name']); - $this->assertEquals('parent[child]', $view['child']->vars['full_name']); - } - - public function testPassIdAndNameToViewWithGrandParent() - { - $parent = $this->factory->createNamed('parent', 'form'); - $parent->add($this->factory->createNamed('child', 'form')); - $parent['child']->add($this->factory->createNamed('grand_child', 'form')); - $view = $parent->createView(); - - $this->assertEquals('parent_child_grand_child', $view['child']['grand_child']->vars['id']); - $this->assertEquals('grand_child', $view['child']['grand_child']->vars['name']); - $this->assertEquals('parent[child][grand_child]', $view['child']['grand_child']->vars['full_name']); - } - public function testNonReadOnlyFormWithReadOnlyParentBeingReadOnly() { $parent = $this->factory->createNamed('parent', 'form', null, array('read_only' => true)); @@ -180,57 +135,6 @@ public function testPassMaxLengthToView() $this->assertSame(10, $view->vars['max_length']); } - public function testPassTranslationDomainToView() - { - $form = $this->factory->create('form', null, array('translation_domain' => 'test')); - $view = $form->createView(); - - $this->assertSame('test', $view->vars['translation_domain']); - } - - public function testNonTranslationDomainFormWithTranslationDomainParentBeingTranslationDomain() - { - $parent = $this->factory->createNamed('parent', 'form', null, array('translation_domain' => 'test')); - $child = $this->factory->createNamed('child', 'form'); - $view = $parent->add($child)->createView(); - - $this->assertEquals('test', $view['child']->vars['translation_domain']); - } - - public function testTranslationDomainFormWithNonTranslationDomainParentBeingTranslationDomain() - { - $parent = $this->factory->createNamed('parent', 'form'); - $child = $this->factory->createNamed('child', 'form', null, array('translation_domain' => 'test')); - $view = $parent->add($child)->createView(); - - $this->assertEquals('test', $view['child']->vars['translation_domain']); - } - - public function testNonTranslationDomainFormWithNonTranslationDomainParentBeingTranslationDomainDefault() - { - $parent = $this->factory->createNamed('parent', 'form'); - $child = $this->factory->createNamed('child', 'form'); - $view = $parent->add($child)->createView(); - - $this->assertEquals('messages', $view['child']->vars['translation_domain']); - } - - public function testPassLabelToView() - { - $form = $this->factory->createNamed('__test___field', 'form', null, array('label' => 'My label')); - $view = $form->createView(); - - $this->assertSame('My label', $view->vars['label']); - } - - public function testDefaultTranslationDomain() - { - $form = $this->factory->create('form'); - $view = $form->createView(); - - $this->assertSame('messages', $view->vars['translation_domain']); - } - public function testBindWithEmptyDataCreatesObjectIfClassAvailable() { $form = $this->factory->create('form', null, array( @@ -404,6 +308,7 @@ public function testNameCanBeEmptyString() $this->assertEquals('', $form->getName()); } + public function testSubformDoesntCallSetters() { $author = new FormTest_AuthorWithoutRefSetter(new Author()); @@ -523,14 +428,6 @@ function ($value) use ($ref2) { // reverseTransform $this->assertSame($ref2, $author['referenceCopy']); } - public function testPassMultipartFalseToView() - { - $form = $this->factory->create('form'); - $view = $form->createView(); - - $this->assertFalse($view->vars['multipart']); - } - public function testPassMultipartTrueIfAnyChildIsMultipartToView() { $form = $this->factory->create('form'); @@ -661,4 +558,9 @@ public function testPassZeroLabelToView() $this->assertSame('0', $view->vars['label']); } + + protected function getTestedType() + { + return 'form'; + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php new file mode 100644 index 0000000000000..b85d72f5680a4 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/SubmitTypeTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Extension\Core\Type; + +/** + * @author Bernhard Schussek + */ +class SubmitTypeTest extends TypeTestCase +{ + public function testCreateSubmitButtonInstances() + { + $this->assertInstanceOf('Symfony\Component\Form\SubmitButton', $this->factory->create('submit')); + } + + public function testNotClickedByDefault() + { + $button = $this->factory->create('submit'); + + $this->assertFalse($button->isClicked()); + } + + public function testNotClickedIfBoundWithNull() + { + $button = $this->factory->create('submit'); + $button->bind(null); + + $this->assertFalse($button->isClicked()); + } + + public function testClickedIfBoundWithEmptyString() + { + $button = $this->factory->create('submit'); + $button->bind(''); + + $this->assertTrue($button->isClicked()); + } + + public function testClickedIfBoundWithUnemptyString() + { + $button = $this->factory->create('submit'); + $button->bind('foo'); + + $this->assertTrue($button->isClicked()); + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index a3d9f26d98617..ce5035717d72c 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator; +use Symfony\Component\Form\SubmitButtonBuilder; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\NotBlank; @@ -169,6 +170,51 @@ public function testValidateConstraintsEvenIfNoCascadeValidation() $this->validator->validate($form, new Form()); } + public function testDontValidateIfNoValidationGroups() + { + $context = $this->getMockExecutionContext(); + $object = $this->getMock('\stdClass'); + + $form = $this->getBuilder('name', '\stdClass', array( + 'validation_groups' => array(), + )) + ->setData($object) + ->getForm(); + + $form->setData($object); + + $context->expects($this->never()) + ->method('validate'); + + $this->validator->initialize($context); + $this->validator->validate($form, new Form()); + } + + public function testDontValidateConstraintsIfNoValidationGroups() + { + $context = $this->getMockExecutionContext(); + $object = $this->getMock('\stdClass'); + $constraint1 = $this->getMock('Symfony\Component\Validator\Constraint'); + $constraint2 = $this->getMock('Symfony\Component\Validator\Constraint'); + + $options = array( + 'validation_groups' => array(), + 'constraints' => array($constraint1, $constraint2), + ); + $form = $this->getBuilder('name', '\stdClass', $options) + ->setData($object) + ->getForm(); + + // Launch transformer + $form->bind(array()); + + $context->expects($this->never()) + ->method('validate'); + + $this->validator->initialize($context); + $this->validator->validate($form, new Form()); + } + public function testDontValidateIfNotSynchronized() { $context = $this->getMockExecutionContext(); @@ -208,6 +254,46 @@ function () { throw new TransformationFailedException(); } $this->validator->validate($form, new Form()); } + public function testAddInvalidErrorEvenIfNoValidationGroups() + { + $context = $this->getMockExecutionContext(); + $object = $this->getMock('\stdClass'); + + $form = $this->getBuilder('name', '\stdClass', array( + 'invalid_message' => 'invalid_message_key', + // Invalid message parameters must be supported, because the + // invalid message can be a translation key + // see https://github.com/symfony/symfony/issues/5144 + 'invalid_message_parameters' => array('{{ foo }}' => 'bar'), + 'validation_groups' => array(), + )) + ->setData($object) + ->addViewTransformer(new CallbackTransformer( + function ($data) { return $data; }, + function () { throw new TransformationFailedException(); } + )) + ->getForm(); + + // Launch transformer + $form->bind('foo'); + + $context->expects($this->never()) + ->method('validate'); + + $context->expects($this->once()) + ->method('addViolation') + ->with( + 'invalid_message_key', + array('{{ value }}' => 'foo', '{{ foo }}' => 'bar'), + 'foo' + ); + $context->expects($this->never()) + ->method('addViolationAt'); + + $this->validator->initialize($context); + $this->validator->validate($form, new Form()); + } + public function testDontValidateConstraintsIfNotSynchronized() { $context = $this->getMockExecutionContext(); @@ -313,6 +399,62 @@ public function testHandleClosureValidationGroups() $this->validator->validate($form, new Form()); } + public function testUseValidationGroupOfClickedButton() + { + $context = $this->getMockExecutionContext(); + $object = $this->getMock('\stdClass'); + + $parent = $this->getBuilder('parent', null, array('cascade_validation' => true)) + ->setCompound(true) + ->setDataMapper($this->getDataMapper()) + ->getForm(); + $form = $this->getForm('name', '\stdClass', array( + 'validation_groups' => 'form_group', + )); + + $parent->add($form); + $parent->add($this->getClickedSubmitButton('submit', array( + 'validation_groups' => 'button_group', + ))); + + $form->setData($object); + + $context->expects($this->once()) + ->method('validate') + ->with($object, 'data', 'button_group', true); + + $this->validator->initialize($context); + $this->validator->validate($form, new Form()); + } + + public function testDontUseValidationGroupOfUnclickedButton() + { + $context = $this->getMockExecutionContext(); + $object = $this->getMock('\stdClass'); + + $parent = $this->getBuilder('parent', null, array('cascade_validation' => true)) + ->setCompound(true) + ->setDataMapper($this->getDataMapper()) + ->getForm(); + $form = $this->getForm('name', '\stdClass', array( + 'validation_groups' => 'form_group', + )); + + $parent->add($form); + $parent->add($this->getSubmitButton('submit', array( + 'validation_groups' => 'button_group', + ))); + + $form->setData($object); + + $context->expects($this->once()) + ->method('validate') + ->with($object, 'data', 'form_group', true); + + $this->validator->initialize($context); + $this->validator->validate($form, new Form()); + } + public function testUseInheritedValidationGroup() { $context = $this->getMockExecutionContext(); @@ -561,9 +703,21 @@ private function getBuilder($name = 'name', $dataClass = null, array $options = return new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory, $options); } - private function getForm($name = 'name', $dataClass = null) + private function getForm($name = 'name', $dataClass = null, array $options = array()) + { + return $this->getBuilder($name, $dataClass, $options)->getForm(); + } + + private function getSubmitButton($name = 'name', array $options = array()) + { + $builder = new SubmitButtonBuilder($name, $options); + + return $builder->getForm(); + } + + private function getClickedSubmitButton($name = 'name', array $options = array()) { - return $this->getBuilder($name, $dataClass)->getForm(); + return $this->getSubmitButton($name, $options)->bind(''); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php index 13faefe95624a..094a26853b7c3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php @@ -40,6 +40,15 @@ public function testValidationGroupsCanBeSetToArray() $this->assertEquals(array('group1', 'group2'), $form->getConfig()->getOption('validation_groups')); } + public function testValidationGroupsCanBeSetToFalse() + { + $form = $this->factory->create('form', null, array( + 'validation_groups' => false, + )); + + $this->assertEquals(array(), $form->getConfig()->getOption('validation_groups')); + } + public function testValidationGroupsCanBeSetToCallback() { $form = $this->factory->create('form', null, array( diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php index e8137df35cda3..83a5db6e1040b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php @@ -781,7 +781,7 @@ public function testDefaultErrorMapping($target, $childName, $childPath, $grandC } else { $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one'); - $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName. ' should have an error, but has none'); + $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none'); } } @@ -1253,7 +1253,7 @@ public function testCustomDataErrorMapping($target, $mapFrom, $mapTo, $childName } else { $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one'); - $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName. ' should have an error, but has none'); + $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none'); } } @@ -1442,7 +1442,7 @@ public function testCustomFormErrorMapping($target, $mapFrom, $mapTo, $errorName $this->assertCount(0, $errorChild->getErrors(), $errorName.' should not have an error, but has one'); $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one'); - $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName. ' should have an error, but has none'); + $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none'); } } @@ -1497,7 +1497,7 @@ public function testVirtualFormErrorMapping($target, $childName, $childPath, $gr } else { $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $childName.' should not have an error, but has one'); - $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName. ' should have an error, but has none'); + $this->assertEquals(array($this->getFormError()), $grandChild->getErrors(), $grandChildName.' should have an error, but has none'); } } } diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index 14c8746f8b9d2..4f8cf05da8ff7 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -200,62 +200,19 @@ public function testGetGuessedType() $this->assertNotSame($builder, $this->builder); } - public function testGetParent() - { - $this->assertNull($this->builder->getParent()); - } - - public function testGetParentForAddedBuilder() - { - $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory); - $this->builder->add($builder); - $this->assertSame($this->builder, $builder->getParent()); - } - - public function testGetParentForRemovedBuilder() - { - $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory); - $this->builder->add($builder); - $this->builder->remove('name'); - $this->assertNull($builder->getParent()); - } - - public function testGetParentForCreatedBuilder() - { - $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory); - $this->factory - ->expects($this->once()) - ->method('createNamedBuilder') - ->with('bar', 'text', null, array(), $this->builder) - ; - - $this->factory - ->expects($this->once()) - ->method('createBuilderForProperty') - ->with('stdClass', 'foo', null, array(), $this->builder) - ; - - $this->builder->create('foo'); - $this->builder->create('bar', 'text'); - } - public function testGetFormConfigErasesReferences() { $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory); - $builder->setParent(new FormBuilder('parent', null, $this->dispatcher, $this->factory)); $builder->add(new FormBuilder('child', null, $this->dispatcher, $this->factory)); $config = $builder->getFormConfig(); $reflClass = new \ReflectionClass($config); - $parent = $reflClass->getProperty('parent'); $children = $reflClass->getProperty('children'); $unresolvedChildren = $reflClass->getProperty('unresolvedChildren'); - $parent->setAccessible(true); $children->setAccessible(true); $unresolvedChildren->setAccessible(true); - $this->assertNull($parent->getValue($config)); $this->assertEmpty($children->getValue($config)); $this->assertEmpty($unresolvedChildren->getValue($config)); } diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index cbb72f2bb31d6..ea872b01edf28 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -171,25 +171,6 @@ public function testCreateNamedBuilderWithResolvedTypeInstance() $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $resolvedType, null, $options)); } - public function testCreateNamedBuilderWithParentBuilder() - { - $options = array('a' => '1', 'b' => '2'); - $parentBuilder = $this->getMockFormBuilder(); - $resolvedType = $this->getMockResolvedType(); - - $this->registry->expects($this->once()) - ->method('getType') - ->with('type') - ->will($this->returnValue($resolvedType)); - - $resolvedType->expects($this->once()) - ->method('createBuilder') - ->with($this->factory, 'name', $options, $parentBuilder) - ->will($this->returnValue('BUILDER')); - - $this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', null, $options, $parentBuilder)); - } - public function testCreateNamedBuilderFillsDataOption() { $givenOptions = array('a' => '1', 'b' => '2'); @@ -228,7 +209,7 @@ public function testCreateNamedBuilderDoesNotOverrideExistingDataOption() } /** - * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException * @expectedExceptionMessage Expected argument of type "string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface", "stdClass" given */ public function testCreateNamedBuilderThrowsUnderstandableException() diff --git a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php index fd69dba171720..bb32a24122e58 100644 --- a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php @@ -134,10 +134,8 @@ public function testCreateBuilder() ->will($this->returnCallback($assertIndex(7))); $factory = $this->getMockFormFactory(); - $parentBuilder = $this->getBuilder('parent'); - $builder = $resolvedType->createBuilder($factory, 'name', $givenOptions, $parentBuilder); + $builder = $resolvedType->createBuilder($factory, 'name', $givenOptions); - $this->assertSame($parentBuilder, $builder->getParent()); $this->assertSame($resolvedType, $builder->getType()); } diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index c7fbab2d9c67b..a420a95f8c31e 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -89,7 +89,7 @@ public function testLoadThrowsAnExceptionIfFileNotLocal() } /** - * @expectedException Symfony\Component\Translation\Exception\InvalidResourceException + * @expectedException \Symfony\Component\Translation\Exception\InvalidResourceException * @expectedExceptionMessage Document types are not allowed. */ public function testDocTypeIsNotAllowed() diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php index 22478e606d0ec..1677b81b1f62c 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php @@ -82,7 +82,7 @@ public function testLoadGroupSequenceProvider() } /** - * @expectedException Symfony\Component\Validator\Exception\MappingException + * @expectedException \Symfony\Component\Validator\Exception\MappingException * @expectedExceptionMessage Document types are not allowed. */ public function testDocTypeIsNotAllowed()