comparison vendor/symfony/validator/Mapping/ClassMetadata.php @ 0:4c8ae668cc8c

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