bug #38380 [Form] propagate validation groups to subforms (johanderuijter, xabbuh)
This PR was merged into the 3.4 branch. Discussion ---------- [Form] propagate validation groups to subforms | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | Fix #38300 | License | MIT | Doc PR | Commits -------04f5698e29
propagate validation groups to subformse2c7c3373d
[Form] [Validator] Add failing testcase to demonstrate group sequence issue
This commit is contained in:
commit
4be56f6932
@ -25,6 +25,7 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
|||||||
class FormValidator extends ConstraintValidator
|
class FormValidator extends ConstraintValidator
|
||||||
{
|
{
|
||||||
private $resolvedGroups;
|
private $resolvedGroups;
|
||||||
|
private $fieldFormConstraints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
@ -67,6 +68,7 @@ class FormValidator extends ConstraintValidator
|
|||||||
|
|
||||||
if ($hasChildren && $form->isRoot()) {
|
if ($hasChildren && $form->isRoot()) {
|
||||||
$this->resolvedGroups = new \SplObjectStorage();
|
$this->resolvedGroups = new \SplObjectStorage();
|
||||||
|
$this->fieldFormConstraints = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($groups instanceof GroupSequence) {
|
if ($groups instanceof GroupSequence) {
|
||||||
@ -84,14 +86,16 @@ class FormValidator extends ConstraintValidator
|
|||||||
|
|
||||||
foreach ($form->all() as $field) {
|
foreach ($form->all() as $field) {
|
||||||
if ($field->isSubmitted()) {
|
if ($field->isSubmitted()) {
|
||||||
// remember to validate this field is one group only
|
// remember to validate this field in one group only
|
||||||
// otherwise resolving the groups would reuse the same
|
// otherwise resolving the groups would reuse the same
|
||||||
// sequence recursively, thus some fields could fail
|
// sequence recursively, thus some fields could fail
|
||||||
// in different steps without breaking early enough
|
// in different steps without breaking early enough
|
||||||
$this->resolvedGroups[$field] = (array) $group;
|
$this->resolvedGroups[$field] = (array) $group;
|
||||||
$fieldFormConstraint = new Form();
|
$fieldFormConstraint = new Form();
|
||||||
|
$fieldFormConstraint->groups = $group;
|
||||||
|
$this->fieldFormConstraints[] = $fieldFormConstraint;
|
||||||
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
|
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
|
||||||
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint);
|
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint, $group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +134,7 @@ class FormValidator extends ConstraintValidator
|
|||||||
if ($field->isSubmitted()) {
|
if ($field->isSubmitted()) {
|
||||||
$this->resolvedGroups[$field] = $groups;
|
$this->resolvedGroups[$field] = $groups;
|
||||||
$fieldFormConstraint = new Form();
|
$fieldFormConstraint = new Form();
|
||||||
|
$this->fieldFormConstraints[] = $fieldFormConstraint;
|
||||||
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
|
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
|
||||||
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint);
|
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint);
|
||||||
}
|
}
|
||||||
@ -139,6 +144,7 @@ class FormValidator extends ConstraintValidator
|
|||||||
if ($hasChildren && $form->isRoot()) {
|
if ($hasChildren && $form->isRoot()) {
|
||||||
// destroy storage to avoid memory leaks
|
// destroy storage to avoid memory leaks
|
||||||
$this->resolvedGroups = new \SplObjectStorage();
|
$this->resolvedGroups = new \SplObjectStorage();
|
||||||
|
$this->fieldFormConstraints = [];
|
||||||
}
|
}
|
||||||
} elseif (!$form->isSynchronized()) {
|
} elseif (!$form->isSynchronized()) {
|
||||||
$childrenSynchronized = true;
|
$childrenSynchronized = true;
|
||||||
@ -149,6 +155,7 @@ class FormValidator extends ConstraintValidator
|
|||||||
$childrenSynchronized = false;
|
$childrenSynchronized = false;
|
||||||
|
|
||||||
$fieldFormConstraint = new Form();
|
$fieldFormConstraint = new Form();
|
||||||
|
$this->fieldFormConstraints[] = $fieldFormConstraint;
|
||||||
$this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath());
|
$this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath());
|
||||||
$validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $fieldFormConstraint);
|
$validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $fieldFormConstraint);
|
||||||
}
|
}
|
||||||
|
@ -232,6 +232,34 @@ class FormValidatorFunctionalTest extends TestCase
|
|||||||
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testConstraintsInDifferentGroupsOnSingleFieldWithAdditionalFieldThatHasNoConstraintsAddedBeforeTheFieldWithConstraints()
|
||||||
|
{
|
||||||
|
$form = $this->formFactory->create(FormType::class, null, [
|
||||||
|
'validation_groups' => new GroupSequence(['group1', 'group2']),
|
||||||
|
])
|
||||||
|
->add('bar')
|
||||||
|
->add('foo', TextType::class, [
|
||||||
|
'constraints' => [
|
||||||
|
new NotBlank([
|
||||||
|
'groups' => ['group1'],
|
||||||
|
]),
|
||||||
|
new Length([
|
||||||
|
'groups' => ['group2'],
|
||||||
|
'max' => 3,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$form->submit([
|
||||||
|
'foo' => 'test@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$errors = $form->getErrors(true);
|
||||||
|
|
||||||
|
$this->assertFalse($form->isValid());
|
||||||
|
$this->assertCount(1, $errors);
|
||||||
|
$this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint());
|
||||||
|
}
|
||||||
|
|
||||||
public function testCascadeValidationToChildFormsUsingPropertyPaths()
|
public function testCascadeValidationToChildFormsUsingPropertyPaths()
|
||||||
{
|
{
|
||||||
$form = $this->formFactory->create(FormType::class, null, [
|
$form = $this->formFactory->create(FormType::class, null, [
|
||||||
|
Reference in New Issue
Block a user