summaryrefslogtreecommitdiff
path: root/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php')
-rw-r--r--vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php146
1 files changed, 146 insertions, 0 deletions
diff --git a/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php b/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php
new file mode 100644
index 0000000..2de622a
--- /dev/null
+++ b/vendor/doctrine/orm/src/Mapping/Driver/AttributeReader.php
@@ -0,0 +1,146 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Doctrine\ORM\Mapping\Driver;
6
7use Attribute;
8use Doctrine\ORM\Mapping\MappingAttribute;
9use LogicException;
10use ReflectionAttribute;
11use ReflectionClass;
12use ReflectionMethod;
13use ReflectionProperty;
14
15use function assert;
16use function is_string;
17use function is_subclass_of;
18use function sprintf;
19
20/** @internal */
21final class AttributeReader
22{
23 /** @var array<class-string<MappingAttribute>, bool> */
24 private array $isRepeatableAttribute = [];
25
26 /**
27 * @psalm-return class-string-map<T, T|RepeatableAttributeCollection<T>>
28 *
29 * @template T of MappingAttribute
30 */
31 public function getClassAttributes(ReflectionClass $class): array
32 {
33 return $this->convertToAttributeInstances($class->getAttributes());
34 }
35
36 /**
37 * @return class-string-map<T, T|RepeatableAttributeCollection<T>>
38 *
39 * @template T of MappingAttribute
40 */
41 public function getMethodAttributes(ReflectionMethod $method): array
42 {
43 return $this->convertToAttributeInstances($method->getAttributes());
44 }
45
46 /**
47 * @return class-string-map<T, T|RepeatableAttributeCollection<T>>
48 *
49 * @template T of MappingAttribute
50 */
51 public function getPropertyAttributes(ReflectionProperty $property): array
52 {
53 return $this->convertToAttributeInstances($property->getAttributes());
54 }
55
56 /**
57 * @param class-string<T> $attributeName The name of the annotation.
58 *
59 * @return T|null
60 *
61 * @template T of MappingAttribute
62 */
63 public function getPropertyAttribute(ReflectionProperty $property, string $attributeName)
64 {
65 if ($this->isRepeatable($attributeName)) {
66 throw new LogicException(sprintf(
67 'The attribute "%s" is repeatable. Call getPropertyAttributeCollection() instead.',
68 $attributeName,
69 ));
70 }
71
72 return $this->getPropertyAttributes($property)[$attributeName] ?? null;
73 }
74
75 /**
76 * @param class-string<T> $attributeName The name of the annotation.
77 *
78 * @return RepeatableAttributeCollection<T>
79 *
80 * @template T of MappingAttribute
81 */
82 public function getPropertyAttributeCollection(
83 ReflectionProperty $property,
84 string $attributeName,
85 ): RepeatableAttributeCollection {
86 if (! $this->isRepeatable($attributeName)) {
87 throw new LogicException(sprintf(
88 'The attribute "%s" is not repeatable. Call getPropertyAttribute() instead.',
89 $attributeName,
90 ));
91 }
92
93 return $this->getPropertyAttributes($property)[$attributeName] ?? new RepeatableAttributeCollection();
94 }
95
96 /**
97 * @param array<ReflectionAttribute> $attributes
98 *
99 * @return class-string-map<T, T|RepeatableAttributeCollection<T>>
100 *
101 * @template T of MappingAttribute
102 */
103 private function convertToAttributeInstances(array $attributes): array
104 {
105 $instances = [];
106
107 foreach ($attributes as $attribute) {
108 $attributeName = $attribute->getName();
109 assert(is_string($attributeName));
110 // Make sure we only get Doctrine Attributes
111 if (! is_subclass_of($attributeName, MappingAttribute::class)) {
112 continue;
113 }
114
115 $instance = $attribute->newInstance();
116 assert($instance instanceof MappingAttribute);
117
118 if ($this->isRepeatable($attributeName)) {
119 if (! isset($instances[$attributeName])) {
120 $instances[$attributeName] = new RepeatableAttributeCollection();
121 }
122
123 $collection = $instances[$attributeName];
124 assert($collection instanceof RepeatableAttributeCollection);
125 $collection[] = $instance;
126 } else {
127 $instances[$attributeName] = $instance;
128 }
129 }
130
131 return $instances;
132 }
133
134 /** @param class-string<MappingAttribute> $attributeClassName */
135 private function isRepeatable(string $attributeClassName): bool
136 {
137 if (isset($this->isRepeatableAttribute[$attributeClassName])) {
138 return $this->isRepeatableAttribute[$attributeClassName];
139 }
140
141 $reflectionClass = new ReflectionClass($attributeClassName);
142 $attribute = $reflectionClass->getAttributes()[0]->newInstance();
143
144 return $this->isRepeatableAttribute[$attributeClassName] = ($attribute->flags & Attribute::IS_REPEATABLE) > 0;
145 }
146}