1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* File was created 06.10.2015 06:22 |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace PeekAndPoke\Component\Slumber\Core\LookUp; |
7
|
|
|
|
8
|
|
|
use Doctrine\Common\Annotations\AnnotationRegistry; |
9
|
|
|
use Doctrine\Common\Annotations\Reader; |
10
|
|
|
use PeekAndPoke\Component\Creator\Creator; |
11
|
|
|
use PeekAndPoke\Component\Creator\CreatorFactory; |
12
|
|
|
use PeekAndPoke\Component\Creator\CreatorFactoryImpl; |
13
|
|
|
use PeekAndPoke\Component\PropertyAccess\PropertyAccessFactory; |
14
|
|
|
use PeekAndPoke\Component\PropertyAccess\PropertyAccessFactoryImpl; |
15
|
|
|
use PeekAndPoke\Component\Psi\Psi; |
16
|
|
|
use PeekAndPoke\Component\Slumber\Annotation\ClassCreatorMarker; |
17
|
|
|
use PeekAndPoke\Component\Slumber\Annotation\ClassMarker; |
18
|
|
|
use PeekAndPoke\Component\Slumber\Annotation\PropertyMappingMarker; |
19
|
|
|
use PeekAndPoke\Component\Slumber\Annotation\PropertyMarker; |
20
|
|
|
use PeekAndPoke\Component\Slumber\Core\Exception\SlumberException; |
21
|
|
|
use PeekAndPoke\Component\Slumber\Core\Validation\ClassAnnotationValidationContext; |
22
|
|
|
use PeekAndPoke\Component\Slumber\Core\Validation\PropertyAnnotationValidationContext; |
23
|
|
|
use Psr\Container\ContainerInterface; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @author Karsten J. Gerber <[email protected]> |
27
|
|
|
*/ |
28
|
|
|
class AnnotatedEntityConfigReader implements EntityConfigReader |
29
|
|
|
{ |
30
|
|
|
/** @var Reader */ |
31
|
|
|
private $annotationReader; |
32
|
|
|
/** @var ContainerInterface */ |
33
|
|
|
private $serviceProvider; |
34
|
|
|
/** @var PropertyMarker2Mapper */ |
35
|
|
|
private $mappings; |
36
|
|
|
/** @var CreatorFactory */ |
37
|
|
|
private $creatorFactory; |
38
|
|
|
/** @var PropertyAccessFactory */ |
39
|
|
|
private $propertyAccessFactory; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param ContainerInterface $serviceProvider |
43
|
|
|
* @param Reader $annotationReader |
44
|
|
|
* @param PropertyMarker2Mapper $mappings |
45
|
|
|
*/ |
46
|
336 |
|
public function __construct(ContainerInterface $serviceProvider, Reader $annotationReader, PropertyMarker2Mapper $mappings) |
47
|
|
|
{ |
48
|
336 |
|
static $autoloader = false; |
49
|
|
|
|
50
|
336 |
|
if ($autoloader === false) { |
51
|
1 |
|
$autoloader = true; |
52
|
1 |
|
AnnotationRegistry::registerLoader('class_exists'); |
|
|
|
|
53
|
|
|
} |
54
|
|
|
|
55
|
336 |
|
$this->annotationReader = $annotationReader; |
56
|
336 |
|
$this->serviceProvider = $serviceProvider; |
57
|
336 |
|
$this->mappings = $mappings; |
58
|
|
|
|
59
|
336 |
|
$this->creatorFactory = new CreatorFactoryImpl(); |
60
|
336 |
|
$this->propertyAccessFactory = new PropertyAccessFactoryImpl(); |
61
|
336 |
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @param \ReflectionClass $subject |
65
|
|
|
* |
66
|
|
|
* @return EntityConfig |
67
|
|
|
* @throws SlumberException |
68
|
|
|
*/ |
69
|
23 |
|
public function getEntityConfig(\ReflectionClass $subject) |
70
|
|
|
{ |
71
|
23 |
|
$config = new EntityConfig( |
72
|
23 |
|
$subject->name, |
73
|
23 |
|
$this->getCreator($subject), |
74
|
23 |
|
$this->getClassMarkers($subject), |
75
|
23 |
|
$this->getPropertyMarkersRecursive($subject) |
76
|
|
|
); |
77
|
|
|
|
78
|
23 |
|
return $config; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @param PropertyMarkedForSlumber $marked |
83
|
|
|
* |
84
|
|
|
* @return PropertyMarkedForSlumber |
85
|
|
|
*/ |
86
|
22 |
|
protected function enrich(PropertyMarkedForSlumber $marked) |
87
|
|
|
{ |
88
|
22 |
|
$marked->mapper = $this->mappings->createMapper($marked->marker); |
89
|
|
|
|
90
|
22 |
|
return $marked; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param \ReflectionClass $subject |
95
|
|
|
* |
96
|
|
|
* @return Creator |
97
|
|
|
*/ |
98
|
23 |
|
private function getCreator(\ReflectionClass $subject) |
99
|
|
|
{ |
100
|
23 |
|
$validationContext = new ClassAnnotationValidationContext($this->serviceProvider, $subject); |
101
|
|
|
|
102
|
23 |
|
$creatorAnnotation = Psi::it($this->annotationReader->getClassAnnotations($subject)) |
103
|
23 |
|
->filter(new Psi\IsInstanceOf(ClassCreatorMarker::class)) |
104
|
23 |
|
->each($validationContext) |
105
|
23 |
|
->getFirst(); |
106
|
|
|
|
107
|
23 |
|
if ($creatorAnnotation instanceof ClassCreatorMarker) { |
108
|
4 |
|
return $creatorAnnotation->getCreator($this->creatorFactory); |
109
|
|
|
} |
110
|
|
|
|
111
|
23 |
|
return $this->creatorFactory->create($subject); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* @param \ReflectionClass $subject |
116
|
|
|
* |
117
|
|
|
* @return ClassMarker[] |
118
|
|
|
*/ |
119
|
23 |
|
private function getClassMarkers(\ReflectionClass $subject) |
120
|
|
|
{ |
121
|
23 |
|
$validationContext = new ClassAnnotationValidationContext($this->serviceProvider, $subject); |
122
|
|
|
|
123
|
23 |
|
return Psi::it($this->annotationReader->getClassAnnotations($subject)) |
124
|
23 |
|
->filter(new Psi\IsInstanceOf(ClassMarker::class)) |
125
|
23 |
|
->each($validationContext) |
126
|
23 |
|
->toArray(); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* @param \ReflectionClass $subjectClass |
131
|
|
|
* |
132
|
|
|
* @return PropertyMarkedForSlumber[] |
133
|
|
|
*/ |
134
|
23 |
|
private function getPropertyMarkersRecursive(\ReflectionClass $subjectClass) |
135
|
|
|
{ |
136
|
|
|
/** @var PropertyMarkedForSlumber[] $result */ |
137
|
23 |
|
$result = []; |
138
|
|
|
|
139
|
|
|
// We climb up the inheritance ladder to also capture private properties that are not shadowed |
140
|
|
|
// by other properties on derived classes. |
141
|
23 |
|
while ($subjectClass instanceof \ReflectionClass && $subjectClass->isUserDefined()) { |
142
|
|
|
|
143
|
22 |
|
$this->getPropertyMarkersForClass($subjectClass, $result); |
144
|
|
|
|
145
|
22 |
|
$subjectClass = $subjectClass->getParentClass(); |
146
|
|
|
} |
147
|
|
|
|
148
|
23 |
|
return array_values($result); |
149
|
|
|
} |
150
|
|
|
|
151
|
22 |
|
private function getPropertyMarkersForClass(\ReflectionClass $class, array &$result): void |
152
|
|
|
{ |
153
|
22 |
|
$properties = $class->getProperties(); |
154
|
|
|
|
155
|
22 |
|
foreach ($properties as $property) { |
156
|
|
|
|
157
|
22 |
|
$propertyName = $property->getName(); |
158
|
|
|
|
159
|
22 |
|
if (! isset($result[$propertyName])) { |
160
|
|
|
|
161
|
22 |
|
$context = $this->getPropertyValidationContext($class, $property); |
162
|
22 |
|
$marker = $this->getPropertyAnnotationsOfType($context); |
|
|
|
|
163
|
|
|
|
164
|
22 |
|
if ($marker) { |
165
|
22 |
|
$result[$propertyName] = $this->enrich($marker); |
166
|
|
|
} |
167
|
|
|
} |
168
|
|
|
} |
169
|
22 |
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* @param \ReflectionClass $cls |
173
|
|
|
* @param \ReflectionProperty $property |
174
|
|
|
* |
175
|
|
|
* @return PropertyAnnotationValidationContext |
176
|
|
|
*/ |
177
|
22 |
|
private function getPropertyValidationContext(\ReflectionClass $cls, \ReflectionProperty $property) |
178
|
|
|
{ |
179
|
22 |
|
return new PropertyAnnotationValidationContext($this->serviceProvider, $cls, $property); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* @param PropertyAnnotationValidationContext $context |
184
|
|
|
* |
185
|
|
|
* @return PropertyMarkedForSlumber|null |
186
|
|
|
*/ |
187
|
22 |
|
private function getPropertyAnnotationsOfType(PropertyAnnotationValidationContext $context) |
188
|
|
|
{ |
189
|
22 |
|
$annotations = $this->annotationReader->getPropertyAnnotations($context->property); |
190
|
|
|
|
191
|
|
|
// get the mapping marker like AsString() or AsObject() ... |
192
|
22 |
|
$marker = Psi::it($annotations) |
193
|
22 |
|
->filter(new Psi\IsInstanceOf(PropertyMappingMarker::class)) |
194
|
22 |
|
->each($context) |
195
|
22 |
|
->getFirst(); |
196
|
|
|
|
197
|
22 |
|
if ($marker === null) { |
198
|
|
|
return null; |
199
|
|
|
} |
200
|
|
|
|
201
|
22 |
|
$newEntry = new PropertyMarkedForSlumber(); |
202
|
|
|
|
203
|
22 |
|
$newEntry->name = $context->property->getName(); |
204
|
22 |
|
$newEntry->alias = $marker->hasAlias() ? $marker->getAlias() : $context->property->getName(); |
205
|
22 |
|
$newEntry->marker = $marker; |
206
|
22 |
|
$newEntry->allMarkers = Psi::it($annotations) |
207
|
22 |
|
->filter(new Psi\IsInstanceOf(PropertyMarker::class)) |
208
|
22 |
|
->each($context) |
209
|
22 |
|
->toArray(); |
210
|
22 |
|
$newEntry->mapper = $this->mappings->createMapper($marker); |
211
|
22 |
|
$newEntry->propertyAccess = $this->propertyAccessFactory->create($context->cls, $context->property); |
212
|
|
|
|
213
|
22 |
|
return $newEntry; |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.