merged branch bschussek/optional-form-child-validation (PR #3128)
Commits
-------
0c70a41
[Form] Made validation of form children configurable. Set the option "cascade_validation" to `true` if you need it.
Discussion
----------
[Form] Made validation of form children configurable
Bug fix: yes
Feature addition: yes
Backwards compatibility break: yes
Symfony2 tests pass: yes
Fixes the following tickets: #797
Todo: adapt documentation
![Travis Build Status](https://secure.travis-ci.org/bschussek/symfony.png?branch=optional-form-child-validation)
Child forms now aren't validated anymore by default. This is not a problem as long as @Valid constraints are properly put in your model. If you want to enable cascading validation, for example when there is no connection between the parent and the child model, you can set the option "cascade_validation" in the parent form to true.
This change is not backwards compatible, but from my estimation the break should not affect many applications.
---------------------------------------------------------------------------
by kriswallsmith at 2012-01-16T19:59:25Z
👍
This commit is contained in:
commit
b8d8cab1f9
@ -38,6 +38,7 @@ class FieldTypeValidatorExtension extends AbstractTypeExtension
|
||||
$builder
|
||||
->setAttribute('validation_groups', $options['validation_groups'])
|
||||
->setAttribute('validation_constraint', $options['validation_constraint'])
|
||||
->setAttribute('cascade_validation', $options['cascade_validation'])
|
||||
->addValidator(new DelegatingValidator($this->validator));
|
||||
}
|
||||
|
||||
@ -46,6 +47,7 @@ class FieldTypeValidatorExtension extends AbstractTypeExtension
|
||||
return array(
|
||||
'validation_groups' => null,
|
||||
'validation_constraint' => null,
|
||||
'cascade_validation' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,29 @@ class DelegatingValidator implements FormValidatorInterface
|
||||
}
|
||||
}
|
||||
|
||||
static public function validateFormChildren(FormInterface $form, ExecutionContext $context)
|
||||
{
|
||||
if ($form->getAttribute('cascade_validation')) {
|
||||
$propertyPath = $context->getPropertyPath();
|
||||
$graphWalker = $context->getGraphWalker();
|
||||
|
||||
// The Execute constraint is called on class level, so we need to
|
||||
// set the property manually
|
||||
$context->setCurrentProperty('children');
|
||||
|
||||
// Adjust the property path accordingly
|
||||
if (!empty($propertyPath)) {
|
||||
$propertyPath .= '.';
|
||||
}
|
||||
|
||||
$propertyPath .= 'children';
|
||||
|
||||
foreach (self::getFormValidationGroups($form) as $group) {
|
||||
$graphWalker->walkReference($form->getChildren(), $group, $propertyPath, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static protected function getFormValidationGroups(FormInterface $form)
|
||||
{
|
||||
$groups = null;
|
||||
|
@ -10,9 +10,10 @@
|
||||
<value>Symfony\Component\Form\Extension\Validator\Validator\DelegatingValidator</value>
|
||||
<value>validateFormData</value>
|
||||
</value>
|
||||
<value>
|
||||
<value>Symfony\Component\Form\Extension\Validator\Validator\DelegatingValidator</value>
|
||||
<value>validateFormChildren</value>
|
||||
</value>
|
||||
</constraint>
|
||||
<property name="children">
|
||||
<constraint name="Valid" />
|
||||
</property>
|
||||
</class>
|
||||
</constraint-mapping>
|
||||
|
@ -798,6 +798,81 @@ class DelegatingValidatorTest extends \PHPUnit_Framework_TestCase
|
||||
DelegatingValidator::validateFormData($form, $context);
|
||||
}
|
||||
|
||||
public function testValidateFormChildren()
|
||||
{
|
||||
$graphWalker = $this->getMockGraphWalker();
|
||||
$metadataFactory = $this->getMockMetadataFactory();
|
||||
$context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
|
||||
$form = $this->getBuilder()
|
||||
->setAttribute('cascade_validation', true)
|
||||
->setAttribute('validation_groups', array('group1', 'group2'))
|
||||
->getForm();
|
||||
$form->add($this->getForm('firstName'));
|
||||
|
||||
$graphWalker->expects($this->at(0))
|
||||
->method('walkReference')
|
||||
->with($form->getChildren(), 'group1', 'children', true);
|
||||
$graphWalker->expects($this->at(1))
|
||||
->method('walkReference')
|
||||
->with($form->getChildren(), 'group2', 'children', true);
|
||||
|
||||
DelegatingValidator::validateFormChildren($form, $context);
|
||||
}
|
||||
|
||||
public function testValidateFormChildrenAppendsPropertyPath()
|
||||
{
|
||||
$graphWalker = $this->getMockGraphWalker();
|
||||
$metadataFactory = $this->getMockMetadataFactory();
|
||||
$context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
|
||||
$context->setPropertyPath('path');
|
||||
$form = $this->getBuilder()
|
||||
->setAttribute('cascade_validation', true)
|
||||
->getForm();
|
||||
$form->add($this->getForm('firstName'));
|
||||
|
||||
$graphWalker->expects($this->once())
|
||||
->method('walkReference')
|
||||
->with($form->getChildren(), 'Default', 'path.children', true);
|
||||
|
||||
DelegatingValidator::validateFormChildren($form, $context);
|
||||
}
|
||||
|
||||
public function testValidateFormChildrenSetsCurrentPropertyToData()
|
||||
{
|
||||
$graphWalker = $this->getMockGraphWalker();
|
||||
$metadataFactory = $this->getMockMetadataFactory();
|
||||
$context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
|
||||
$form = $this->getBuilder()
|
||||
->setAttribute('cascade_validation', true)
|
||||
->getForm();
|
||||
$form->add($this->getForm('firstName'));
|
||||
$test = $this;
|
||||
|
||||
$graphWalker->expects($this->once())
|
||||
->method('walkReference')
|
||||
->will($this->returnCallback(function () use ($context, $test) {
|
||||
$test->assertEquals('children', $context->getCurrentProperty());
|
||||
}));
|
||||
|
||||
DelegatingValidator::validateFormChildren($form, $context);
|
||||
}
|
||||
|
||||
public function testValidateFormChildrenDoesNothingIfDisabled()
|
||||
{
|
||||
$graphWalker = $this->getMockGraphWalker();
|
||||
$metadataFactory = $this->getMockMetadataFactory();
|
||||
$context = new ExecutionContext('Root', $graphWalker, $metadataFactory);
|
||||
$form = $this->getBuilder()
|
||||
->setAttribute('cascade_validation', false)
|
||||
->getForm();
|
||||
$form->add($this->getForm('firstName'));
|
||||
|
||||
$graphWalker->expects($this->never())
|
||||
->method('walkReference');
|
||||
|
||||
DelegatingValidator::validateFormChildren($form, $context);
|
||||
}
|
||||
|
||||
public function testValidateIgnoresNonRoot()
|
||||
{
|
||||
$form = $this->getMockForm();
|
||||
|
Reference in New Issue
Block a user