Mercurial > hg > cmmr2012-drupal-site
comparison vendor/symfony/validator/Validator/RecursiveContextualValidator.php @ 4:a9cd425dd02b
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:11:55 +0000 |
parents | c75dbcec494b |
children | 12f9dff5fda9 |
comparison
equal
deleted
inserted
replaced
3:307d7a7fd348 | 4:a9cd425dd02b |
---|---|
10 */ | 10 */ |
11 | 11 |
12 namespace Symfony\Component\Validator\Validator; | 12 namespace Symfony\Component\Validator\Validator; |
13 | 13 |
14 use Symfony\Component\Validator\Constraint; | 14 use Symfony\Component\Validator\Constraint; |
15 use Symfony\Component\Validator\Constraints\Composite; | |
15 use Symfony\Component\Validator\Constraints\GroupSequence; | 16 use Symfony\Component\Validator\Constraints\GroupSequence; |
16 use Symfony\Component\Validator\ConstraintValidatorFactoryInterface; | 17 use Symfony\Component\Validator\ConstraintValidatorFactoryInterface; |
17 use Symfony\Component\Validator\Context\ExecutionContext; | 18 use Symfony\Component\Validator\Context\ExecutionContext; |
18 use Symfony\Component\Validator\Context\ExecutionContextInterface; | 19 use Symfony\Component\Validator\Context\ExecutionContextInterface; |
19 use Symfony\Component\Validator\Exception\ConstraintDefinitionException; | 20 use Symfony\Component\Validator\Exception\ConstraintDefinitionException; |
21 use Symfony\Component\Validator\Exception\RuntimeException; | 22 use Symfony\Component\Validator\Exception\RuntimeException; |
22 use Symfony\Component\Validator\Exception\UnsupportedMetadataException; | 23 use Symfony\Component\Validator\Exception\UnsupportedMetadataException; |
23 use Symfony\Component\Validator\Exception\ValidatorException; | 24 use Symfony\Component\Validator\Exception\ValidatorException; |
24 use Symfony\Component\Validator\Mapping\CascadingStrategy; | 25 use Symfony\Component\Validator\Mapping\CascadingStrategy; |
25 use Symfony\Component\Validator\Mapping\ClassMetadataInterface; | 26 use Symfony\Component\Validator\Mapping\ClassMetadataInterface; |
27 use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; | |
26 use Symfony\Component\Validator\Mapping\GenericMetadata; | 28 use Symfony\Component\Validator\Mapping\GenericMetadata; |
27 use Symfony\Component\Validator\Mapping\MetadataInterface; | 29 use Symfony\Component\Validator\Mapping\MetadataInterface; |
28 use Symfony\Component\Validator\Mapping\PropertyMetadataInterface; | 30 use Symfony\Component\Validator\Mapping\PropertyMetadataInterface; |
29 use Symfony\Component\Validator\Mapping\TraversalStrategy; | 31 use Symfony\Component\Validator\Mapping\TraversalStrategy; |
30 use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; | |
31 use Symfony\Component\Validator\ObjectInitializerInterface; | 32 use Symfony\Component\Validator\ObjectInitializerInterface; |
32 use Symfony\Component\Validator\Util\PropertyPath; | 33 use Symfony\Component\Validator\Util\PropertyPath; |
33 | 34 |
34 /** | 35 /** |
35 * Recursive implementation of {@link ContextualValidatorInterface}. | 36 * Recursive implementation of {@link ContextualValidatorInterface}. |
54 * of validated objects | 55 * of validated objects |
55 * @param ConstraintValidatorFactoryInterface $validatorFactory The factory for creating | 56 * @param ConstraintValidatorFactoryInterface $validatorFactory The factory for creating |
56 * constraint validators | 57 * constraint validators |
57 * @param ObjectInitializerInterface[] $objectInitializers The object initializers | 58 * @param ObjectInitializerInterface[] $objectInitializers The object initializers |
58 */ | 59 */ |
59 public function __construct(ExecutionContextInterface $context, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, array $objectInitializers = array()) | 60 public function __construct(ExecutionContextInterface $context, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, array $objectInitializers = []) |
60 { | 61 { |
61 $this->context = $context; | 62 $this->context = $context; |
62 $this->defaultPropertyPath = $context->getPropertyPath(); | 63 $this->defaultPropertyPath = $context->getPropertyPath(); |
63 $this->defaultGroups = array($context->getGroup() ?: Constraint::DEFAULT_GROUP); | 64 $this->defaultGroups = [$context->getGroup() ?: Constraint::DEFAULT_GROUP]; |
64 $this->metadataFactory = $metadataFactory; | 65 $this->metadataFactory = $metadataFactory; |
65 $this->validatorFactory = $validatorFactory; | 66 $this->validatorFactory = $validatorFactory; |
66 $this->objectInitializers = $objectInitializers; | 67 $this->objectInitializers = $objectInitializers; |
67 } | 68 } |
68 | 69 |
97 // If explicit constraints are passed, validate the value against | 98 // If explicit constraints are passed, validate the value against |
98 // those constraints | 99 // those constraints |
99 if (null !== $constraints) { | 100 if (null !== $constraints) { |
100 // You can pass a single constraint or an array of constraints | 101 // You can pass a single constraint or an array of constraints |
101 // Make sure to deal with an array in the rest of the code | 102 // Make sure to deal with an array in the rest of the code |
102 if (!is_array($constraints)) { | 103 if (!\is_array($constraints)) { |
103 $constraints = array($constraints); | 104 $constraints = [$constraints]; |
104 } | 105 } |
105 | 106 |
106 $metadata = new GenericMetadata(); | 107 $metadata = new GenericMetadata(); |
107 $metadata->addConstraints($constraints); | 108 $metadata->addConstraints($constraints); |
108 | 109 |
109 $this->validateGenericNode( | 110 $this->validateGenericNode( |
110 $value, | 111 $value, |
111 $previousObject, | 112 $previousObject, |
112 is_object($value) ? spl_object_hash($value) : null, | 113 \is_object($value) ? spl_object_hash($value) : null, |
113 $metadata, | 114 $metadata, |
114 $this->defaultPropertyPath, | 115 $this->defaultPropertyPath, |
115 $groups, | 116 $groups, |
116 null, | 117 null, |
117 TraversalStrategy::IMPLICIT, | 118 TraversalStrategy::IMPLICIT, |
128 return $this; | 129 return $this; |
129 } | 130 } |
130 | 131 |
131 // If an object is passed without explicit constraints, validate that | 132 // If an object is passed without explicit constraints, validate that |
132 // object against the constraints defined for the object's class | 133 // object against the constraints defined for the object's class |
133 if (is_object($value)) { | 134 if (\is_object($value)) { |
134 $this->validateObject( | 135 $this->validateObject( |
135 $value, | 136 $value, |
136 $this->defaultPropertyPath, | 137 $this->defaultPropertyPath, |
137 $groups, | 138 $groups, |
138 TraversalStrategy::IMPLICIT, | 139 TraversalStrategy::IMPLICIT, |
145 return $this; | 146 return $this; |
146 } | 147 } |
147 | 148 |
148 // If an array is passed without explicit constraints, validate each | 149 // If an array is passed without explicit constraints, validate each |
149 // object in the array | 150 // object in the array |
150 if (is_array($value)) { | 151 if (\is_array($value)) { |
151 $this->validateEachObjectIn( | 152 $this->validateEachObjectIn( |
152 $value, | 153 $value, |
153 $this->defaultPropertyPath, | 154 $this->defaultPropertyPath, |
154 $groups, | 155 $groups, |
155 $this->context | 156 $this->context |
159 $this->context->setGroup($previousGroup); | 160 $this->context->setGroup($previousGroup); |
160 | 161 |
161 return $this; | 162 return $this; |
162 } | 163 } |
163 | 164 |
164 throw new RuntimeException(sprintf( | 165 throw new RuntimeException(sprintf('Cannot validate values of type "%s" automatically. Please provide a constraint.', \gettype($value))); |
165 'Cannot validate values of type "%s" automatically. Please '. | |
166 'provide a constraint.', | |
167 gettype($value) | |
168 )); | |
169 } | 166 } |
170 | 167 |
171 /** | 168 /** |
172 * {@inheritdoc} | 169 * {@inheritdoc} |
173 */ | 170 */ |
174 public function validateProperty($object, $propertyName, $groups = null) | 171 public function validateProperty($object, $propertyName, $groups = null) |
175 { | 172 { |
176 $classMetadata = $this->metadataFactory->getMetadataFor($object); | 173 $classMetadata = $this->metadataFactory->getMetadataFor($object); |
177 | 174 |
178 if (!$classMetadata instanceof ClassMetadataInterface) { | 175 if (!$classMetadata instanceof ClassMetadataInterface) { |
179 throw new ValidatorException(sprintf( | 176 throw new ValidatorException(sprintf('The metadata factory should return instances of "\Symfony\Component\Validator\Mapping\ClassMetadataInterface", got: "%s".', \is_object($classMetadata) ? \get_class($classMetadata) : \gettype($classMetadata))); |
180 'The metadata factory should return instances of '. | |
181 '"\Symfony\Component\Validator\Mapping\ClassMetadataInterface", '. | |
182 'got: "%s".', | |
183 is_object($classMetadata) ? get_class($classMetadata) : gettype($classMetadata) | |
184 )); | |
185 } | 177 } |
186 | 178 |
187 $propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName); | 179 $propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName); |
188 $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; | 180 $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; |
189 $cacheKey = spl_object_hash($object); | 181 $cacheKey = spl_object_hash($object); |
199 $propertyValue = $propertyMetadata->getPropertyValue($object); | 191 $propertyValue = $propertyMetadata->getPropertyValue($object); |
200 | 192 |
201 $this->validateGenericNode( | 193 $this->validateGenericNode( |
202 $propertyValue, | 194 $propertyValue, |
203 $object, | 195 $object, |
204 $cacheKey.':'.get_class($object).':'.$propertyName, | 196 $cacheKey.':'.\get_class($object).':'.$propertyName, |
205 $propertyMetadata, | 197 $propertyMetadata, |
206 $propertyPath, | 198 $propertyPath, |
207 $groups, | 199 $groups, |
208 null, | 200 null, |
209 TraversalStrategy::IMPLICIT, | 201 TraversalStrategy::IMPLICIT, |
223 public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null) | 215 public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null) |
224 { | 216 { |
225 $classMetadata = $this->metadataFactory->getMetadataFor($objectOrClass); | 217 $classMetadata = $this->metadataFactory->getMetadataFor($objectOrClass); |
226 | 218 |
227 if (!$classMetadata instanceof ClassMetadataInterface) { | 219 if (!$classMetadata instanceof ClassMetadataInterface) { |
228 throw new ValidatorException(sprintf( | 220 throw new ValidatorException(sprintf('The metadata factory should return instances of "\Symfony\Component\Validator\Mapping\ClassMetadataInterface", got: "%s".', \is_object($classMetadata) ? \get_class($classMetadata) : \gettype($classMetadata))); |
229 'The metadata factory should return instances of '. | |
230 '"\Symfony\Component\Validator\Mapping\ClassMetadataInterface", '. | |
231 'got: "%s".', | |
232 is_object($classMetadata) ? get_class($classMetadata) : gettype($classMetadata) | |
233 )); | |
234 } | 221 } |
235 | 222 |
236 $propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName); | 223 $propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName); |
237 $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; | 224 $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; |
238 | 225 |
239 if (is_object($objectOrClass)) { | 226 if (\is_object($objectOrClass)) { |
240 $object = $objectOrClass; | 227 $object = $objectOrClass; |
241 $class = get_class($object); | 228 $class = \get_class($object); |
242 $cacheKey = spl_object_hash($objectOrClass); | 229 $cacheKey = spl_object_hash($objectOrClass); |
243 $propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName); | 230 $propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName); |
244 } else { | 231 } else { |
245 // $objectOrClass contains a class name | 232 // $objectOrClass contains a class name |
246 $object = null; | 233 $object = null; |
284 } | 271 } |
285 | 272 |
286 /** | 273 /** |
287 * Normalizes the given group or list of groups to an array. | 274 * Normalizes the given group or list of groups to an array. |
288 * | 275 * |
289 * @param mixed $groups The groups to normalize | 276 * @param string|GroupSequence|(string|GroupSequence)[] $groups The groups to normalize |
290 * | 277 * |
291 * @return array A group array | 278 * @return (string|GroupSequence)[] A group array |
292 */ | 279 */ |
293 protected function normalizeGroups($groups) | 280 protected function normalizeGroups($groups) |
294 { | 281 { |
295 if (is_array($groups)) { | 282 if (\is_array($groups)) { |
296 return $groups; | 283 return $groups; |
297 } | 284 } |
298 | 285 |
299 return array($groups); | 286 return [$groups]; |
300 } | 287 } |
301 | 288 |
302 /** | 289 /** |
303 * Validates an object against the constraints defined for its class. | 290 * Validates an object against the constraints defined for its class. |
304 * | 291 * |
307 * traversal, the object will be iterated and each nested object will be | 294 * traversal, the object will be iterated and each nested object will be |
308 * validated instead. | 295 * validated instead. |
309 * | 296 * |
310 * @param object $object The object to cascade | 297 * @param object $object The object to cascade |
311 * @param string $propertyPath The current property path | 298 * @param string $propertyPath The current property path |
312 * @param string[] $groups The validated groups | 299 * @param (string|GroupSequence)[] $groups The validated groups |
313 * @param int $traversalStrategy The strategy for traversing the | 300 * @param int $traversalStrategy The strategy for traversing the |
314 * cascaded object | 301 * cascaded object |
315 * @param ExecutionContextInterface $context The current execution context | 302 * @param ExecutionContextInterface $context The current execution context |
316 * | 303 * |
317 * @throws NoSuchMetadataException If the object has no associated metadata | 304 * @throws NoSuchMetadataException If the object has no associated metadata |
326 { | 313 { |
327 try { | 314 try { |
328 $classMetadata = $this->metadataFactory->getMetadataFor($object); | 315 $classMetadata = $this->metadataFactory->getMetadataFor($object); |
329 | 316 |
330 if (!$classMetadata instanceof ClassMetadataInterface) { | 317 if (!$classMetadata instanceof ClassMetadataInterface) { |
331 throw new UnsupportedMetadataException(sprintf( | 318 throw new UnsupportedMetadataException(sprintf('The metadata factory should return instances of "Symfony\Component\Validator\Mapping\ClassMetadataInterface", got: "%s".', \is_object($classMetadata) ? \get_class($classMetadata) : \gettype($classMetadata))); |
332 'The metadata factory should return instances of '. | |
333 '"Symfony\Component\Validator\Mapping\ClassMetadataInterface", '. | |
334 'got: "%s".', | |
335 is_object($classMetadata) ? get_class($classMetadata) : gettype($classMetadata) | |
336 )); | |
337 } | 319 } |
338 | 320 |
339 $this->validateClassNode( | 321 $this->validateClassNode( |
340 $object, | 322 $object, |
341 spl_object_hash($object), | 323 spl_object_hash($object), |
374 * objects are iterated as well. Nested arrays are always iterated, | 356 * objects are iterated as well. Nested arrays are always iterated, |
375 * regardless of the value of $recursive. | 357 * regardless of the value of $recursive. |
376 * | 358 * |
377 * @param iterable $collection The collection | 359 * @param iterable $collection The collection |
378 * @param string $propertyPath The current property path | 360 * @param string $propertyPath The current property path |
379 * @param string[] $groups The validated groups | 361 * @param (string|GroupSequence)[] $groups The validated groups |
380 * @param ExecutionContextInterface $context The current execution context | 362 * @param ExecutionContextInterface $context The current execution context |
381 * | 363 * |
382 * @see ClassNode | 364 * @see ClassNode |
383 * @see CollectionNode | 365 * @see CollectionNode |
384 */ | 366 */ |
385 private function validateEachObjectIn($collection, $propertyPath, array $groups, ExecutionContextInterface $context) | 367 private function validateEachObjectIn($collection, $propertyPath, array $groups, ExecutionContextInterface $context) |
386 { | 368 { |
387 foreach ($collection as $key => $value) { | 369 foreach ($collection as $key => $value) { |
388 if (is_array($value)) { | 370 if (\is_array($value)) { |
389 // Arrays are always cascaded, independent of the specified | 371 // Arrays are always cascaded, independent of the specified |
390 // traversal strategy | 372 // traversal strategy |
391 $this->validateEachObjectIn( | 373 $this->validateEachObjectIn( |
392 $value, | 374 $value, |
393 $propertyPath.'['.$key.']', | 375 $propertyPath.'['.$key.']', |
397 | 379 |
398 continue; | 380 continue; |
399 } | 381 } |
400 | 382 |
401 // Scalar and null values in the collection are ignored | 383 // Scalar and null values in the collection are ignored |
402 if (is_object($value)) { | 384 if (\is_object($value)) { |
403 $this->validateObject( | 385 $this->validateObject( |
404 $value, | 386 $value, |
405 $propertyPath.'['.$key.']', | 387 $propertyPath.'['.$key.']', |
406 $groups, | 388 $groups, |
407 TraversalStrategy::IMPLICIT, | 389 TraversalStrategy::IMPLICIT, |
441 * the validated object | 423 * the validated object |
442 * @param ClassMetadataInterface $metadata The class metadata of | 424 * @param ClassMetadataInterface $metadata The class metadata of |
443 * the object | 425 * the object |
444 * @param string $propertyPath The property path leading | 426 * @param string $propertyPath The property path leading |
445 * to the object | 427 * to the object |
446 * @param string[] $groups The groups in which the | 428 * @param (string|GroupSequence)[] $groups The groups in which the |
447 * object should be validated | 429 * object should be validated |
448 * @param string[]|null $cascadedGroups The groups in which | 430 * @param string[]|null $cascadedGroups The groups in which |
449 * cascaded objects should | 431 * cascaded objects should |
450 * be validated | 432 * be validated |
451 * @param int $traversalStrategy The strategy used for | 433 * @param int $traversalStrategy The strategy used for |
477 // to cascade the "Default" group when traversing the group | 459 // to cascade the "Default" group when traversing the group |
478 // sequence | 460 // sequence |
479 $defaultOverridden = false; | 461 $defaultOverridden = false; |
480 | 462 |
481 // Use the object hash for group sequences | 463 // Use the object hash for group sequences |
482 $groupHash = is_object($group) ? spl_object_hash($group) : $group; | 464 $groupHash = \is_object($group) ? spl_object_hash($group) : $group; |
483 | 465 |
484 if ($context->isGroupValidated($cacheKey, $groupHash)) { | 466 if ($context->isGroupValidated($cacheKey, $groupHash)) { |
485 // Skip this group when validating the properties and when | 467 // Skip this group when validating the properties and when |
486 // traversing the object | 468 // traversing the object |
487 unset($groups[$key]); | 469 unset($groups[$key]); |
542 $this->validateInGroup($object, $cacheKey, $metadata, $group, $context); | 524 $this->validateInGroup($object, $cacheKey, $metadata, $group, $context); |
543 } | 525 } |
544 | 526 |
545 // If no more groups should be validated for the property nodes, | 527 // If no more groups should be validated for the property nodes, |
546 // we can safely quit | 528 // we can safely quit |
547 if (0 === count($groups)) { | 529 if (0 === \count($groups)) { |
548 return; | 530 return; |
549 } | 531 } |
550 | 532 |
551 // Validate all properties against their constraints | 533 // Validate all properties against their constraints |
552 foreach ($metadata->getConstrainedProperties() as $propertyName) { | 534 foreach ($metadata->getConstrainedProperties() as $propertyName) { |
553 // If constraints are defined both on the getter of a property as | 535 // If constraints are defined both on the getter of a property as |
554 // well as on the property itself, then getPropertyMetadata() | 536 // well as on the property itself, then getPropertyMetadata() |
555 // returns two metadata objects, not just one | 537 // returns two metadata objects, not just one |
556 foreach ($metadata->getPropertyMetadata($propertyName) as $propertyMetadata) { | 538 foreach ($metadata->getPropertyMetadata($propertyName) as $propertyMetadata) { |
557 if (!$propertyMetadata instanceof PropertyMetadataInterface) { | 539 if (!$propertyMetadata instanceof PropertyMetadataInterface) { |
558 throw new UnsupportedMetadataException(sprintf( | 540 throw new UnsupportedMetadataException(sprintf('The property metadata instances should implement "Symfony\Component\Validator\Mapping\PropertyMetadataInterface", got: "%s".', \is_object($propertyMetadata) ? \get_class($propertyMetadata) : \gettype($propertyMetadata))); |
559 'The property metadata instances should implement '. | |
560 '"Symfony\Component\Validator\Mapping\PropertyMetadataInterface", '. | |
561 'got: "%s".', | |
562 is_object($propertyMetadata) ? get_class($propertyMetadata) : gettype($propertyMetadata) | |
563 )); | |
564 } | 541 } |
565 | 542 |
566 $propertyValue = $propertyMetadata->getPropertyValue($object); | 543 $propertyValue = $propertyMetadata->getPropertyValue($object); |
567 | 544 |
568 $this->validateGenericNode( | 545 $this->validateGenericNode( |
569 $propertyValue, | 546 $propertyValue, |
570 $object, | 547 $object, |
571 $cacheKey.':'.get_class($object).':'.$propertyName, | 548 $cacheKey.':'.\get_class($object).':'.$propertyName, |
572 $propertyMetadata, | 549 $propertyMetadata, |
573 PropertyPath::append($propertyPath, $propertyName), | 550 PropertyPath::append($propertyPath, $propertyName), |
574 $groups, | 551 $groups, |
575 $cascadedGroups, | 552 $cascadedGroups, |
576 TraversalStrategy::IMPLICIT, | 553 TraversalStrategy::IMPLICIT, |
595 return; | 572 return; |
596 } | 573 } |
597 | 574 |
598 // If TRAVERSE, fail if we have no Traversable | 575 // If TRAVERSE, fail if we have no Traversable |
599 if (!$object instanceof \Traversable) { | 576 if (!$object instanceof \Traversable) { |
600 throw new ConstraintDefinitionException(sprintf( | 577 throw new ConstraintDefinitionException(sprintf('Traversal was enabled for "%s", but this class does not implement "\Traversable".', \get_class($object))); |
601 'Traversal was enabled for "%s", but this class '. | |
602 'does not implement "\Traversable".', | |
603 get_class($object) | |
604 )); | |
605 } | 578 } |
606 | 579 |
607 $this->validateEachObjectIn( | 580 $this->validateEachObjectIn( |
608 $object, | 581 $object, |
609 $propertyPath, | 582 $propertyPath, |
634 * the validated value | 607 * the validated value |
635 * @param MetadataInterface $metadata The metadata of the | 608 * @param MetadataInterface $metadata The metadata of the |
636 * value | 609 * value |
637 * @param string $propertyPath The property path leading | 610 * @param string $propertyPath The property path leading |
638 * to the value | 611 * to the value |
639 * @param string[] $groups The groups in which the | 612 * @param (string|GroupSequence)[] $groups The groups in which the |
640 * value should be validated | 613 * value should be validated |
641 * @param string[]|null $cascadedGroups The groups in which | 614 * @param string[]|null $cascadedGroups The groups in which |
642 * cascaded objects should | 615 * cascaded objects should |
643 * be validated | 616 * be validated |
644 * @param int $traversalStrategy The strategy used for | 617 * @param int $traversalStrategy The strategy used for |
673 } | 646 } |
674 | 647 |
675 $this->validateInGroup($value, $cacheKey, $metadata, $group, $context); | 648 $this->validateInGroup($value, $cacheKey, $metadata, $group, $context); |
676 } | 649 } |
677 | 650 |
678 if (0 === count($groups)) { | 651 if (0 === \count($groups)) { |
679 return; | 652 return; |
680 } | 653 } |
681 | 654 |
682 if (null === $value) { | 655 if (null === $value) { |
683 return; | 656 return; |
684 } | 657 } |
685 | 658 |
686 $cascadingStrategy = $metadata->getCascadingStrategy(); | 659 $cascadingStrategy = $metadata->getCascadingStrategy(); |
687 | 660 |
688 // Quit unless we have an array or a cascaded object | 661 // Quit unless we have an array or a cascaded object |
689 if (!is_array($value) && !($cascadingStrategy & CascadingStrategy::CASCADE)) { | 662 if (!\is_array($value) && !($cascadingStrategy & CascadingStrategy::CASCADE)) { |
690 return; | 663 return; |
691 } | 664 } |
692 | 665 |
693 // If no specific traversal strategy was requested when this method | 666 // If no specific traversal strategy was requested when this method |
694 // was called, use the traversal strategy of the node's metadata | 667 // was called, use the traversal strategy of the node's metadata |
697 } | 670 } |
698 | 671 |
699 // The $cascadedGroups property is set, if the "Default" group is | 672 // The $cascadedGroups property is set, if the "Default" group is |
700 // overridden by a group sequence | 673 // overridden by a group sequence |
701 // See validateClassNode() | 674 // See validateClassNode() |
702 $cascadedGroups = null !== $cascadedGroups && count($cascadedGroups) > 0 ? $cascadedGroups : $groups; | 675 $cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups; |
703 | 676 |
704 if (is_array($value)) { | 677 if (\is_array($value)) { |
705 // Arrays are always traversed, independent of the specified | 678 // Arrays are always traversed, independent of the specified |
706 // traversal strategy | 679 // traversal strategy |
707 $this->validateEachObjectIn( | 680 $this->validateEachObjectIn( |
708 $value, | 681 $value, |
709 $propertyPath, | 682 $propertyPath, |
755 * the group sequence | 728 * the group sequence |
756 * @param ExecutionContextInterface $context The execution context | 729 * @param ExecutionContextInterface $context The execution context |
757 */ | 730 */ |
758 private function stepThroughGroupSequence($value, $object, $cacheKey, MetadataInterface $metadata = null, $propertyPath, $traversalStrategy, GroupSequence $groupSequence, $cascadedGroup, ExecutionContextInterface $context) | 731 private function stepThroughGroupSequence($value, $object, $cacheKey, MetadataInterface $metadata = null, $propertyPath, $traversalStrategy, GroupSequence $groupSequence, $cascadedGroup, ExecutionContextInterface $context) |
759 { | 732 { |
760 $violationCount = count($context->getViolations()); | 733 $violationCount = \count($context->getViolations()); |
761 $cascadedGroups = $cascadedGroup ? array($cascadedGroup) : null; | 734 $cascadedGroups = $cascadedGroup ? [$cascadedGroup] : null; |
762 | 735 |
763 foreach ($groupSequence->groups as $groupInSequence) { | 736 foreach ($groupSequence->groups as $groupInSequence) { |
764 $groups = (array) $groupInSequence; | 737 $groups = (array) $groupInSequence; |
765 | 738 |
766 if ($metadata instanceof ClassMetadataInterface) { | 739 if ($metadata instanceof ClassMetadataInterface) { |
787 $context | 760 $context |
788 ); | 761 ); |
789 } | 762 } |
790 | 763 |
791 // Abort sequence validation if a violation was generated | 764 // Abort sequence validation if a violation was generated |
792 if (count($context->getViolations()) > $violationCount) { | 765 if (\count($context->getViolations()) > $violationCount) { |
793 break; | 766 break; |
794 } | 767 } |
795 } | 768 } |
796 } | 769 } |
797 | 770 |
813 // Prevent duplicate validation of constraints, in the case | 786 // Prevent duplicate validation of constraints, in the case |
814 // that constraints belong to multiple validated groups | 787 // that constraints belong to multiple validated groups |
815 if (null !== $cacheKey) { | 788 if (null !== $cacheKey) { |
816 $constraintHash = spl_object_hash($constraint); | 789 $constraintHash = spl_object_hash($constraint); |
817 | 790 |
791 if ($constraint instanceof Composite) { | |
792 $constraintHash .= $group; | |
793 } | |
794 | |
818 if ($context->isConstraintValidated($cacheKey, $constraintHash)) { | 795 if ($context->isConstraintValidated($cacheKey, $constraintHash)) { |
819 continue; | 796 continue; |
820 } | 797 } |
821 | 798 |
822 $context->markConstraintAsValidated($cacheKey, $constraintHash); | 799 $context->markConstraintAsValidated($cacheKey, $constraintHash); |