Skip to content

Commit

Permalink
[Form] Made validation of form children configurable. Set the option …
Browse files Browse the repository at this point in the history
…"cascade_validation" to `true` if you need it.
  • Loading branch information
webmozart committed Jan 16, 2012
1 parent efada56 commit 0c70a41
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public function buildForm(FormBuilder $builder, array $options)
$builder
->setAttribute('validation_groups', $options['validation_groups'])
->setAttribute('validation_constraint', $options['validation_constraint'])
->setAttribute('cascade_validation', $options['cascade_validation'])
->addValidator(new DelegatingValidator($this->validator));
}

Expand All @@ -46,6 +47,7 @@ public function getDefaultOptions(array $options)
return array(
'validation_groups' => null,
'validation_constraint' => null,
'cascade_validation' => false,

This comment has been minimized.

Copy link
@umpirsky

umpirsky Jul 7, 2012

Contributor

Why is default value false?

This comment has been minimized.

Copy link
@webmozart

webmozart Jul 7, 2012

Author Contributor

Because you usually want to control the cascading in your model using @Valid constraints.

This comment has been minimized.

Copy link
@umpirsky

umpirsky Jul 7, 2012

Contributor

Hehum, I didn't know that, and I don't understand. Any example, doc for @Valid? Thanks.

This comment has been minimized.

Copy link
@webmozart

This comment has been minimized.

Copy link
@umpirsky

umpirsky Jul 8, 2012

Contributor

Ah, ok, thanks!

);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,29 @@ static public function validateFormData(FormInterface $form, ExecutionContext $c
}
}

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;
Expand Down
7 changes: 4 additions & 3 deletions src/Symfony/Component/Form/Resources/config/validation.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,81 @@ public function testValidateFormDataDoesNotWalkScalars()
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();
Expand Down

0 comments on commit 0c70a41

Please sign in to comment.