[Form] Made submit buttons able to convey validation groups
This commit is contained in:
parent
cc2118dd5c
commit
7b438a816b
@ -163,5 +163,8 @@
|
|||||||
<service id="form.type_extension.repeated.validator" class="Symfony\Component\Form\Extension\Validator\Type\RepeatedTypeValidatorExtension">
|
<service id="form.type_extension.repeated.validator" class="Symfony\Component\Form\Extension\Validator\Type\RepeatedTypeValidatorExtension">
|
||||||
<tag name="form.type_extension" alias="repeated" />
|
<tag name="form.type_extension" alias="repeated" />
|
||||||
</service>
|
</service>
|
||||||
|
<service id="form.type_extension.submit.validator" class="Symfony\Component\Form\Extension\Validator\Type\SubmitTypeValidatorExtension">
|
||||||
|
<tag name="form.type_extension" alias="submit" />
|
||||||
|
</service>
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
@ -40,8 +40,6 @@ abstract class BaseType extends AbstractType
|
|||||||
*/
|
*/
|
||||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||||
{
|
{
|
||||||
/* @var \Symfony\Component\Form\ClickableInterface $form */
|
|
||||||
|
|
||||||
$name = $form->getName();
|
$name = $form->getName();
|
||||||
$blockName = $options['block_name'] ?: $form->getName();
|
$blockName = $options['block_name'] ?: $form->getName();
|
||||||
$translationDomain = $options['translation_domain'];
|
$translationDomain = $options['translation_domain'];
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Form\Extension\Validator\Constraints;
|
namespace Symfony\Component\Form\Extension\Validator\Constraints;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\ClickableInterface;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
|
use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
@ -171,15 +172,21 @@ class FormValidator extends ConstraintValidator
|
|||||||
*/
|
*/
|
||||||
private static function getValidationGroups(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 {
|
do {
|
||||||
$groups = $form->getConfig()->getOption('validation_groups');
|
$groups = $form->getConfig()->getOption('validation_groups');
|
||||||
|
|
||||||
if (null !== $groups) {
|
if (null !== $groups) {
|
||||||
if (is_callable($groups)) {
|
return self::resolveValidationGroups($groups, $form);
|
||||||
$groups = call_user_func($groups, $form);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (array) $groups;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $form->getParent();
|
$form = $form->getParent();
|
||||||
@ -187,4 +194,43 @@ class FormValidator extends ConstraintValidator
|
|||||||
|
|
||||||
return array(Constraint::DEFAULT_GROUP);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* 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 <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
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 (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,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ use Symfony\Component\OptionsResolver\OptionsResolverInterface;
|
|||||||
/**
|
/**
|
||||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*/
|
*/
|
||||||
class FormTypeValidatorExtension extends AbstractTypeExtension
|
class FormTypeValidatorExtension extends BaseValidatorExtension
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var ValidatorInterface
|
* @var ValidatorInterface
|
||||||
@ -53,6 +53,8 @@ class FormTypeValidatorExtension extends AbstractTypeExtension
|
|||||||
*/
|
*/
|
||||||
public function setDefaultOptions(OptionsResolverInterface $resolver)
|
public function setDefaultOptions(OptionsResolverInterface $resolver)
|
||||||
{
|
{
|
||||||
|
parent::setDefaultOptions($resolver);
|
||||||
|
|
||||||
// BC clause
|
// BC clause
|
||||||
$constraints = function (Options $options) {
|
$constraints = function (Options $options) {
|
||||||
return $options['validation_constraint'];
|
return $options['validation_constraint'];
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* 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 <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class SubmitTypeValidatorExtension extends AbstractTypeExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getExtendedType()
|
||||||
|
{
|
||||||
|
return 'submit';
|
||||||
|
}
|
||||||
|
}
|
@ -51,6 +51,7 @@ class ValidatorExtension extends AbstractExtension
|
|||||||
return array(
|
return array(
|
||||||
new Type\FormTypeValidatorExtension($this->validator),
|
new Type\FormTypeValidatorExtension($this->validator),
|
||||||
new Type\RepeatedTypeValidatorExtension(),
|
new Type\RepeatedTypeValidatorExtension(),
|
||||||
|
new Type\SubmitTypeValidatorExtension(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ use Symfony\Component\Form\CallbackTransformer;
|
|||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
|
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
|
||||||
use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
|
use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator;
|
||||||
|
use Symfony\Component\Form\SubmitButtonBuilder;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\Constraints\NotNull;
|
use Symfony\Component\Validator\Constraints\NotNull;
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
@ -313,6 +314,62 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->validator->validate($form, new Form());
|
$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()
|
public function testUseInheritedValidationGroup()
|
||||||
{
|
{
|
||||||
$context = $this->getMockExecutionContext();
|
$context = $this->getMockExecutionContext();
|
||||||
@ -561,9 +618,21 @@ class FormValidatorTest extends \PHPUnit_Framework_TestCase
|
|||||||
return new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory, $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)->getForm();
|
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->getSubmitButton($name, $options)->bind('');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user