annotate vendor/symfony/validator/Mapping/ClassMetadata.php @ 14:1fec387a4317

Update Drupal core to 8.5.2 via Composer
author Chris Cannam
date Mon, 23 Apr 2018 09:46:53 +0100
parents 4c8ae668cc8c
children c2387f117808
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Validator\Mapping;
Chris@0 13
Chris@0 14 use Symfony\Component\Validator\Constraint;
Chris@0 15 use Symfony\Component\Validator\Constraints\GroupSequence;
Chris@0 16 use Symfony\Component\Validator\Constraints\Traverse;
Chris@0 17 use Symfony\Component\Validator\Constraints\Valid;
Chris@0 18 use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
Chris@0 19 use Symfony\Component\Validator\Exception\GroupDefinitionException;
Chris@0 20
Chris@0 21 /**
Chris@0 22 * Default implementation of {@link ClassMetadataInterface}.
Chris@0 23 *
Chris@0 24 * This class supports serialization and cloning.
Chris@0 25 *
Chris@0 26 * @author Bernhard Schussek <bschussek@gmail.com>
Chris@0 27 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 28 */
Chris@0 29 class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
Chris@0 30 {
Chris@0 31 /**
Chris@0 32 * @var string
Chris@0 33 *
Chris@0 34 * @internal This property is public in order to reduce the size of the
Chris@0 35 * class' serialized representation. Do not access it. Use
Chris@0 36 * {@link getClassName()} instead.
Chris@0 37 */
Chris@0 38 public $name;
Chris@0 39
Chris@0 40 /**
Chris@0 41 * @var string
Chris@0 42 *
Chris@0 43 * @internal This property is public in order to reduce the size of the
Chris@0 44 * class' serialized representation. Do not access it. Use
Chris@0 45 * {@link getDefaultGroup()} instead.
Chris@0 46 */
Chris@0 47 public $defaultGroup;
Chris@0 48
Chris@0 49 /**
Chris@14 50 * @var MemberMetadata[][]
Chris@0 51 *
Chris@0 52 * @internal This property is public in order to reduce the size of the
Chris@0 53 * class' serialized representation. Do not access it. Use
Chris@0 54 * {@link getPropertyMetadata()} instead.
Chris@0 55 */
Chris@0 56 public $members = array();
Chris@0 57
Chris@0 58 /**
Chris@0 59 * @var PropertyMetadata[]
Chris@0 60 *
Chris@0 61 * @internal This property is public in order to reduce the size of the
Chris@0 62 * class' serialized representation. Do not access it. Use
Chris@0 63 * {@link getPropertyMetadata()} instead.
Chris@0 64 */
Chris@0 65 public $properties = array();
Chris@0 66
Chris@0 67 /**
Chris@0 68 * @var GetterMetadata[]
Chris@0 69 *
Chris@0 70 * @internal This property is public in order to reduce the size of the
Chris@0 71 * class' serialized representation. Do not access it. Use
Chris@0 72 * {@link getPropertyMetadata()} instead.
Chris@0 73 */
Chris@0 74 public $getters = array();
Chris@0 75
Chris@0 76 /**
Chris@0 77 * @var array
Chris@0 78 *
Chris@0 79 * @internal This property is public in order to reduce the size of the
Chris@0 80 * class' serialized representation. Do not access it. Use
Chris@0 81 * {@link getGroupSequence()} instead.
Chris@0 82 */
Chris@0 83 public $groupSequence = array();
Chris@0 84
Chris@0 85 /**
Chris@0 86 * @var bool
Chris@0 87 *
Chris@0 88 * @internal This property is public in order to reduce the size of the
Chris@0 89 * class' serialized representation. Do not access it. Use
Chris@0 90 * {@link isGroupSequenceProvider()} instead.
Chris@0 91 */
Chris@0 92 public $groupSequenceProvider = false;
Chris@0 93
Chris@0 94 /**
Chris@0 95 * The strategy for traversing traversable objects.
Chris@0 96 *
Chris@0 97 * By default, only instances of {@link \Traversable} are traversed.
Chris@0 98 *
Chris@0 99 * @var int
Chris@0 100 *
Chris@0 101 * @internal This property is public in order to reduce the size of the
Chris@0 102 * class' serialized representation. Do not access it. Use
Chris@0 103 * {@link getTraversalStrategy()} instead.
Chris@0 104 */
Chris@0 105 public $traversalStrategy = TraversalStrategy::IMPLICIT;
Chris@0 106
Chris@0 107 /**
Chris@0 108 * @var \ReflectionClass
Chris@0 109 */
Chris@0 110 private $reflClass;
Chris@0 111
Chris@0 112 /**
Chris@0 113 * Constructs a metadata for the given class.
Chris@0 114 *
Chris@0 115 * @param string $class
Chris@0 116 */
Chris@0 117 public function __construct($class)
Chris@0 118 {
Chris@0 119 $this->name = $class;
Chris@0 120 // class name without namespace
Chris@0 121 if (false !== $nsSep = strrpos($class, '\\')) {
Chris@0 122 $this->defaultGroup = substr($class, $nsSep + 1);
Chris@0 123 } else {
Chris@0 124 $this->defaultGroup = $class;
Chris@0 125 }
Chris@0 126 }
Chris@0 127
Chris@0 128 /**
Chris@0 129 * {@inheritdoc}
Chris@0 130 */
Chris@0 131 public function __sleep()
Chris@0 132 {
Chris@0 133 $parentProperties = parent::__sleep();
Chris@0 134
Chris@0 135 // Don't store the cascading strategy. Classes never cascade.
Chris@0 136 unset($parentProperties[array_search('cascadingStrategy', $parentProperties)]);
Chris@0 137
Chris@0 138 return array_merge($parentProperties, array(
Chris@0 139 'getters',
Chris@0 140 'groupSequence',
Chris@0 141 'groupSequenceProvider',
Chris@0 142 'members',
Chris@0 143 'name',
Chris@0 144 'properties',
Chris@0 145 'defaultGroup',
Chris@0 146 ));
Chris@0 147 }
Chris@0 148
Chris@0 149 /**
Chris@0 150 * {@inheritdoc}
Chris@0 151 */
Chris@0 152 public function getClassName()
Chris@0 153 {
Chris@0 154 return $this->name;
Chris@0 155 }
Chris@0 156
Chris@0 157 /**
Chris@0 158 * Returns the name of the default group for this class.
Chris@0 159 *
Chris@0 160 * For each class, the group "Default" is an alias for the group
Chris@0 161 * "<ClassName>", where <ClassName> is the non-namespaced name of the
Chris@0 162 * class. All constraints implicitly or explicitly assigned to group
Chris@0 163 * "Default" belong to both of these groups, unless the class defines
Chris@0 164 * a group sequence.
Chris@0 165 *
Chris@0 166 * If a class defines a group sequence, validating the class in "Default"
Chris@0 167 * will validate the group sequence. The constraints assigned to "Default"
Chris@0 168 * can still be validated by validating the class in "<ClassName>".
Chris@0 169 *
Chris@0 170 * @return string The name of the default group
Chris@0 171 */
Chris@0 172 public function getDefaultGroup()
Chris@0 173 {
Chris@0 174 return $this->defaultGroup;
Chris@0 175 }
Chris@0 176
Chris@0 177 /**
Chris@0 178 * {@inheritdoc}
Chris@0 179 */
Chris@0 180 public function addConstraint(Constraint $constraint)
Chris@0 181 {
Chris@0 182 if (!in_array(Constraint::CLASS_CONSTRAINT, (array) $constraint->getTargets())) {
Chris@0 183 throw new ConstraintDefinitionException(sprintf(
Chris@0 184 'The constraint "%s" cannot be put on classes.',
Chris@0 185 get_class($constraint)
Chris@0 186 ));
Chris@0 187 }
Chris@0 188
Chris@0 189 if ($constraint instanceof Valid) {
Chris@0 190 throw new ConstraintDefinitionException(sprintf(
Chris@0 191 'The constraint "%s" cannot be put on classes.',
Chris@0 192 get_class($constraint)
Chris@0 193 ));
Chris@0 194 }
Chris@0 195
Chris@0 196 if ($constraint instanceof Traverse) {
Chris@0 197 if ($constraint->traverse) {
Chris@0 198 // If traverse is true, traversal should be explicitly enabled
Chris@0 199 $this->traversalStrategy = TraversalStrategy::TRAVERSE;
Chris@0 200 } else {
Chris@0 201 // If traverse is false, traversal should be explicitly disabled
Chris@0 202 $this->traversalStrategy = TraversalStrategy::NONE;
Chris@0 203 }
Chris@0 204
Chris@0 205 // The constraint is not added
Chris@0 206 return $this;
Chris@0 207 }
Chris@0 208
Chris@0 209 $constraint->addImplicitGroupName($this->getDefaultGroup());
Chris@0 210
Chris@0 211 parent::addConstraint($constraint);
Chris@0 212
Chris@0 213 return $this;
Chris@0 214 }
Chris@0 215
Chris@0 216 /**
Chris@0 217 * Adds a constraint to the given property.
Chris@0 218 *
Chris@0 219 * @param string $property The name of the property
Chris@0 220 * @param Constraint $constraint The constraint
Chris@0 221 *
Chris@0 222 * @return $this
Chris@0 223 */
Chris@0 224 public function addPropertyConstraint($property, Constraint $constraint)
Chris@0 225 {
Chris@0 226 if (!isset($this->properties[$property])) {
Chris@0 227 $this->properties[$property] = new PropertyMetadata($this->getClassName(), $property);
Chris@0 228
Chris@0 229 $this->addPropertyMetadata($this->properties[$property]);
Chris@0 230 }
Chris@0 231
Chris@0 232 $constraint->addImplicitGroupName($this->getDefaultGroup());
Chris@0 233
Chris@0 234 $this->properties[$property]->addConstraint($constraint);
Chris@0 235
Chris@0 236 return $this;
Chris@0 237 }
Chris@0 238
Chris@0 239 /**
Chris@0 240 * @param string $property
Chris@0 241 * @param Constraint[] $constraints
Chris@0 242 *
Chris@0 243 * @return $this
Chris@0 244 */
Chris@0 245 public function addPropertyConstraints($property, array $constraints)
Chris@0 246 {
Chris@0 247 foreach ($constraints as $constraint) {
Chris@0 248 $this->addPropertyConstraint($property, $constraint);
Chris@0 249 }
Chris@0 250
Chris@0 251 return $this;
Chris@0 252 }
Chris@0 253
Chris@0 254 /**
Chris@0 255 * Adds a constraint to the getter of the given property.
Chris@0 256 *
Chris@0 257 * The name of the getter is assumed to be the name of the property with an
Chris@0 258 * uppercased first letter and either the prefix "get" or "is".
Chris@0 259 *
Chris@0 260 * @param string $property The name of the property
Chris@0 261 * @param Constraint $constraint The constraint
Chris@0 262 *
Chris@0 263 * @return $this
Chris@0 264 */
Chris@0 265 public function addGetterConstraint($property, Constraint $constraint)
Chris@0 266 {
Chris@0 267 if (!isset($this->getters[$property])) {
Chris@0 268 $this->getters[$property] = new GetterMetadata($this->getClassName(), $property);
Chris@0 269
Chris@0 270 $this->addPropertyMetadata($this->getters[$property]);
Chris@0 271 }
Chris@0 272
Chris@0 273 $constraint->addImplicitGroupName($this->getDefaultGroup());
Chris@0 274
Chris@0 275 $this->getters[$property]->addConstraint($constraint);
Chris@0 276
Chris@0 277 return $this;
Chris@0 278 }
Chris@0 279
Chris@0 280 /**
Chris@0 281 * Adds a constraint to the getter of the given property.
Chris@0 282 *
Chris@0 283 * @param string $property The name of the property
Chris@0 284 * @param string $method The name of the getter method
Chris@0 285 * @param Constraint $constraint The constraint
Chris@0 286 *
Chris@0 287 * @return $this
Chris@0 288 */
Chris@0 289 public function addGetterMethodConstraint($property, $method, Constraint $constraint)
Chris@0 290 {
Chris@0 291 if (!isset($this->getters[$property])) {
Chris@0 292 $this->getters[$property] = new GetterMetadata($this->getClassName(), $property, $method);
Chris@0 293
Chris@0 294 $this->addPropertyMetadata($this->getters[$property]);
Chris@0 295 }
Chris@0 296
Chris@0 297 $constraint->addImplicitGroupName($this->getDefaultGroup());
Chris@0 298
Chris@0 299 $this->getters[$property]->addConstraint($constraint);
Chris@0 300
Chris@0 301 return $this;
Chris@0 302 }
Chris@0 303
Chris@0 304 /**
Chris@0 305 * @param string $property
Chris@0 306 * @param Constraint[] $constraints
Chris@0 307 *
Chris@0 308 * @return $this
Chris@0 309 */
Chris@0 310 public function addGetterConstraints($property, array $constraints)
Chris@0 311 {
Chris@0 312 foreach ($constraints as $constraint) {
Chris@0 313 $this->addGetterConstraint($property, $constraint);
Chris@0 314 }
Chris@0 315
Chris@0 316 return $this;
Chris@0 317 }
Chris@0 318
Chris@0 319 /**
Chris@0 320 * @param string $property
Chris@0 321 * @param string $method
Chris@0 322 * @param Constraint[] $constraints
Chris@0 323 *
Chris@0 324 * @return $this
Chris@0 325 */
Chris@0 326 public function addGetterMethodConstraints($property, $method, array $constraints)
Chris@0 327 {
Chris@0 328 foreach ($constraints as $constraint) {
Chris@0 329 $this->addGetterMethodConstraint($property, $method, $constraint);
Chris@0 330 }
Chris@0 331
Chris@0 332 return $this;
Chris@0 333 }
Chris@0 334
Chris@0 335 /**
Chris@0 336 * Merges the constraints of the given metadata into this object.
Chris@0 337 */
Chris@0 338 public function mergeConstraints(ClassMetadata $source)
Chris@0 339 {
Chris@14 340 if ($source->isGroupSequenceProvider()) {
Chris@14 341 $this->setGroupSequenceProvider(true);
Chris@14 342 }
Chris@14 343
Chris@0 344 foreach ($source->getConstraints() as $constraint) {
Chris@0 345 $this->addConstraint(clone $constraint);
Chris@0 346 }
Chris@0 347
Chris@0 348 foreach ($source->getConstrainedProperties() as $property) {
Chris@0 349 foreach ($source->getPropertyMetadata($property) as $member) {
Chris@0 350 $member = clone $member;
Chris@0 351
Chris@0 352 foreach ($member->getConstraints() as $constraint) {
Chris@0 353 if (in_array($constraint::DEFAULT_GROUP, $constraint->groups, true)) {
Chris@0 354 $member->constraintsByGroup[$this->getDefaultGroup()][] = $constraint;
Chris@0 355 }
Chris@0 356
Chris@0 357 $constraint->addImplicitGroupName($this->getDefaultGroup());
Chris@0 358 }
Chris@0 359
Chris@0 360 $this->addPropertyMetadata($member);
Chris@0 361
Chris@0 362 if ($member instanceof MemberMetadata && !$member->isPrivate($this->name)) {
Chris@0 363 $property = $member->getPropertyName();
Chris@0 364
Chris@0 365 if ($member instanceof PropertyMetadata && !isset($this->properties[$property])) {
Chris@0 366 $this->properties[$property] = $member;
Chris@0 367 } elseif ($member instanceof GetterMetadata && !isset($this->getters[$property])) {
Chris@0 368 $this->getters[$property] = $member;
Chris@0 369 }
Chris@0 370 }
Chris@0 371 }
Chris@0 372 }
Chris@0 373 }
Chris@0 374
Chris@0 375 /**
Chris@0 376 * {@inheritdoc}
Chris@0 377 */
Chris@0 378 public function hasPropertyMetadata($property)
Chris@0 379 {
Chris@0 380 return array_key_exists($property, $this->members);
Chris@0 381 }
Chris@0 382
Chris@0 383 /**
Chris@0 384 * {@inheritdoc}
Chris@0 385 */
Chris@0 386 public function getPropertyMetadata($property)
Chris@0 387 {
Chris@0 388 if (!isset($this->members[$property])) {
Chris@0 389 return array();
Chris@0 390 }
Chris@0 391
Chris@0 392 return $this->members[$property];
Chris@0 393 }
Chris@0 394
Chris@0 395 /**
Chris@0 396 * {@inheritdoc}
Chris@0 397 */
Chris@0 398 public function getConstrainedProperties()
Chris@0 399 {
Chris@0 400 return array_keys($this->members);
Chris@0 401 }
Chris@0 402
Chris@0 403 /**
Chris@0 404 * Sets the default group sequence for this class.
Chris@0 405 *
Chris@0 406 * @param array $groupSequence An array of group names
Chris@0 407 *
Chris@0 408 * @return $this
Chris@0 409 *
Chris@0 410 * @throws GroupDefinitionException
Chris@0 411 */
Chris@0 412 public function setGroupSequence($groupSequence)
Chris@0 413 {
Chris@0 414 if ($this->isGroupSequenceProvider()) {
Chris@0 415 throw new GroupDefinitionException('Defining a static group sequence is not allowed with a group sequence provider');
Chris@0 416 }
Chris@0 417
Chris@0 418 if (is_array($groupSequence)) {
Chris@0 419 $groupSequence = new GroupSequence($groupSequence);
Chris@0 420 }
Chris@0 421
Chris@0 422 if (in_array(Constraint::DEFAULT_GROUP, $groupSequence->groups, true)) {
Chris@0 423 throw new GroupDefinitionException(sprintf('The group "%s" is not allowed in group sequences', Constraint::DEFAULT_GROUP));
Chris@0 424 }
Chris@0 425
Chris@0 426 if (!in_array($this->getDefaultGroup(), $groupSequence->groups, true)) {
Chris@0 427 throw new GroupDefinitionException(sprintf('The group "%s" is missing in the group sequence', $this->getDefaultGroup()));
Chris@0 428 }
Chris@0 429
Chris@0 430 $this->groupSequence = $groupSequence;
Chris@0 431
Chris@0 432 return $this;
Chris@0 433 }
Chris@0 434
Chris@0 435 /**
Chris@0 436 * {@inheritdoc}
Chris@0 437 */
Chris@0 438 public function hasGroupSequence()
Chris@0 439 {
Chris@0 440 return $this->groupSequence && count($this->groupSequence->groups) > 0;
Chris@0 441 }
Chris@0 442
Chris@0 443 /**
Chris@0 444 * {@inheritdoc}
Chris@0 445 */
Chris@0 446 public function getGroupSequence()
Chris@0 447 {
Chris@0 448 return $this->groupSequence;
Chris@0 449 }
Chris@0 450
Chris@0 451 /**
Chris@0 452 * Returns a ReflectionClass instance for this class.
Chris@0 453 *
Chris@0 454 * @return \ReflectionClass
Chris@0 455 */
Chris@0 456 public function getReflectionClass()
Chris@0 457 {
Chris@0 458 if (!$this->reflClass) {
Chris@0 459 $this->reflClass = new \ReflectionClass($this->getClassName());
Chris@0 460 }
Chris@0 461
Chris@0 462 return $this->reflClass;
Chris@0 463 }
Chris@0 464
Chris@0 465 /**
Chris@0 466 * Sets whether a group sequence provider should be used.
Chris@0 467 *
Chris@0 468 * @param bool $active
Chris@0 469 *
Chris@0 470 * @throws GroupDefinitionException
Chris@0 471 */
Chris@0 472 public function setGroupSequenceProvider($active)
Chris@0 473 {
Chris@0 474 if ($this->hasGroupSequence()) {
Chris@0 475 throw new GroupDefinitionException('Defining a group sequence provider is not allowed with a static group sequence');
Chris@0 476 }
Chris@0 477
Chris@0 478 if (!$this->getReflectionClass()->implementsInterface('Symfony\Component\Validator\GroupSequenceProviderInterface')) {
Chris@0 479 throw new GroupDefinitionException(sprintf('Class "%s" must implement GroupSequenceProviderInterface', $this->name));
Chris@0 480 }
Chris@0 481
Chris@0 482 $this->groupSequenceProvider = $active;
Chris@0 483 }
Chris@0 484
Chris@0 485 /**
Chris@0 486 * {@inheritdoc}
Chris@0 487 */
Chris@0 488 public function isGroupSequenceProvider()
Chris@0 489 {
Chris@0 490 return $this->groupSequenceProvider;
Chris@0 491 }
Chris@0 492
Chris@0 493 /**
Chris@0 494 * Class nodes are never cascaded.
Chris@0 495 *
Chris@0 496 * {@inheritdoc}
Chris@0 497 */
Chris@0 498 public function getCascadingStrategy()
Chris@0 499 {
Chris@0 500 return CascadingStrategy::NONE;
Chris@0 501 }
Chris@0 502
Chris@0 503 private function addPropertyMetadata(PropertyMetadataInterface $metadata)
Chris@0 504 {
Chris@0 505 $property = $metadata->getPropertyName();
Chris@0 506
Chris@0 507 $this->members[$property][] = $metadata;
Chris@0 508 }
Chris@0 509 }