ContextualValidatorInterface.php
4 years ago
LazyProperty.php
4 years ago
RecursiveContextualValidator.php
6 months ago
RecursiveValidator.php
4 years ago
TraceableValidator.php
4 years ago
ValidatorInterface.php
4 years ago
index.php
3 years ago
RecursiveContextualValidator.php
417 lines
| 1 | <?php |
| 2 | namespace MailPoetVendor\Symfony\Component\Validator\Validator; |
| 3 | if (!defined('ABSPATH')) exit; |
| 4 | use MailPoetVendor\Symfony\Component\Validator\Constraint; |
| 5 | use MailPoetVendor\Symfony\Component\Validator\Constraints\Composite; |
| 6 | use MailPoetVendor\Symfony\Component\Validator\Constraints\Existence; |
| 7 | use MailPoetVendor\Symfony\Component\Validator\Constraints\GroupSequence; |
| 8 | use MailPoetVendor\Symfony\Component\Validator\Constraints\Valid; |
| 9 | use MailPoetVendor\Symfony\Component\Validator\ConstraintValidatorFactoryInterface; |
| 10 | use MailPoetVendor\Symfony\Component\Validator\Context\ExecutionContext; |
| 11 | use MailPoetVendor\Symfony\Component\Validator\Context\ExecutionContextInterface; |
| 12 | use MailPoetVendor\Symfony\Component\Validator\Exception\ConstraintDefinitionException; |
| 13 | use MailPoetVendor\Symfony\Component\Validator\Exception\NoSuchMetadataException; |
| 14 | use MailPoetVendor\Symfony\Component\Validator\Exception\RuntimeException; |
| 15 | use MailPoetVendor\Symfony\Component\Validator\Exception\UnexpectedValueException; |
| 16 | use MailPoetVendor\Symfony\Component\Validator\Exception\UnsupportedMetadataException; |
| 17 | use MailPoetVendor\Symfony\Component\Validator\Exception\ValidatorException; |
| 18 | use MailPoetVendor\Symfony\Component\Validator\Mapping\CascadingStrategy; |
| 19 | use MailPoetVendor\Symfony\Component\Validator\Mapping\ClassMetadataInterface; |
| 20 | use MailPoetVendor\Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; |
| 21 | use MailPoetVendor\Symfony\Component\Validator\Mapping\GenericMetadata; |
| 22 | use MailPoetVendor\Symfony\Component\Validator\Mapping\GetterMetadata; |
| 23 | use MailPoetVendor\Symfony\Component\Validator\Mapping\MetadataInterface; |
| 24 | use MailPoetVendor\Symfony\Component\Validator\Mapping\PropertyMetadataInterface; |
| 25 | use MailPoetVendor\Symfony\Component\Validator\Mapping\TraversalStrategy; |
| 26 | use MailPoetVendor\Symfony\Component\Validator\ObjectInitializerInterface; |
| 27 | use MailPoetVendor\Symfony\Component\Validator\Util\PropertyPath; |
| 28 | class RecursiveContextualValidator implements ContextualValidatorInterface |
| 29 | { |
| 30 | private $context; |
| 31 | private $defaultPropertyPath; |
| 32 | private $defaultGroups; |
| 33 | private $metadataFactory; |
| 34 | private $validatorFactory; |
| 35 | private $objectInitializers; |
| 36 | public function __construct(ExecutionContextInterface $context, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, array $objectInitializers = []) |
| 37 | { |
| 38 | $this->context = $context; |
| 39 | $this->defaultPropertyPath = $context->getPropertyPath(); |
| 40 | $this->defaultGroups = [$context->getGroup() ?: Constraint::DEFAULT_GROUP]; |
| 41 | $this->metadataFactory = $metadataFactory; |
| 42 | $this->validatorFactory = $validatorFactory; |
| 43 | $this->objectInitializers = $objectInitializers; |
| 44 | } |
| 45 | public function atPath(string $path) |
| 46 | { |
| 47 | $this->defaultPropertyPath = $this->context->getPropertyPath($path); |
| 48 | return $this; |
| 49 | } |
| 50 | public function validate($value, $constraints = null, $groups = null) |
| 51 | { |
| 52 | $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; |
| 53 | $previousValue = $this->context->getValue(); |
| 54 | $previousObject = $this->context->getObject(); |
| 55 | $previousMetadata = $this->context->getMetadata(); |
| 56 | $previousPath = $this->context->getPropertyPath(); |
| 57 | $previousGroup = $this->context->getGroup(); |
| 58 | $previousConstraint = null; |
| 59 | if ($this->context instanceof ExecutionContext || \method_exists($this->context, 'getConstraint')) { |
| 60 | $previousConstraint = $this->context->getConstraint(); |
| 61 | } |
| 62 | // If explicit constraints are passed, validate the value against |
| 63 | // those constraints |
| 64 | if (null !== $constraints) { |
| 65 | // You can pass a single constraint or an array of constraints |
| 66 | // Make sure to deal with an array in the rest of the code |
| 67 | if (!\is_array($constraints)) { |
| 68 | $constraints = [$constraints]; |
| 69 | } |
| 70 | $metadata = new GenericMetadata(); |
| 71 | $metadata->addConstraints($constraints); |
| 72 | $this->validateGenericNode($value, $previousObject, \is_object($value) ? $this->generateCacheKey($value) : null, $metadata, $this->defaultPropertyPath, $groups, null, TraversalStrategy::IMPLICIT, $this->context); |
| 73 | $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); |
| 74 | $this->context->setGroup($previousGroup); |
| 75 | if (null !== $previousConstraint) { |
| 76 | $this->context->setConstraint($previousConstraint); |
| 77 | } |
| 78 | return $this; |
| 79 | } |
| 80 | // If an object is passed without explicit constraints, validate that |
| 81 | // object against the constraints defined for the object's class |
| 82 | if (\is_object($value)) { |
| 83 | $this->validateObject($value, $this->defaultPropertyPath, $groups, TraversalStrategy::IMPLICIT, $this->context); |
| 84 | $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); |
| 85 | $this->context->setGroup($previousGroup); |
| 86 | return $this; |
| 87 | } |
| 88 | // If an array is passed without explicit constraints, validate each |
| 89 | // object in the array |
| 90 | if (\is_array($value)) { |
| 91 | $this->validateEachObjectIn($value, $this->defaultPropertyPath, $groups, $this->context); |
| 92 | $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); |
| 93 | $this->context->setGroup($previousGroup); |
| 94 | return $this; |
| 95 | } |
| 96 | throw new RuntimeException(\sprintf('Cannot validate values of type "%s" automatically. Please provide a constraint.', \get_debug_type($value))); |
| 97 | } |
| 98 | public function validateProperty(object $object, string $propertyName, $groups = null) |
| 99 | { |
| 100 | $classMetadata = $this->metadataFactory->getMetadataFor($object); |
| 101 | if (!$classMetadata instanceof ClassMetadataInterface) { |
| 102 | throw new ValidatorException(\sprintf('The metadata factory should return instances of "\\Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface", got: "%s".', \get_debug_type($classMetadata))); |
| 103 | } |
| 104 | $propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName); |
| 105 | $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; |
| 106 | $cacheKey = $this->generateCacheKey($object); |
| 107 | $propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName); |
| 108 | $previousValue = $this->context->getValue(); |
| 109 | $previousObject = $this->context->getObject(); |
| 110 | $previousMetadata = $this->context->getMetadata(); |
| 111 | $previousPath = $this->context->getPropertyPath(); |
| 112 | $previousGroup = $this->context->getGroup(); |
| 113 | foreach ($propertyMetadatas as $propertyMetadata) { |
| 114 | $propertyValue = $propertyMetadata->getPropertyValue($object); |
| 115 | $this->validateGenericNode($propertyValue, $object, $cacheKey . ':' . \get_class($object) . ':' . $propertyName, $propertyMetadata, $propertyPath, $groups, null, TraversalStrategy::IMPLICIT, $this->context); |
| 116 | } |
| 117 | $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); |
| 118 | $this->context->setGroup($previousGroup); |
| 119 | return $this; |
| 120 | } |
| 121 | public function validatePropertyValue($objectOrClass, string $propertyName, $value, $groups = null) |
| 122 | { |
| 123 | $classMetadata = $this->metadataFactory->getMetadataFor($objectOrClass); |
| 124 | if (!$classMetadata instanceof ClassMetadataInterface) { |
| 125 | throw new ValidatorException(\sprintf('The metadata factory should return instances of "\\Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface", got: "%s".', \get_debug_type($classMetadata))); |
| 126 | } |
| 127 | $propertyMetadatas = $classMetadata->getPropertyMetadata($propertyName); |
| 128 | $groups = $groups ? $this->normalizeGroups($groups) : $this->defaultGroups; |
| 129 | if (\is_object($objectOrClass)) { |
| 130 | $object = $objectOrClass; |
| 131 | $class = \get_class($object); |
| 132 | $cacheKey = $this->generateCacheKey($objectOrClass); |
| 133 | $propertyPath = PropertyPath::append($this->defaultPropertyPath, $propertyName); |
| 134 | } else { |
| 135 | // $objectOrClass contains a class ?name |
| 136 | $object = null; |
| 137 | $class = $objectOrClass; |
| 138 | $cacheKey = null; |
| 139 | $propertyPath = $this->defaultPropertyPath; |
| 140 | } |
| 141 | $previousValue = $this->context->getValue(); |
| 142 | $previousObject = $this->context->getObject(); |
| 143 | $previousMetadata = $this->context->getMetadata(); |
| 144 | $previousPath = $this->context->getPropertyPath(); |
| 145 | $previousGroup = $this->context->getGroup(); |
| 146 | foreach ($propertyMetadatas as $propertyMetadata) { |
| 147 | $this->validateGenericNode($value, $object, $cacheKey . ':' . $class . ':' . $propertyName, $propertyMetadata, $propertyPath, $groups, null, TraversalStrategy::IMPLICIT, $this->context); |
| 148 | } |
| 149 | $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); |
| 150 | $this->context->setGroup($previousGroup); |
| 151 | return $this; |
| 152 | } |
| 153 | public function getViolations() |
| 154 | { |
| 155 | return $this->context->getViolations(); |
| 156 | } |
| 157 | protected function normalizeGroups($groups) |
| 158 | { |
| 159 | if (\is_array($groups)) { |
| 160 | return $groups; |
| 161 | } |
| 162 | return [$groups]; |
| 163 | } |
| 164 | private function validateObject(object $object, string $propertyPath, array $groups, int $traversalStrategy, ExecutionContextInterface $context) |
| 165 | { |
| 166 | try { |
| 167 | $classMetadata = $this->metadataFactory->getMetadataFor($object); |
| 168 | if (!$classMetadata instanceof ClassMetadataInterface) { |
| 169 | throw new UnsupportedMetadataException(\sprintf('The metadata factory should return instances of "Symfony\\Component\\Validator\\Mapping\\ClassMetadataInterface", got: "%s".', \get_debug_type($classMetadata))); |
| 170 | } |
| 171 | $this->validateClassNode($object, $this->generateCacheKey($object), $classMetadata, $propertyPath, $groups, null, $traversalStrategy, $context); |
| 172 | } catch (NoSuchMetadataException $e) { |
| 173 | // Rethrow if not Traversable |
| 174 | if (!$object instanceof \Traversable) { |
| 175 | throw $e; |
| 176 | } |
| 177 | // Rethrow unless IMPLICIT or TRAVERSE |
| 178 | if (!($traversalStrategy & (TraversalStrategy::IMPLICIT | TraversalStrategy::TRAVERSE))) { |
| 179 | throw $e; |
| 180 | } |
| 181 | $this->validateEachObjectIn($object, $propertyPath, $groups, $context); |
| 182 | } |
| 183 | } |
| 184 | private function validateEachObjectIn(iterable $collection, string $propertyPath, array $groups, ExecutionContextInterface $context) |
| 185 | { |
| 186 | foreach ($collection as $key => $value) { |
| 187 | if (\is_array($value)) { |
| 188 | // Also traverse nested arrays |
| 189 | $this->validateEachObjectIn($value, $propertyPath . '[' . $key . ']', $groups, $context); |
| 190 | continue; |
| 191 | } |
| 192 | // Scalar and null values in the collection are ignored |
| 193 | if (\is_object($value)) { |
| 194 | $this->validateObject($value, $propertyPath . '[' . $key . ']', $groups, TraversalStrategy::IMPLICIT, $context); |
| 195 | } |
| 196 | } |
| 197 | } |
| 198 | private function validateClassNode(object $object, ?string $cacheKey, ClassMetadataInterface $metadata, string $propertyPath, array $groups, ?array $cascadedGroups, int $traversalStrategy, ExecutionContextInterface $context) |
| 199 | { |
| 200 | $context->setNode($object, $object, $metadata, $propertyPath); |
| 201 | if (!$context->isObjectInitialized($cacheKey)) { |
| 202 | foreach ($this->objectInitializers as $initializer) { |
| 203 | $initializer->initialize($object); |
| 204 | } |
| 205 | $context->markObjectAsInitialized($cacheKey); |
| 206 | } |
| 207 | foreach ($groups as $key => $group) { |
| 208 | // If the "Default" group is replaced by a group sequence, remember |
| 209 | // to cascade the "Default" group when traversing the group |
| 210 | // sequence |
| 211 | $defaultOverridden = \false; |
| 212 | // Use the object hash for group sequences |
| 213 | $groupHash = \is_object($group) ? $this->generateCacheKey($group, \true) : $group; |
| 214 | if ($context->isGroupValidated($cacheKey, $groupHash)) { |
| 215 | // Skip this group when validating the properties and when |
| 216 | // traversing the object |
| 217 | unset($groups[$key]); |
| 218 | continue; |
| 219 | } |
| 220 | $context->markGroupAsValidated($cacheKey, $groupHash); |
| 221 | // Replace the "Default" group by the group sequence defined |
| 222 | // for the class, if applicable. |
| 223 | // This is done after checking the cache, so that |
| 224 | // spl_object_hash() isn't called for this sequence and |
| 225 | // "Default" is used instead in the cache. This is useful |
| 226 | // if the getters below return different group sequences in |
| 227 | // every call. |
| 228 | if (Constraint::DEFAULT_GROUP === $group) { |
| 229 | if ($metadata->hasGroupSequence()) { |
| 230 | // The group sequence is statically defined for the class |
| 231 | $group = $metadata->getGroupSequence(); |
| 232 | $defaultOverridden = \true; |
| 233 | } elseif ($metadata->isGroupSequenceProvider()) { |
| 234 | // The group sequence is dynamically obtained from the validated |
| 235 | // object |
| 236 | $group = $object->getGroupSequence(); |
| 237 | $defaultOverridden = \true; |
| 238 | if (!$group instanceof GroupSequence) { |
| 239 | $group = new GroupSequence($group); |
| 240 | } |
| 241 | } |
| 242 | } |
| 243 | // If the groups (=[<G1,G2>,G3,G4]) contain a group sequence |
| 244 | // (=<G1,G2>), then call validateClassNode() with each entry of the |
| 245 | // group sequence and abort if necessary (G1, G2) |
| 246 | if ($group instanceof GroupSequence) { |
| 247 | $this->stepThroughGroupSequence($object, $object, $cacheKey, $metadata, $propertyPath, $traversalStrategy, $group, $defaultOverridden ? Constraint::DEFAULT_GROUP : null, $context); |
| 248 | // Skip the group sequence when validating properties, because |
| 249 | // stepThroughGroupSequence() already validates the properties |
| 250 | unset($groups[$key]); |
| 251 | continue; |
| 252 | } |
| 253 | $this->validateInGroup($object, $cacheKey, $metadata, $group, $context); |
| 254 | } |
| 255 | // If no more groups should be validated for the property nodes, |
| 256 | // we can safely quit |
| 257 | if (0 === \count($groups)) { |
| 258 | return; |
| 259 | } |
| 260 | // Validate all properties against their constraints |
| 261 | foreach ($metadata->getConstrainedProperties() as $propertyName) { |
| 262 | // If constraints are defined both on the getter of a property as |
| 263 | // well as on the property itself, then getPropertyMetadata() |
| 264 | // returns two metadata objects, not just one |
| 265 | foreach ($metadata->getPropertyMetadata($propertyName) as $propertyMetadata) { |
| 266 | if (!$propertyMetadata instanceof PropertyMetadataInterface) { |
| 267 | throw new UnsupportedMetadataException(\sprintf('The property metadata instances should implement "Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface", got: "%s".', \get_debug_type($propertyMetadata))); |
| 268 | } |
| 269 | if ($propertyMetadata instanceof GetterMetadata) { |
| 270 | $propertyValue = new LazyProperty(static function () use($propertyMetadata, $object) { |
| 271 | return $propertyMetadata->getPropertyValue($object); |
| 272 | }); |
| 273 | } else { |
| 274 | $propertyValue = $propertyMetadata->getPropertyValue($object); |
| 275 | } |
| 276 | $this->validateGenericNode($propertyValue, $object, $cacheKey . ':' . \get_class($object) . ':' . $propertyName, $propertyMetadata, PropertyPath::append($propertyPath, $propertyName), $groups, $cascadedGroups, TraversalStrategy::IMPLICIT, $context); |
| 277 | } |
| 278 | } |
| 279 | // If no specific traversal strategy was requested when this method |
| 280 | // was called, use the traversal strategy of the class' metadata |
| 281 | if ($traversalStrategy & TraversalStrategy::IMPLICIT) { |
| 282 | $traversalStrategy = $metadata->getTraversalStrategy(); |
| 283 | } |
| 284 | // Traverse only if IMPLICIT or TRAVERSE |
| 285 | if (!($traversalStrategy & (TraversalStrategy::IMPLICIT | TraversalStrategy::TRAVERSE))) { |
| 286 | return; |
| 287 | } |
| 288 | // If IMPLICIT, stop unless we deal with a Traversable |
| 289 | if ($traversalStrategy & TraversalStrategy::IMPLICIT && !$object instanceof \Traversable) { |
| 290 | return; |
| 291 | } |
| 292 | // If TRAVERSE, fail if we have no Traversable |
| 293 | if (!$object instanceof \Traversable) { |
| 294 | throw new ConstraintDefinitionException(\sprintf('Traversal was enabled for "%s", but this class does not implement "\\Traversable".', \get_debug_type($object))); |
| 295 | } |
| 296 | $this->validateEachObjectIn($object, $propertyPath, $groups, $context); |
| 297 | } |
| 298 | private function validateGenericNode($value, ?object $object, ?string $cacheKey, ?MetadataInterface $metadata, string $propertyPath, array $groups, ?array $cascadedGroups, int $traversalStrategy, ExecutionContextInterface $context) |
| 299 | { |
| 300 | $context->setNode($value, $object, $metadata, $propertyPath); |
| 301 | foreach ($groups as $key => $group) { |
| 302 | if ($group instanceof GroupSequence) { |
| 303 | $this->stepThroughGroupSequence($value, $object, $cacheKey, $metadata, $propertyPath, $traversalStrategy, $group, null, $context); |
| 304 | // Skip the group sequence when cascading, as the cascading |
| 305 | // logic is already done in stepThroughGroupSequence() |
| 306 | unset($groups[$key]); |
| 307 | continue; |
| 308 | } |
| 309 | $this->validateInGroup($value, $cacheKey, $metadata, $group, $context); |
| 310 | } |
| 311 | if (0 === \count($groups)) { |
| 312 | return; |
| 313 | } |
| 314 | if (null === $value) { |
| 315 | return; |
| 316 | } |
| 317 | $cascadingStrategy = $metadata->getCascadingStrategy(); |
| 318 | // Quit unless we cascade |
| 319 | if (!($cascadingStrategy & CascadingStrategy::CASCADE)) { |
| 320 | return; |
| 321 | } |
| 322 | // If no specific traversal strategy was requested when this method |
| 323 | // was called, use the traversal strategy of the node's metadata |
| 324 | if ($traversalStrategy & TraversalStrategy::IMPLICIT) { |
| 325 | $traversalStrategy = $metadata->getTraversalStrategy(); |
| 326 | } |
| 327 | // The $cascadedGroups property is set, if the "Default" group is |
| 328 | // overridden by a group sequence |
| 329 | // See validateClassNode() |
| 330 | $cascadedGroups = null !== $cascadedGroups && \count($cascadedGroups) > 0 ? $cascadedGroups : $groups; |
| 331 | if ($value instanceof LazyProperty) { |
| 332 | $value = $value->getPropertyValue(); |
| 333 | if (null === $value) { |
| 334 | return; |
| 335 | } |
| 336 | } |
| 337 | if (\is_array($value)) { |
| 338 | // Arrays are always traversed, independent of the specified |
| 339 | // traversal strategy |
| 340 | $this->validateEachObjectIn($value, $propertyPath, $cascadedGroups, $context); |
| 341 | return; |
| 342 | } |
| 343 | if (!\is_object($value)) { |
| 344 | throw new NoSuchMetadataException(\sprintf('Cannot create metadata for non-objects. Got: "%s".', \gettype($value))); |
| 345 | } |
| 346 | $this->validateObject($value, $propertyPath, $cascadedGroups, $traversalStrategy, $context); |
| 347 | // Currently, the traversal strategy can only be TRAVERSE for a |
| 348 | // generic node if the cascading strategy is CASCADE. Thus, traversable |
| 349 | // objects will always be handled within validateObject() and there's |
| 350 | // nothing more to do here. |
| 351 | // see GenericMetadata::addConstraint() |
| 352 | } |
| 353 | private function stepThroughGroupSequence($value, ?object $object, ?string $cacheKey, ?MetadataInterface $metadata, string $propertyPath, int $traversalStrategy, GroupSequence $groupSequence, ?string $cascadedGroup, ExecutionContextInterface $context) |
| 354 | { |
| 355 | $violationCount = \count($context->getViolations()); |
| 356 | $cascadedGroups = $cascadedGroup ? [$cascadedGroup] : null; |
| 357 | foreach ($groupSequence->groups as $groupInSequence) { |
| 358 | $groups = (array) $groupInSequence; |
| 359 | if ($metadata instanceof ClassMetadataInterface) { |
| 360 | $this->validateClassNode($value, $cacheKey, $metadata, $propertyPath, $groups, $cascadedGroups, $traversalStrategy, $context); |
| 361 | } else { |
| 362 | $this->validateGenericNode($value, $object, $cacheKey, $metadata, $propertyPath, $groups, $cascadedGroups, $traversalStrategy, $context); |
| 363 | } |
| 364 | // Abort sequence validation if a violation was generated |
| 365 | if (\count($context->getViolations()) > $violationCount) { |
| 366 | break; |
| 367 | } |
| 368 | } |
| 369 | } |
| 370 | private function validateInGroup($value, ?string $cacheKey, MetadataInterface $metadata, string $group, ExecutionContextInterface $context) |
| 371 | { |
| 372 | $context->setGroup($group); |
| 373 | foreach ($metadata->findConstraints($group) as $constraint) { |
| 374 | if ($constraint instanceof Existence) { |
| 375 | continue; |
| 376 | } |
| 377 | // Prevent duplicate validation of constraints, in the case |
| 378 | // that constraints belong to multiple validated groups |
| 379 | if (null !== $cacheKey) { |
| 380 | $constraintHash = $this->generateCacheKey($constraint, \true); |
| 381 | // instanceof Valid: In case of using a Valid constraint with many groups |
| 382 | // it makes a reference object get validated by each group |
| 383 | if ($constraint instanceof Composite || $constraint instanceof Valid) { |
| 384 | $constraintHash .= $group; |
| 385 | } |
| 386 | if ($context->isConstraintValidated($cacheKey, $constraintHash)) { |
| 387 | continue; |
| 388 | } |
| 389 | $context->markConstraintAsValidated($cacheKey, $constraintHash); |
| 390 | } |
| 391 | $context->setConstraint($constraint); |
| 392 | $validator = $this->validatorFactory->getInstance($constraint); |
| 393 | $validator->initialize($context); |
| 394 | if ($value instanceof LazyProperty) { |
| 395 | $value = $value->getPropertyValue(); |
| 396 | } |
| 397 | try { |
| 398 | $validator->validate($value, $constraint); |
| 399 | } catch (UnexpectedValueException $e) { |
| 400 | $context->buildViolation('This value should be of type {{ type }}.')->setParameter('{{ type }}', $e->getExpectedType())->addViolation(); |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | private function generateCacheKey(object $object, bool $dependsOnPropertyPath = \false) : string |
| 405 | { |
| 406 | if ($this->context instanceof ExecutionContext) { |
| 407 | $cacheKey = $this->context->generateCacheKey($object); |
| 408 | } else { |
| 409 | $cacheKey = \spl_object_hash($object); |
| 410 | } |
| 411 | if ($dependsOnPropertyPath) { |
| 412 | $cacheKey .= $this->context->getPropertyPath(); |
| 413 | } |
| 414 | return $cacheKey; |
| 415 | } |
| 416 | } |
| 417 |