diff options
Diffstat (limited to 'vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php')
-rw-r--r-- | vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php new file mode 100644 index 00000000..bad5a007 --- /dev/null +++ b/vendor/symfony/form/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php | |||
@@ -0,0 +1,236 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of the Symfony package. | ||
5 | * | ||
6 | * (c) Fabien Potencier <fabien@symfony.com> | ||
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\ClickableInterface; | ||
15 | use Symfony\Component\Form\FormInterface; | ||
16 | use Symfony\Component\Form\Extension\Validator\Util\ServerParams; | ||
17 | use Symfony\Component\Validator\Constraint; | ||
18 | use Symfony\Component\Validator\ConstraintValidator; | ||
19 | |||
20 | /** | ||
21 | * @author Bernhard Schussek <bschussek@gmail.com> | ||
22 | */ | ||
23 | class FormValidator 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 (!$form instanceof FormInterface) { | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | /* @var FormInterface $form */ | ||
51 | $config = $form->getConfig(); | ||
52 | |||
53 | if ($form->isSynchronized()) { | ||
54 | // Validate the form data only if transformation succeeded | ||
55 | $groups = self::getValidationGroups($form); | ||
56 | |||
57 | // Validate the data against its own constraints | ||
58 | if (self::allowDataWalking($form)) { | ||
59 | foreach ($groups as $group) { | ||
60 | $this->context->validate($form->getData(), 'data', $group, true); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // Validate the data against the constraints defined | ||
65 | // in the form | ||
66 | $constraints = $config->getOption('constraints'); | ||
67 | foreach ($constraints as $constraint) { | ||
68 | foreach ($groups as $group) { | ||
69 | if (in_array($group, $constraint->groups)) { | ||
70 | $this->context->validateValue($form->getData(), $constraint, 'data', $group); | ||
71 | |||
72 | // Prevent duplicate validation | ||
73 | continue 2; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | } else { | ||
78 | $childrenSynchronized = true; | ||
79 | |||
80 | foreach ($form as $child) { | ||
81 | if (!$child->isSynchronized()) { | ||
82 | $childrenSynchronized = false; | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // Mark the form with an error if it is not synchronized BUT all | ||
88 | // of its children are synchronized. If any child is not | ||
89 | // synchronized, an error is displayed there already and showing | ||
90 | // a second error in its parent form is pointless, or worse, may | ||
91 | // lead to duplicate errors if error bubbling is enabled on the | ||
92 | // child. | ||
93 | // See also https://github.com/symfony/symfony/issues/4359 | ||
94 | if ($childrenSynchronized) { | ||
95 | $clientDataAsString = is_scalar($form->getViewData()) | ||
96 | ? (string) $form->getViewData() | ||
97 | : gettype($form->getViewData()); | ||
98 | |||
99 | $this->context->addViolation( | ||
100 | $config->getOption('invalid_message'), | ||
101 | array_replace(array('{{ value }}' => $clientDataAsString), $config->getOption('invalid_message_parameters')), | ||
102 | $form->getViewData(), | ||
103 | null, | ||
104 | Form::ERR_INVALID | ||
105 | ); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // Mark the form with an error if it contains extra fields | ||
110 | if (count($form->getExtraData()) > 0) { | ||
111 | $this->context->addViolation( | ||
112 | $config->getOption('extra_fields_message'), | ||
113 | array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))), | ||
114 | $form->getExtraData() | ||
115 | ); | ||
116 | } | ||
117 | |||
118 | // Mark the form with an error if the uploaded size was too large | ||
119 | $length = $this->serverParams->getContentLength(); | ||
120 | |||
121 | if ($form->isRoot() && null !== $length) { | ||
122 | $max = $this->serverParams->getPostMaxSize(); | ||
123 | |||
124 | if (!empty($max) && $length > $max) { | ||
125 | $this->context->addViolation( | ||
126 | $config->getOption('post_max_size_message'), | ||
127 | array('{{ max }}' => $this->serverParams->getNormalizedIniPostMaxSize()), | ||
128 | $length | ||
129 | ); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * Returns whether the data of a form may be walked. | ||
136 | * | ||
137 | * @param FormInterface $form The form to test. | ||
138 | * | ||
139 | * @return Boolean Whether the graph walker may walk the data. | ||
140 | */ | ||
141 | private static function allowDataWalking(FormInterface $form) | ||
142 | { | ||
143 | $data = $form->getData(); | ||
144 | |||
145 | // Scalar values cannot have mapped constraints | ||
146 | if (!is_object($data) && !is_array($data)) { | ||
147 | return false; | ||
148 | } | ||
149 | |||
150 | // Root forms are always validated | ||
151 | if ($form->isRoot()) { | ||
152 | return true; | ||
153 | } | ||
154 | |||
155 | // Non-root forms are validated if validation cascading | ||
156 | // is enabled in all ancestor forms | ||
157 | while (null !== ($form = $form->getParent())) { | ||
158 | if (!$form->getConfig()->getOption('cascade_validation')) { | ||
159 | return false; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return true; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * Returns the validation groups of the given form. | ||
168 | * | ||
169 | * @param FormInterface $form The form. | ||
170 | * | ||
171 | * @return array The validation groups. | ||
172 | */ | ||
173 | private static function getValidationGroups(FormInterface $form) | ||
174 | { | ||
175 | $button = self::findClickedButton($form->getRoot()); | ||
176 | |||
177 | if (null !== $button) { | ||
178 | $groups = $button->getConfig()->getOption('validation_groups'); | ||
179 | |||
180 | if (null !== $groups) { | ||
181 | return self::resolveValidationGroups($groups, $form); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | do { | ||
186 | $groups = $form->getConfig()->getOption('validation_groups'); | ||
187 | |||
188 | if (null !== $groups) { | ||
189 | return self::resolveValidationGroups($groups, $form); | ||
190 | } | ||
191 | |||
192 | $form = $form->getParent(); | ||
193 | } while (null !== $form); | ||
194 | |||
195 | return array(Constraint::DEFAULT_GROUP); | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * Extracts a clicked button from a form tree, if one exists. | ||
200 | * | ||
201 | * @param FormInterface $form The root form. | ||
202 | * | ||
203 | * @return ClickableInterface|null The clicked button or null. | ||
204 | */ | ||
205 | private static function findClickedButton(FormInterface $form) | ||
206 | { | ||
207 | if ($form instanceof ClickableInterface && $form->isClicked()) { | ||
208 | return $form; | ||
209 | } | ||
210 | |||
211 | foreach ($form as $child) { | ||
212 | if (null !== ($button = self::findClickedButton($child))) { | ||
213 | return $button; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | return null; | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * Post-processes the validation groups option for a given form. | ||
222 | * | ||
223 | * @param array|callable $groups The validation groups. | ||
224 | * @param FormInterface $form The validated form. | ||
225 | * | ||
226 | * @return array The validation groups. | ||
227 | */ | ||
228 | private static function resolveValidationGroups($groups, FormInterface $form) | ||
229 | { | ||
230 | if (!is_string($groups) && is_callable($groups)) { | ||
231 | $groups = call_user_func($groups, $form); | ||
232 | } | ||
233 | |||
234 | return (array) $groups; | ||
235 | } | ||
236 | } | ||