Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cd322c4

Browse files
committed
bug #11571 [Form] Fixed FormValidator compatibility with the non-BC 2.5 Validation API (webmozart)
This PR was merged into the 2.5 branch. Discussion ---------- [Form] Fixed FormValidator compatibility with the non-BC 2.5 Validation API | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #11568 | License | MIT | Doc PR | - Commits ------- 6ac130e [Form] Fixed FormValidator compatibility with the non-BC 2.5 Validation API
2 parents 98c0621 + 6ac130e commit cd322c4

File tree

7 files changed

+433
-205
lines changed

7 files changed

+433
-205
lines changed

src/Symfony/Bundle/FrameworkBundle/Validator/LegacyConstraintValidatorFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
class LegacyConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
3030
{
3131
const BASE_NAMESPACE = 'Symfony\\Component\\Validator\\Constraints';
32+
const FORM_BASE_NAMESPACE = 'Symfony\\Component\\Form\\Extension\\Validator\\Constraints';
3233

3334
protected $container;
3435
protected $validators;
@@ -75,6 +76,9 @@ public function getInstance(Constraint $constraint)
7576
case self::BASE_NAMESPACE.'\\Length':
7677
$name = self::BASE_NAMESPACE.'\\LegacyLengthValidator';
7778
break;
79+
case self::FORM_BASE_NAMESPACE.'\\Form':
80+
$name = self::FORM_BASE_NAMESPACE.'\\LegacyFormValidator';
81+
break;
7882
}
7983

8084
$this->validators[$name] = new $name();

src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public function validate($form, Constraint $constraint)
5353

5454
/* @var FormInterface $form */
5555
$config = $form->getConfig();
56+
$validator = $this->context->getValidator()->inContext($this->context);
5657

5758
if ($form->isSynchronized()) {
5859
// Validate the form data only if transformation succeeded
@@ -61,7 +62,7 @@ public function validate($form, Constraint $constraint)
6162
// Validate the data against its own constraints
6263
if (self::allowDataWalking($form)) {
6364
foreach ($groups as $group) {
64-
$this->context->validate($form->getData(), 'data', $group, true);
65+
$validator->atPath('data')->validate($form->getData(), null, $group);
6566
}
6667
}
6768

@@ -71,7 +72,7 @@ public function validate($form, Constraint $constraint)
7172
foreach ($constraints as $constraint) {
7273
foreach ($groups as $group) {
7374
if (in_array($group, $constraint->groups)) {
74-
$this->context->validateValue($form->getData(), $constraint, 'data', $group);
75+
$validator->atPath('data')->validate($form->getData(), $constraint, $group);
7576

7677
// Prevent duplicate validation
7778
continue 2;
@@ -100,23 +101,20 @@ public function validate($form, Constraint $constraint)
100101
? (string) $form->getViewData()
101102
: gettype($form->getViewData());
102103

103-
$this->context->addViolation(
104-
$config->getOption('invalid_message'),
105-
array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')),
106-
$form->getViewData(),
107-
null,
108-
Form::ERR_INVALID
109-
);
104+
$this->context->buildViolation($config->getOption('invalid_message'))
105+
->setParameters(array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')))
106+
->setInvalidValue($form->getViewData())
107+
->setCode(Form::ERR_INVALID)
108+
->addViolation();
110109
}
111110
}
112111

113112
// Mark the form with an error if it contains extra fields
114113
if (count($form->getExtraData()) > 0) {
115-
$this->context->addViolation(
116-
$config->getOption('extra_fields_message'),
117-
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
118-
$form->getExtraData()
119-
);
114+
$this->context->buildViolation($config->getOption('extra_fields_message'))
115+
->setParameter('{{ extra_fields }}', implode('", "', array_keys($form->getExtraData())))
116+
->setInvalidValue($form->getExtraData())
117+
->addViolation();
120118
}
121119

122120
// Mark the form with an error if the uploaded size was too large
@@ -126,11 +124,10 @@ public function validate($form, Constraint $constraint)
126124
$max = $this->serverParams->getPostMaxSize();
127125

128126
if (!empty($max) && $length > $max) {
129-
$this->context->addViolation(
130-
$config->getOption('post_max_size_message'),
131-
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
132-
$length
133-
);
127+
$this->context->buildViolation($config->getOption('post_max_size_message'))
128+
->setParameter('{{ max }}', $this->serverParams->getNormalizedIniPostMaxSize())
129+
->setInvalidValue($length)
130+
->addViolation();
134131
}
135132
}
136133
}
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Extension\Validator\Constraints;
13+
14+
use Symfony\Component\Form\FormInterface;
15+
use Symfony\Component\Form\Extension\Validator\Util\ServerParams;
16+
use Symfony\Component\Validator\Constraint;
17+
use Symfony\Component\Validator\ConstraintValidator;
18+
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
19+
20+
/**
21+
* @author Bernhard Schussek <[email protected]>
22+
*/
23+
class LegacyFormValidator extends ConstraintValidator
24+
{
25+
/**
26+
* @var ServerParams
27+
*/
28+
private $serverParams;
29+
30+
/**
31+
* Creates a validator with the given server parameters.
32+
*
33+
* @param ServerParams $params The server parameters. Default
34+
* parameters are created if null.
35+
*/
36+
public function __construct(ServerParams $params = null)
37+
{
38+
$this->serverParams = $params ?: new ServerParams();
39+
}
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function validate($form, Constraint $constraint)
45+
{
46+
if (!$constraint instanceof Form) {
47+
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Form');
48+
}
49+
50+
if (!$form instanceof FormInterface) {
51+
return;
52+
}
53+
54+
/* @var FormInterface $form */
55+
$config = $form->getConfig();
56+
57+
if ($form->isSynchronized()) {
58+
// Validate the form data only if transformation succeeded
59+
$groups = self::getValidationGroups($form);
60+
61+
// Validate the data against its own constraints
62+
if (self::allowDataWalking($form)) {
63+
foreach ($groups as $group) {
64+
$this->context->validate($form->getData(), 'data', $group, true);
65+
}
66+
}
67+
68+
// Validate the data against the constraints defined
69+
// in the form
70+
$constraints = $config->getOption('constraints');
71+
foreach ($constraints as $constraint) {
72+
foreach ($groups as $group) {
73+
if (in_array($group, $constraint->groups)) {
74+
$this->context->validateValue($form->getData(), $constraint, 'data', $group);
75+
76+
// Prevent duplicate validation
77+
continue 2;
78+
}
79+
}
80+
}
81+
} else {
82+
$childrenSynchronized = true;
83+
84+
foreach ($form as $child) {
85+
if (!$child->isSynchronized()) {
86+
$childrenSynchronized = false;
87+
break;
88+
}
89+
}
90+
91+
// Mark the form with an error if it is not synchronized BUT all
92+
// of its children are synchronized. If any child is not
93+
// synchronized, an error is displayed there already and showing
94+
// a second error in its parent form is pointless, or worse, may
95+
// lead to duplicate errors if error bubbling is enabled on the
96+
// child.
97+
// See also https://github.com/symfony/symfony/issues/4359
98+
if ($childrenSynchronized) {
99+
$clientDataAsString = is_scalar($form->getViewData())
100+
? (string) $form->getViewData()
101+
: gettype($form->getViewData());
102+
103+
$this->context->addViolation(
104+
$config->getOption('invalid_message'),
105+
array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')),
106+
$form->getViewData(),
107+
null,
108+
Form::ERR_INVALID
109+
);
110+
}
111+
}
112+
113+
// Mark the form with an error if it contains extra fields
114+
if (count($form->getExtraData()) > 0) {
115+
$this->context->addViolation(
116+
$config->getOption('extra_fields_message'),
117+
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
118+
$form->getExtraData()
119+
);
120+
}
121+
122+
// Mark the form with an error if the uploaded size was too large
123+
$length = $this->serverParams->getContentLength();
124+
125+
if ($form->isRoot() && null !== $length) {
126+
$max = $this->serverParams->getPostMaxSize();
127+
128+
if (!empty($max) && $length > $max) {
129+
$this->context->addViolation(
130+
$config->getOption('post_max_size_message'),
131+
array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()),
132+
$length
133+
);
134+
}
135+
}
136+
}
137+
138+
/**
139+
* Returns whether the data of a form may be walked.
140+
*
141+
* @param FormInterface $form The form to test.
142+
*
143+
* @return bool Whether the graph walker may walk the data.
144+
*/
145+
private static function allowDataWalking(FormInterface $form)
146+
{
147+
$data = $form->getData();
148+
149+
// Scalar values cannot have mapped constraints
150+
if (!is_object($data) && !is_array($data)) {
151+
return false;
152+
}
153+
154+
// Root forms are always validated
155+
if ($form->isRoot()) {
156+
return true;
157+
}
158+
159+
// Non-root forms are validated if validation cascading
160+
// is enabled in all ancestor forms
161+
while (null !== ($form = $form->getParent())) {
162+
if (!$form->getConfig()->getOption('cascade_validation')) {
163+
return false;
164+
}
165+
}
166+
167+
return true;
168+
}
169+
170+
/**
171+
* Returns the validation groups of the given form.
172+
*
173+
* @param FormInterface $form The form.
174+
*
175+
* @return array The validation groups.
176+
*/
177+
private static function getValidationGroups(FormInterface $form)
178+
{
179+
// Determine the clicked button of the complete form tree
180+
$clickedButton = null;
181+
182+
if (method_exists($form, 'getClickedButton')) {
183+
$clickedButton = $form->getClickedButton();
184+
}
185+
186+
if (null !== $clickedButton) {
187+
$groups = $clickedButton->getConfig()->getOption('validation_groups');
188+
189+
if (null !== $groups) {
190+
return self::resolveValidationGroups($groups, $form);
191+
}
192+
}
193+
194+
do {
195+
$groups = $form->getConfig()->getOption('validation_groups');
196+
197+
if (null !== $groups) {
198+
return self::resolveValidationGroups($groups, $form);
199+
}
200+
201+
$form = $form->getParent();
202+
} while (null !== $form);
203+
204+
return array(Constraint::DEFAULT_GROUP);
205+
}
206+
207+
/**
208+
* Post-processes the validation groups option for a given form.
209+
*
210+
* @param array|callable $groups The validation groups.
211+
* @param FormInterface $form The validated form.
212+
*
213+
* @return array The validation groups.
214+
*/
215+
private static function resolveValidationGroups($groups, FormInterface $form)
216+
{
217+
if (!is_string($groups) && is_callable($groups)) {
218+
$groups = call_user_func($groups, $form);
219+
}
220+
221+
return (array) $groups;
222+
}
223+
}

0 commit comments

Comments
 (0)