1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace Doctrine\ORM\Mapping\Driver; |
||||
6 | |||||
7 | use Doctrine\Common\Annotations\AnnotationReader; |
||||
8 | use Doctrine\Common\Persistence\Mapping\Driver\FileLocator; |
||||
9 | use Doctrine\DBAL\DBALException; |
||||
10 | use Doctrine\DBAL\Types\Type; |
||||
11 | use Doctrine\ORM\Annotation; |
||||
12 | use Doctrine\ORM\Events; |
||||
13 | use Doctrine\ORM\Mapping; |
||||
14 | use Doctrine\ORM\Mapping\Factory; |
||||
15 | use ReflectionClass; |
||||
16 | use ReflectionException; |
||||
17 | use ReflectionMethod; |
||||
18 | use ReflectionProperty; |
||||
19 | use function array_diff; |
||||
20 | use function array_filter; |
||||
21 | use function array_intersect; |
||||
22 | use function array_map; |
||||
23 | use function array_merge; |
||||
24 | use function class_exists; |
||||
25 | use function constant; |
||||
26 | use function count; |
||||
27 | use function defined; |
||||
28 | use function get_class; |
||||
29 | use function in_array; |
||||
30 | use function is_numeric; |
||||
31 | use function sprintf; |
||||
32 | use function str_replace; |
||||
33 | use function strtolower; |
||||
34 | use function strtoupper; |
||||
35 | |||||
36 | class NewAnnotationDriver implements MappingDriver |
||||
37 | { |
||||
38 | /** @var int[] */ |
||||
39 | protected static $entityAnnotationClasses = [ |
||||
40 | Annotation\Entity::class => 1, |
||||
41 | Annotation\MappedSuperclass::class => 2, |
||||
42 | ]; |
||||
43 | |||||
44 | /** |
||||
45 | * The Annotation reader. |
||||
46 | * |
||||
47 | * @var AnnotationReader |
||||
48 | */ |
||||
49 | protected $reader; |
||||
50 | |||||
51 | /** |
||||
52 | * The file locator. |
||||
53 | * |
||||
54 | * @var FileLocator |
||||
55 | */ |
||||
56 | protected $locator; |
||||
57 | |||||
58 | /** @var Factory\NamingStrategy */ |
||||
59 | protected $namingStrategy; |
||||
60 | |||||
61 | /** |
||||
62 | * Cache for AnnotationDriver#getAllClassNames(). |
||||
63 | * |
||||
64 | * @var string[]|null |
||||
65 | */ |
||||
66 | private $classNames; |
||||
67 | |||||
68 | /** |
||||
69 | * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading docblock annotations. |
||||
70 | * |
||||
71 | * @param AnnotationReader $reader The AnnotationReader to use, duck-typed. |
||||
72 | * @param FileLocator $locator A FileLocator or one/multiple paths where mapping documents can be found. |
||||
73 | * @param Factory\NamingStrategy $namingStrategy The NamingStrategy to use. |
||||
74 | */ |
||||
75 | public function __construct(AnnotationReader $reader, FileLocator $locator, Factory\NamingStrategy $namingStrategy) |
||||
76 | { |
||||
77 | $this->reader = $reader; |
||||
78 | $this->locator = $locator; |
||||
79 | $this->namingStrategy = $namingStrategy; |
||||
80 | } |
||||
81 | |||||
82 | /** |
||||
83 | * {@inheritdoc} |
||||
84 | * |
||||
85 | * @return Mapping\ComponentMetadata |
||||
86 | * |
||||
87 | * @throws Mapping\MappingException |
||||
88 | * @throws ReflectionException |
||||
89 | */ |
||||
90 | public function loadMetadataForClass( |
||||
91 | string $className, |
||||
92 | ?Mapping\ComponentMetadata $parent, |
||||
93 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||
94 | ) : Mapping\ComponentMetadata { |
||||
95 | // IMPORTANT: We're handling $metadata as "parent" metadata here, while building the $className ClassMetadata. |
||||
96 | $reflectionClass = new ReflectionClass($className); |
||||
97 | |||||
98 | // Evaluate annotations on class metadata |
||||
99 | $classAnnotations = $this->getClassAnnotations($reflectionClass); |
||||
100 | $classMetadata = $this->convertClassAnnotationsToClassMetadata( |
||||
101 | $classAnnotations, |
||||
102 | $reflectionClass, |
||||
103 | $parent, |
||||
104 | $metadataBuildingContext |
||||
105 | ); |
||||
106 | |||||
107 | // Evaluate @Cache annotation |
||||
108 | if (isset($classAnnotations[Annotation\Cache::class])) { |
||||
109 | $cacheAnnot = $classAnnotations[Annotation\Cache::class]; |
||||
110 | $cache = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata); |
||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
111 | |||||
112 | $classMetadata->setCache($cache); |
||||
113 | } |
||||
114 | |||||
115 | // Evaluate annotations on properties/fields |
||||
116 | /** @var ReflectionProperty $reflectionProperty */ |
||||
117 | foreach ($reflectionClass->getProperties() as $reflectionProperty) { |
||||
118 | if ($reflectionProperty->getDeclaringClass()->getClassName() !== $reflectionClass->getName()) { |
||||
0 ignored issues
–
show
The method
getClassName() does not exist on ReflectionClass .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||||
119 | continue; |
||||
120 | } |
||||
121 | |||||
122 | $propertyAnnotations = $this->getPropertyAnnotations($reflectionProperty); |
||||
123 | $property = $this->convertReflectionPropertyAnnotationsToProperty( |
||||
124 | $reflectionProperty, |
||||
125 | $propertyAnnotations, |
||||
126 | $classMetadata |
||||
0 ignored issues
–
show
It seems like
$classMetadata can also be of type Doctrine\ORM\Mapping\MappedSuperClassMetadata ; however, parameter $classMetadata of Doctrine\ORM\Mapping\Dri...AnnotationsToProperty() does only seem to accept Doctrine\ORM\Mapping\ClassMetadata , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
127 | ); |
||||
128 | |||||
129 | $classMetadata->addProperty($property); |
||||
130 | } |
||||
131 | |||||
132 | return $classMetadata; |
||||
133 | } |
||||
134 | |||||
135 | /** |
||||
136 | * {@inheritdoc} |
||||
137 | */ |
||||
138 | public function getAllClassNames() : array |
||||
139 | { |
||||
140 | if ($this->classNames !== null) { |
||||
141 | return $this->classNames; |
||||
142 | } |
||||
143 | |||||
144 | $classNames = array_filter( |
||||
145 | $this->locator->getAllClassNames(null), |
||||
146 | function ($className) { |
||||
147 | return ! $this->isTransient($className); |
||||
148 | } |
||||
149 | ); |
||||
150 | |||||
151 | $this->classNames = $classNames; |
||||
152 | |||||
153 | return $classNames; |
||||
154 | } |
||||
155 | |||||
156 | /** |
||||
157 | * {@inheritdoc} |
||||
158 | */ |
||||
159 | public function isTransient($className) : bool |
||||
160 | { |
||||
161 | $reflectionClass = new ReflectionClass($className); |
||||
162 | $classAnnotations = $this->reader->getClassAnnotations($reflectionClass); |
||||
163 | |||||
164 | foreach ($classAnnotations as $annotation) { |
||||
165 | if (isset(self::$entityAnnotationClasses[get_class($annotation)])) { |
||||
166 | return false; |
||||
167 | } |
||||
168 | } |
||||
169 | |||||
170 | return true; |
||||
171 | } |
||||
172 | |||||
173 | /** |
||||
174 | * @param Annotation\Annotation[] $classAnnotations |
||||
175 | * |
||||
176 | * @return Mapping\ClassMetadata|Mapping\ComponentMetadata |
||||
177 | * |
||||
178 | * @throws DBALException |
||||
179 | * @throws ReflectionException |
||||
180 | */ |
||||
181 | private function convertClassAnnotationsToClassMetadata( |
||||
182 | array $classAnnotations, |
||||
183 | ReflectionClass $reflectionClass, |
||||
184 | ?Mapping\ComponentMetadata $parent, |
||||
185 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||
186 | ) : Mapping\ComponentMetadata { |
||||
187 | switch (true) { |
||||
188 | case isset($classAnnotations[Annotation\Entity::class]): |
||||
189 | return $this->convertClassAnnotationsToEntityClassMetadata( |
||||
190 | $classAnnotations, |
||||
191 | $reflectionClass, |
||||
192 | $parent, |
||||
193 | $metadataBuildingContext |
||||
194 | ); |
||||
195 | |||||
196 | break; |
||||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other
Loading history...
|
|||||
197 | |||||
198 | case isset($classAnnotations[Annotation\MappedSuperclass::class]): |
||||
199 | return $this->convertClassAnnotationsToMappedSuperClassMetadata( |
||||
200 | $classAnnotations, |
||||
201 | $reflectionClass, |
||||
202 | $parent, |
||||
203 | $metadataBuildingContext |
||||
204 | ); |
||||
205 | case isset($classAnnotations[Annotation\Embeddable::class]): |
||||
206 | return $this->convertClassAnnotationsToEntityClassMetadata( |
||||
207 | $classAnnotations, |
||||
208 | $reflectionClass, |
||||
209 | $parent, |
||||
210 | $metadataBuildingContext |
||||
211 | ); |
||||
212 | default: |
||||
213 | throw Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass($reflectionClass->getName()); |
||||
214 | } |
||||
215 | } |
||||
216 | |||||
217 | /** |
||||
218 | * @param Annotation\Annotation[] $classAnnotations |
||||
219 | * |
||||
220 | * @return Mapping\ClassMetadata |
||||
221 | * |
||||
222 | * @throws DBALException |
||||
223 | * @throws ReflectionException |
||||
224 | */ |
||||
225 | private function convertClassAnnotationsToEntityClassMetadata( |
||||
226 | array $classAnnotations, |
||||
227 | ReflectionClass $reflectionClass, |
||||
228 | ?Mapping\ComponentMetadata $parent, |
||||
229 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||
0 ignored issues
–
show
The parameter
$metadataBuildingContext is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.
Loading history...
|
|||||
230 | ) { |
||||
231 | /** @var Annotation\Entity $entityAnnot */ |
||||
232 | $entityAnnot = $classAnnotations[Annotation\Entity::class]; |
||||
233 | $classMetadata = new Mapping\ClassMetadata($reflectionClass->getName(), $parent); |
||||
234 | |||||
235 | if ($entityAnnot->repositoryClass !== null) { |
||||
236 | $classMetadata->setCustomRepositoryClassName($entityAnnot->repositoryClass); |
||||
237 | } |
||||
238 | |||||
239 | if ($entityAnnot->readOnly) { |
||||
240 | $classMetadata->asReadOnly(); |
||||
241 | } |
||||
242 | |||||
243 | // Evaluate @Table annotation |
||||
244 | if (isset($classAnnotations[Annotation\Table::class])) { |
||||
245 | /** @var Annotation\Table $tableAnnot */ |
||||
246 | $tableAnnot = $classAnnotations[Annotation\Table::class]; |
||||
247 | $table = $this->convertTableAnnotationToTableMetadata($tableAnnot); |
||||
248 | |||||
249 | $classMetadata->setTable($table); |
||||
250 | } |
||||
251 | |||||
252 | // Evaluate @ChangeTrackingPolicy annotation |
||||
253 | if (isset($classAnnotations[Annotation\ChangeTrackingPolicy::class])) { |
||||
254 | /** @var Annotation\ChangeTrackingPolicy $changeTrackingAnnot */ |
||||
255 | $changeTrackingAnnot = $classAnnotations[Annotation\ChangeTrackingPolicy::class]; |
||||
256 | |||||
257 | $classMetadata->setChangeTrackingPolicy( |
||||
258 | constant(sprintf('%s::%s', Mapping\ChangeTrackingPolicy::class, $changeTrackingAnnot->value)) |
||||
259 | ); |
||||
260 | } |
||||
261 | |||||
262 | // Evaluate @EntityListeners annotation |
||||
263 | if (isset($classAnnotations[Annotation\EntityListeners::class])) { |
||||
264 | /** @var Annotation\EntityListeners $entityListenersAnnot */ |
||||
265 | $entityListenersAnnot = $classAnnotations[Annotation\EntityListeners::class]; |
||||
266 | $eventMap = [ |
||||
267 | Events::prePersist => Annotation\PrePersist::class, |
||||
268 | Events::postPersist => Annotation\PostPersist::class, |
||||
269 | Events::preUpdate => Annotation\PreUpdate::class, |
||||
270 | Events::postUpdate => Annotation\PostUpdate::class, |
||||
271 | Events::preRemove => Annotation\PreRemove::class, |
||||
272 | Events::postRemove => Annotation\PostRemove::class, |
||||
273 | Events::postLoad => Annotation\PostLoad::class, |
||||
274 | Events::preFlush => Annotation\PreFlush::class, |
||||
275 | ]; |
||||
276 | |||||
277 | foreach ($entityListenersAnnot->value as $listenerClassName) { |
||||
278 | if (! class_exists($listenerClassName)) { |
||||
279 | throw Mapping\MappingException::entityListenerClassNotFound( |
||||
280 | $listenerClassName, |
||||
281 | $classMetadata->getClassName() |
||||
282 | ); |
||||
283 | } |
||||
284 | |||||
285 | $listenerClass = new ReflectionClass($listenerClassName); |
||||
286 | |||||
287 | /** @var ReflectionMethod $reflectionMethod */ |
||||
288 | foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { |
||||
289 | $annotations = $this->getMethodAnnotations($reflectionMethod); |
||||
290 | |||||
291 | foreach ($eventMap as $eventName => $annotationClassName) { |
||||
292 | if (isset($annotations[$annotationClassName])) { |
||||
293 | $classMetadata->addEntityListener($eventName, $listenerClassName, $reflectionMethod->getName()); |
||||
294 | } |
||||
295 | } |
||||
296 | } |
||||
297 | } |
||||
298 | } |
||||
299 | |||||
300 | // Evaluate @HasLifecycleCallbacks annotation |
||||
301 | if (isset($classAnnotations[Annotation\HasLifecycleCallbacks::class])) { |
||||
302 | $eventMap = [ |
||||
303 | Events::prePersist => Annotation\PrePersist::class, |
||||
304 | Events::postPersist => Annotation\PostPersist::class, |
||||
305 | Events::preUpdate => Annotation\PreUpdate::class, |
||||
306 | Events::postUpdate => Annotation\PostUpdate::class, |
||||
307 | Events::preRemove => Annotation\PreRemove::class, |
||||
308 | Events::postRemove => Annotation\PostRemove::class, |
||||
309 | Events::postLoad => Annotation\PostLoad::class, |
||||
310 | Events::preFlush => Annotation\PreFlush::class, |
||||
311 | ]; |
||||
312 | |||||
313 | /** @var ReflectionMethod $reflectionMethod */ |
||||
314 | foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { |
||||
315 | $annotations = $this->getMethodAnnotations($reflectionMethod); |
||||
316 | |||||
317 | foreach ($eventMap as $eventName => $annotationClassName) { |
||||
318 | if (isset($annotations[$annotationClassName])) { |
||||
319 | $classMetadata->addLifecycleCallback($eventName, $reflectionMethod->getName()); |
||||
320 | } |
||||
321 | } |
||||
322 | } |
||||
323 | } |
||||
324 | |||||
325 | // Evaluate @InheritanceType annotation |
||||
326 | if (isset($classAnnotations[Annotation\InheritanceType::class])) { |
||||
327 | /** @var Annotation\InheritanceType $inheritanceTypeAnnot */ |
||||
328 | $inheritanceTypeAnnot = $classAnnotations[Annotation\InheritanceType::class]; |
||||
329 | |||||
330 | $classMetadata->setInheritanceType( |
||||
331 | constant(sprintf('%s::%s', Mapping\InheritanceType::class, $inheritanceTypeAnnot->value)) |
||||
332 | ); |
||||
333 | |||||
334 | if ($classMetadata->inheritanceType !== Mapping\InheritanceType::NONE) { |
||||
335 | $discriminatorColumn = new Mapping\DiscriminatorColumnMetadata(); |
||||
336 | |||||
337 | // Evaluate @DiscriminatorColumn annotation |
||||
338 | if (isset($classAnnotations[Annotation\DiscriminatorColumn::class])) { |
||||
339 | /** @var Annotation\DiscriminatorColumn $discriminatorColumnAnnot */ |
||||
340 | $discriminatorColumnAnnot = $classAnnotations[Annotation\DiscriminatorColumn::class]; |
||||
341 | |||||
342 | $discriminatorColumn->setColumnName($discriminatorColumnAnnot->name); |
||||
343 | |||||
344 | if (! empty($discriminatorColumnAnnot->columnDefinition)) { |
||||
345 | $discriminatorColumn->setColumnDefinition($discriminatorColumnAnnot->columnDefinition); |
||||
346 | } |
||||
347 | |||||
348 | if (! empty($discriminatorColumnAnnot->type)) { |
||||
349 | $discriminatorColumn->setType(Type::getType($discriminatorColumnAnnot->type)); |
||||
350 | } |
||||
351 | |||||
352 | if (! empty($discriminatorColumnAnnot->length)) { |
||||
353 | $discriminatorColumn->setLength($discriminatorColumnAnnot->length); |
||||
354 | } |
||||
355 | } |
||||
356 | |||||
357 | if (empty($discriminatorColumn->getColumnName())) { |
||||
358 | throw Mapping\MappingException::nameIsMandatoryForDiscriminatorColumns($reflectionClass->getName()); |
||||
359 | } |
||||
360 | |||||
361 | $classMetadata->setDiscriminatorColumn($discriminatorColumn); |
||||
362 | |||||
363 | // Evaluate @DiscriminatorMap annotation |
||||
364 | if (isset($classAnnotations[Annotation\DiscriminatorMap::class])) { |
||||
365 | /** @var Annotation\DiscriminatorMap $discriminatorMapAnnotation */ |
||||
366 | $discriminatorMapAnnotation = $classAnnotations[Annotation\DiscriminatorMap::class]; |
||||
367 | $discriminatorMap = $discriminatorMapAnnotation->value; |
||||
368 | |||||
369 | $classMetadata->setDiscriminatorMap($discriminatorMap); |
||||
370 | } |
||||
371 | } |
||||
372 | } |
||||
373 | |||||
374 | return $classMetadata; |
||||
375 | } |
||||
376 | |||||
377 | /** |
||||
378 | * @param Annotation\Annotation[] $classAnnotations |
||||
379 | * |
||||
380 | * @return Mapping\MappedSuperClassMetadata |
||||
381 | */ |
||||
382 | private function convertClassAnnotationsToMappedSuperClassMetadata( |
||||
383 | array $classAnnotations, |
||||
384 | ReflectionClass $reflectionClass, |
||||
385 | ?Mapping\ComponentMetadata $parent, |
||||
0 ignored issues
–
show
The parameter
$parent is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.
Loading history...
|
|||||
386 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||
0 ignored issues
–
show
The parameter
$metadataBuildingContext is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.
Loading history...
|
|||||
387 | ) { |
||||
388 | /** @var Annotation\MappedSuperclass $mappedSuperclassAnnot */ |
||||
389 | $mappedSuperclassAnnot = $classAnnotations[Annotation\MappedSuperclass::class]; |
||||
390 | $classMetadata = new Mapping\MappedSuperClassMetadata($reflectionClass->getName()); |
||||
391 | |||||
392 | if ($mappedSuperclassAnnot->repositoryClass !== null) { |
||||
393 | $classMetadata->setCustomRepositoryClassName($mappedSuperclassAnnot->repositoryClass); |
||||
394 | } |
||||
395 | |||||
396 | return $classMetadata; |
||||
397 | } |
||||
398 | |||||
399 | /** |
||||
400 | * Parse the given Table as TableMetadata |
||||
401 | * |
||||
402 | * @return Mapping\TableMetadata |
||||
403 | */ |
||||
404 | private function convertTableAnnotationToTableMetadata(Annotation\Table $tableAnnot) |
||||
405 | { |
||||
406 | $table = new Mapping\TableMetadata(); |
||||
407 | |||||
408 | if (! empty($tableAnnot->name)) { |
||||
409 | $table->setName($tableAnnot->name); |
||||
410 | } |
||||
411 | |||||
412 | if (! empty($tableAnnot->schema)) { |
||||
413 | $table->setSchema($tableAnnot->schema); |
||||
414 | } |
||||
415 | |||||
416 | foreach ($tableAnnot->options as $optionName => $optionValue) { |
||||
417 | $table->addOption($optionName, $optionValue); |
||||
418 | } |
||||
419 | |||||
420 | foreach ($tableAnnot->indexes as $indexAnnot) { |
||||
421 | $table->addIndex([ |
||||
422 | 'name' => $indexAnnot->name, |
||||
423 | 'columns' => $indexAnnot->columns, |
||||
424 | 'unique' => $indexAnnot->unique, |
||||
425 | 'options' => $indexAnnot->options, |
||||
426 | 'flags' => $indexAnnot->flags, |
||||
427 | ]); |
||||
428 | } |
||||
429 | |||||
430 | foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) { |
||||
431 | $table->addUniqueConstraint([ |
||||
432 | 'name' => $uniqueConstraintAnnot->name, |
||||
433 | 'columns' => $uniqueConstraintAnnot->columns, |
||||
434 | 'options' => $uniqueConstraintAnnot->options, |
||||
435 | 'flags' => $uniqueConstraintAnnot->flags, |
||||
436 | ]); |
||||
437 | } |
||||
438 | |||||
439 | return $table; |
||||
440 | } |
||||
441 | |||||
442 | /** |
||||
443 | * Parse the given Cache as CacheMetadata |
||||
444 | * |
||||
445 | * @param string|null $fieldName |
||||
446 | * |
||||
447 | * @return Mapping\CacheMetadata |
||||
448 | */ |
||||
449 | private function convertCacheAnnotationToCacheMetadata( |
||||
450 | Annotation\Cache $cacheAnnot, |
||||
451 | Mapping\ClassMetadata $metadata, |
||||
452 | $fieldName = null |
||||
453 | ) { |
||||
454 | $usage = constant(sprintf('%s::%s', Mapping\CacheUsage::class, $cacheAnnot->usage)); |
||||
455 | $baseRegion = strtolower(str_replace('\\', '_', $metadata->getRootClassName())); |
||||
456 | $defaultRegion = $baseRegion . ($fieldName ? '__' . $fieldName : ''); |
||||
457 | |||||
458 | return new Mapping\CacheMetadata($usage, $cacheAnnot->region ?: $defaultRegion); |
||||
459 | } |
||||
460 | |||||
461 | /** |
||||
462 | * @param Annotation\Annotation[] $propertyAnnotations |
||||
463 | * |
||||
464 | * @return Mapping\Property |
||||
465 | * |
||||
466 | * @throws Mapping\MappingException |
||||
467 | */ |
||||
468 | private function convertReflectionPropertyAnnotationsToProperty( |
||||
469 | ReflectionProperty $reflectionProperty, |
||||
470 | array $propertyAnnotations, |
||||
471 | Mapping\ClassMetadata $classMetadata |
||||
472 | ) { |
||||
473 | // Field can only be annotated with one of: |
||||
474 | // @Column, @OneToOne, @OneToMany, @ManyToOne, @ManyToMany, @Embedded |
||||
475 | switch (true) { |
||||
476 | case isset($propertyAnnotations[Annotation\Column::class]): |
||||
477 | return $this->convertReflectionPropertyToFieldMetadata( |
||||
478 | $reflectionProperty, |
||||
479 | $propertyAnnotations, |
||||
480 | $classMetadata |
||||
481 | ); |
||||
482 | case isset($propertyAnnotations[Annotation\OneToOne::class]): |
||||
483 | return $this->convertReflectionPropertyToOneToOneAssociationMetadata( |
||||
484 | $reflectionProperty, |
||||
485 | $propertyAnnotations, |
||||
486 | $classMetadata |
||||
487 | ); |
||||
488 | case isset($propertyAnnotations[Annotation\ManyToOne::class]): |
||||
489 | return $this->convertReflectionPropertyToManyToOneAssociationMetadata( |
||||
490 | $reflectionProperty, |
||||
491 | $propertyAnnotations, |
||||
492 | $classMetadata |
||||
493 | ); |
||||
494 | case isset($propertyAnnotations[Annotation\OneToMany::class]): |
||||
495 | return $this->convertReflectionPropertyToOneToManyAssociationMetadata( |
||||
496 | $reflectionProperty, |
||||
497 | $propertyAnnotations, |
||||
498 | $classMetadata |
||||
499 | ); |
||||
500 | case isset($propertyAnnotations[Annotation\ManyToMany::class]): |
||||
501 | return $this->convertReflectionPropertyToManyToManyAssociationMetadata( |
||||
502 | $reflectionProperty, |
||||
503 | $propertyAnnotations, |
||||
504 | $classMetadata |
||||
505 | ); |
||||
506 | case isset($propertyAnnotations[Annotation\Embedded::class]): |
||||
507 | // @todo guilhermeblanco Implement later... =) |
||||
508 | break; |
||||
509 | |||||
510 | default: |
||||
511 | return new Mapping\TransientMetadata($reflectionProperty->getName()); |
||||
512 | } |
||||
513 | } |
||||
514 | |||||
515 | /** |
||||
516 | * @param Annotation\Annotation[] $propertyAnnotations |
||||
517 | * |
||||
518 | * @return Mapping\FieldMetadata |
||||
519 | * |
||||
520 | * @throws Mapping\MappingException |
||||
521 | * @throws DBALException |
||||
522 | */ |
||||
523 | private function convertReflectionPropertyToFieldMetadata( |
||||
524 | ReflectionProperty $reflectionProperty, |
||||
525 | array $propertyAnnotations, |
||||
526 | Mapping\ClassMetadata $classMetadata |
||||
527 | ) { |
||||
528 | $className = $classMetadata->getClassName(); |
||||
529 | $fieldName = $reflectionProperty->getName(); |
||||
530 | $columnAnnot = $propertyAnnotations[Annotation\Column::class]; |
||||
531 | $isVersioned = isset($propertyAnnotations[Annotation\Version::class]); |
||||
532 | $isPrimaryKey = isset($propertyAnnotations[Annotation\Id::class]); |
||||
533 | |||||
534 | if ($columnAnnot->type === null) { |
||||
0 ignored issues
–
show
|
|||||
535 | throw Mapping\MappingException::propertyTypeIsRequired($className, $fieldName); |
||||
536 | } |
||||
537 | |||||
538 | if ($isVersioned && $isPrimaryKey) { |
||||
539 | throw Mapping\MappingException::cannotVersionIdField($className, $fieldName); |
||||
540 | } |
||||
541 | |||||
542 | $fieldType = Type::getType($columnAnnot->type); |
||||
543 | $columnName = empty($columnAnnot->name) |
||||
0 ignored issues
–
show
|
|||||
544 | ? $this->namingStrategy->propertyToColumnName($fieldName, $className) |
||||
545 | : $columnAnnot->name; |
||||
546 | |||||
547 | $fieldMetadata = new Mapping\FieldMetadata($fieldName); |
||||
548 | |||||
549 | $fieldMetadata->setType($fieldType); |
||||
550 | $fieldMetadata->setVersioned($isVersioned); |
||||
551 | $fieldMetadata->setColumnName($columnName); |
||||
552 | $fieldMetadata->setScale($columnAnnot->scale); |
||||
0 ignored issues
–
show
|
|||||
553 | $fieldMetadata->setPrecision($columnAnnot->precision); |
||||
0 ignored issues
–
show
|
|||||
554 | $fieldMetadata->setNullable($columnAnnot->nullable); |
||||
0 ignored issues
–
show
|
|||||
555 | $fieldMetadata->setUnique($columnAnnot->unique); |
||||
0 ignored issues
–
show
|
|||||
556 | |||||
557 | // Check for Id |
||||
558 | if ($isPrimaryKey) { |
||||
559 | if ($fieldType->canRequireSQLConversion()) { |
||||
560 | throw Mapping\MappingException::sqlConversionNotAllowedForPrimaryKeyProperties( |
||||
561 | $className, |
||||
562 | $fieldName, |
||||
563 | $fieldType->getName() |
||||
564 | ); |
||||
565 | } |
||||
566 | |||||
567 | $fieldMetadata->setPrimaryKey(true); |
||||
568 | } |
||||
569 | |||||
570 | if (! empty($columnAnnot->columnDefinition)) { |
||||
0 ignored issues
–
show
|
|||||
571 | $fieldMetadata->setColumnDefinition($columnAnnot->columnDefinition); |
||||
572 | } |
||||
573 | |||||
574 | if (! empty($columnAnnot->length)) { |
||||
0 ignored issues
–
show
|
|||||
575 | $fieldMetadata->setLength($columnAnnot->length); |
||||
576 | } |
||||
577 | |||||
578 | // Assign default options |
||||
579 | $customOptions = $columnAnnot->options ?? []; |
||||
0 ignored issues
–
show
|
|||||
580 | $defaultOptions = []; |
||||
581 | |||||
582 | if ($isVersioned) { |
||||
583 | switch ($fieldMetadata->getTypeName()) { |
||||
584 | case 'integer': |
||||
585 | case 'bigint': |
||||
586 | case 'smallint': |
||||
587 | $defaultOptions['default'] = 1; |
||||
588 | break; |
||||
589 | |||||
590 | case 'datetime': |
||||
591 | $defaultOptions['default'] = 'CURRENT_TIMESTAMP'; |
||||
592 | break; |
||||
593 | |||||
594 | default: |
||||
595 | if (! isset($customOptions['default'])) { |
||||
596 | throw Mapping\MappingException::unsupportedOptimisticLockingType($fieldMetadata->getType()); |
||||
597 | } |
||||
598 | } |
||||
599 | } |
||||
600 | |||||
601 | $fieldMetadata->setOptions(array_merge($defaultOptions, $customOptions)); |
||||
602 | |||||
603 | return $fieldMetadata; |
||||
604 | } |
||||
605 | |||||
606 | /** |
||||
607 | * @param Annotation\Annotation[] $propertyAnnotations |
||||
608 | * |
||||
609 | * @return Mapping\OneToOneAssociationMetadata |
||||
610 | */ |
||||
611 | private function convertReflectionPropertyToOneToOneAssociationMetadata( |
||||
612 | ReflectionProperty $reflectionProperty, |
||||
613 | array $propertyAnnotations, |
||||
614 | Mapping\ClassMetadata $classMetadata |
||||
615 | ) { |
||||
616 | $className = $classMetadata->getClassName(); |
||||
617 | $fieldName = $reflectionProperty->getName(); |
||||
618 | $oneToOneAnnot = $propertyAnnotations[Annotation\OneToOne::class]; |
||||
619 | |||||
620 | if ($oneToOneAnnot->targetEntity === null) { |
||||
0 ignored issues
–
show
|
|||||
621 | throw Mapping\MappingException::missingTargetEntity($fieldName); |
||||
622 | } |
||||
623 | |||||
624 | $assocMetadata = new Mapping\OneToOneAssociationMetadata($fieldName); |
||||
625 | $targetEntity = $oneToOneAnnot->targetEntity; |
||||
626 | |||||
627 | $assocMetadata->setSourceEntity($className); |
||||
628 | $assocMetadata->setTargetEntity($targetEntity); |
||||
629 | $assocMetadata->setCascade($this->getCascade($className, $fieldName, $oneToOneAnnot->cascade)); |
||||
0 ignored issues
–
show
|
|||||
630 | $assocMetadata->setOrphanRemoval($oneToOneAnnot->orphanRemoval); |
||||
0 ignored issues
–
show
|
|||||
631 | $assocMetadata->setFetchMode($this->getFetchMode($className, $oneToOneAnnot->fetch)); |
||||
0 ignored issues
–
show
|
|||||
632 | |||||
633 | if (! empty($oneToOneAnnot->mappedBy)) { |
||||
0 ignored issues
–
show
|
|||||
634 | $assocMetadata->setMappedBy($oneToOneAnnot->mappedBy); |
||||
635 | } |
||||
636 | |||||
637 | if (! empty($oneToOneAnnot->inversedBy)) { |
||||
0 ignored issues
–
show
|
|||||
638 | $assocMetadata->setInversedBy($oneToOneAnnot->inversedBy); |
||||
639 | } |
||||
640 | |||||
641 | // Check for Id |
||||
642 | if (isset($propertyAnnotations[Annotation\Id::class])) { |
||||
643 | $assocMetadata->setPrimaryKey(true); |
||||
644 | } |
||||
645 | |||||
646 | // Check for Cache |
||||
647 | if (isset($propertyAnnotations[Annotation\Cache::class])) { |
||||
648 | $cacheAnnot = $propertyAnnotations[Annotation\Cache::class]; |
||||
649 | $cacheMetadata = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata, $fieldName); |
||||
650 | |||||
651 | $assocMetadata->setCache($cacheMetadata); |
||||
652 | } |
||||
653 | |||||
654 | // Check for JoinColumn/JoinColumns annotations |
||||
655 | switch (true) { |
||||
656 | case isset($propertyAnnotations[Annotation\JoinColumn::class]): |
||||
657 | $joinColumnAnnot = $propertyAnnotations[Annotation\JoinColumn::class]; |
||||
658 | $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
659 | $reflectionProperty, |
||||
660 | $joinColumnAnnot, |
||||
661 | $classMetadata |
||||
662 | ); |
||||
663 | |||||
664 | $assocMetadata->addJoinColumn($joinColumn); |
||||
665 | |||||
666 | break; |
||||
667 | |||||
668 | case isset($propertyAnnotations[Annotation\JoinColumns::class]): |
||||
669 | $joinColumnsAnnot = $propertyAnnotations[Annotation\JoinColumns::class]; |
||||
670 | |||||
671 | foreach ($joinColumnsAnnot->value as $joinColumnAnnot) { |
||||
672 | $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
673 | $reflectionProperty, |
||||
674 | $joinColumnAnnot, |
||||
675 | $classMetadata |
||||
676 | ); |
||||
677 | |||||
678 | $assocMetadata->addJoinColumn($joinColumn); |
||||
679 | } |
||||
680 | |||||
681 | break; |
||||
682 | } |
||||
683 | |||||
684 | return $assocMetadata; |
||||
685 | } |
||||
686 | |||||
687 | /** |
||||
688 | * @param Annotation\Annotation[] $propertyAnnotations |
||||
689 | * |
||||
690 | * @return Mapping\ManyToOneAssociationMetadata |
||||
691 | */ |
||||
692 | private function convertReflectionPropertyToManyToOneAssociationMetadata( |
||||
693 | ReflectionProperty $reflectionProperty, |
||||
694 | array $propertyAnnotations, |
||||
695 | Mapping\ClassMetadata $classMetadata |
||||
696 | ) { |
||||
697 | $className = $classMetadata->getClassName(); |
||||
698 | $fieldName = $reflectionProperty->getName(); |
||||
699 | $manyToOneAnnot = $propertyAnnotations[Annotation\ManyToOne::class]; |
||||
700 | |||||
701 | if ($manyToOneAnnot->targetEntity === null) { |
||||
0 ignored issues
–
show
|
|||||
702 | throw Mapping\MappingException::missingTargetEntity($fieldName); |
||||
703 | } |
||||
704 | |||||
705 | $assocMetadata = new Mapping\ManyToOneAssociationMetadata($fieldName); |
||||
706 | $targetEntity = $manyToOneAnnot->targetEntity; |
||||
707 | |||||
708 | $assocMetadata->setSourceEntity($className); |
||||
709 | $assocMetadata->setTargetEntity($targetEntity); |
||||
710 | $assocMetadata->setCascade($this->getCascade($className, $fieldName, $manyToOneAnnot->cascade)); |
||||
0 ignored issues
–
show
|
|||||
711 | $assocMetadata->setFetchMode($this->getFetchMode($className, $manyToOneAnnot->fetch)); |
||||
0 ignored issues
–
show
|
|||||
712 | |||||
713 | if (! empty($manyToOneAnnot->inversedBy)) { |
||||
0 ignored issues
–
show
|
|||||
714 | $assocMetadata->setInversedBy($manyToOneAnnot->inversedBy); |
||||
715 | } |
||||
716 | |||||
717 | // Check for Id |
||||
718 | if (isset($propertyAnnotations[Annotation\Id::class])) { |
||||
719 | $assocMetadata->setPrimaryKey(true); |
||||
720 | } |
||||
721 | |||||
722 | // Check for Cache |
||||
723 | if (isset($propertyAnnotations[Annotation\Cache::class])) { |
||||
724 | $cacheAnnot = $propertyAnnotations[Annotation\Cache::class]; |
||||
725 | $cacheMetadata = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata, $fieldName); |
||||
726 | |||||
727 | $assocMetadata->setCache($cacheMetadata); |
||||
728 | } |
||||
729 | |||||
730 | // Check for JoinColumn/JoinColumns annotations |
||||
731 | switch (true) { |
||||
732 | case isset($propertyAnnotations[Annotation\JoinColumn::class]): |
||||
733 | $joinColumnAnnot = $propertyAnnotations[Annotation\JoinColumn::class]; |
||||
734 | $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
735 | $reflectionProperty, |
||||
736 | $joinColumnAnnot, |
||||
737 | $classMetadata |
||||
738 | ); |
||||
739 | |||||
740 | $assocMetadata->addJoinColumn($joinColumn); |
||||
741 | |||||
742 | break; |
||||
743 | |||||
744 | case isset($propertyAnnotations[Annotation\JoinColumns::class]): |
||||
745 | $joinColumnsAnnot = $propertyAnnotations[Annotation\JoinColumns::class]; |
||||
746 | |||||
747 | foreach ($joinColumnsAnnot->value as $joinColumnAnnot) { |
||||
748 | $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
749 | $reflectionProperty, |
||||
750 | $joinColumnAnnot, |
||||
751 | $classMetadata |
||||
752 | ); |
||||
753 | |||||
754 | $assocMetadata->addJoinColumn($joinColumn); |
||||
755 | } |
||||
756 | |||||
757 | break; |
||||
758 | } |
||||
759 | |||||
760 | return $assocMetadata; |
||||
761 | } |
||||
762 | |||||
763 | /** |
||||
764 | * @param Annotation\Annotation[] $propertyAnnotations |
||||
765 | * |
||||
766 | * @return Mapping\OneToManyAssociationMetadata |
||||
767 | */ |
||||
768 | private function convertReflectionPropertyToOneToManyAssociationMetadata( |
||||
769 | ReflectionProperty $reflectionProperty, |
||||
770 | array $propertyAnnotations, |
||||
771 | Mapping\ClassMetadata $classMetadata |
||||
772 | ) { |
||||
773 | $className = $classMetadata->getClassName(); |
||||
774 | $fieldName = $reflectionProperty->getName(); |
||||
775 | $oneToManyAnnot = $propertyAnnotations[Annotation\OneToMany::class]; |
||||
776 | |||||
777 | if ($oneToManyAnnot->targetEntity === null) { |
||||
0 ignored issues
–
show
|
|||||
778 | throw Mapping\MappingException::missingTargetEntity($fieldName); |
||||
779 | } |
||||
780 | |||||
781 | $assocMetadata = new Mapping\OneToManyAssociationMetadata($fieldName); |
||||
782 | $targetEntity = $oneToManyAnnot->targetEntity; |
||||
783 | |||||
784 | $assocMetadata->setSourceEntity($className); |
||||
785 | $assocMetadata->setTargetEntity($targetEntity); |
||||
786 | $assocMetadata->setCascade($this->getCascade($className, $fieldName, $oneToManyAnnot->cascade)); |
||||
0 ignored issues
–
show
|
|||||
787 | $assocMetadata->setOrphanRemoval($oneToManyAnnot->orphanRemoval); |
||||
0 ignored issues
–
show
|
|||||
788 | $assocMetadata->setFetchMode($this->getFetchMode($className, $oneToManyAnnot->fetch)); |
||||
0 ignored issues
–
show
|
|||||
789 | |||||
790 | if (! empty($oneToManyAnnot->mappedBy)) { |
||||
0 ignored issues
–
show
|
|||||
791 | $assocMetadata->setMappedBy($oneToManyAnnot->mappedBy); |
||||
792 | } |
||||
793 | |||||
794 | if (! empty($oneToManyAnnot->indexBy)) { |
||||
0 ignored issues
–
show
|
|||||
795 | $assocMetadata->setIndexedBy($oneToManyAnnot->indexBy); |
||||
796 | } |
||||
797 | |||||
798 | // Check for OrderBy |
||||
799 | if (isset($propertyAnnotations[Annotation\OrderBy::class])) { |
||||
800 | $orderByAnnot = $propertyAnnotations[Annotation\OrderBy::class]; |
||||
801 | |||||
802 | $assocMetadata->setOrderBy($orderByAnnot->value); |
||||
0 ignored issues
–
show
|
|||||
803 | } |
||||
804 | |||||
805 | // Check for Id |
||||
806 | if (isset($propertyAnnotations[Annotation\Id::class])) { |
||||
807 | $assocMetadata->setPrimaryKey(true); |
||||
808 | } |
||||
809 | |||||
810 | // Check for Cache |
||||
811 | if (isset($propertyAnnotations[Annotation\Cache::class])) { |
||||
812 | $cacheAnnot = $propertyAnnotations[Annotation\Cache::class]; |
||||
813 | $cacheMetadata = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata, $fieldName); |
||||
814 | |||||
815 | $assocMetadata->setCache($cacheMetadata); |
||||
816 | } |
||||
817 | |||||
818 | return $assocMetadata; |
||||
819 | } |
||||
820 | |||||
821 | /** |
||||
822 | * @param Annotation\Annotation[] $propertyAnnotations |
||||
823 | * |
||||
824 | * @return Mapping\ManyToManyAssociationMetadata |
||||
825 | */ |
||||
826 | private function convertReflectionPropertyToManyToManyAssociationMetadata( |
||||
827 | ReflectionProperty $reflectionProperty, |
||||
828 | array $propertyAnnotations, |
||||
829 | Mapping\ClassMetadata $classMetadata |
||||
830 | ) { |
||||
831 | $className = $classMetadata->getClassName(); |
||||
832 | $fieldName = $reflectionProperty->getName(); |
||||
833 | $manyToManyAnnot = $propertyAnnotations[Annotation\ManyToMany::class]; |
||||
834 | |||||
835 | if ($manyToManyAnnot->targetEntity === null) { |
||||
0 ignored issues
–
show
|
|||||
836 | throw Mapping\MappingException::missingTargetEntity($fieldName); |
||||
837 | } |
||||
838 | |||||
839 | $assocMetadata = new Mapping\ManyToManyAssociationMetadata($fieldName); |
||||
840 | $targetEntity = $manyToManyAnnot->targetEntity; |
||||
841 | |||||
842 | $assocMetadata->setSourceEntity($className); |
||||
843 | $assocMetadata->setTargetEntity($targetEntity); |
||||
844 | $assocMetadata->setCascade($this->getCascade($className, $fieldName, $manyToManyAnnot->cascade)); |
||||
0 ignored issues
–
show
|
|||||
845 | $assocMetadata->setOrphanRemoval($manyToManyAnnot->orphanRemoval); |
||||
0 ignored issues
–
show
|
|||||
846 | $assocMetadata->setFetchMode($this->getFetchMode($className, $manyToManyAnnot->fetch)); |
||||
0 ignored issues
–
show
|
|||||
847 | |||||
848 | if (! empty($manyToManyAnnot->mappedBy)) { |
||||
0 ignored issues
–
show
|
|||||
849 | $assocMetadata->setMappedBy($manyToManyAnnot->mappedBy); |
||||
850 | } |
||||
851 | |||||
852 | if (! empty($manyToManyAnnot->inversedBy)) { |
||||
0 ignored issues
–
show
|
|||||
853 | $assocMetadata->setInversedBy($manyToManyAnnot->inversedBy); |
||||
854 | } |
||||
855 | |||||
856 | if (! empty($manyToManyAnnot->indexBy)) { |
||||
0 ignored issues
–
show
|
|||||
857 | $assocMetadata->setIndexedBy($manyToManyAnnot->indexBy); |
||||
858 | } |
||||
859 | |||||
860 | // Check for JoinTable |
||||
861 | if (isset($propertyAnnotations[Annotation\JoinTable::class])) { |
||||
862 | $joinTableAnnot = $propertyAnnotations[Annotation\JoinTable::class]; |
||||
863 | $joinTableMetadata = $this->convertJoinTableAnnotationToJoinTableMetadata( |
||||
864 | $reflectionProperty, |
||||
865 | $joinTableAnnot, |
||||
866 | $classMetadata |
||||
867 | ); |
||||
868 | |||||
869 | $assocMetadata->setJoinTable($joinTableMetadata); |
||||
870 | } |
||||
871 | |||||
872 | // Check for OrderBy |
||||
873 | if (isset($propertyAnnotations[Annotation\OrderBy::class])) { |
||||
874 | $orderByAnnot = $propertyAnnotations[Annotation\OrderBy::class]; |
||||
875 | |||||
876 | $assocMetadata->setOrderBy($orderByAnnot->value); |
||||
0 ignored issues
–
show
|
|||||
877 | } |
||||
878 | |||||
879 | // Check for Id |
||||
880 | if (isset($propertyAnnotations[Annotation\Id::class])) { |
||||
881 | $assocMetadata->setPrimaryKey(true); |
||||
882 | } |
||||
883 | |||||
884 | // Check for Cache |
||||
885 | if (isset($propertyAnnotations[Annotation\Cache::class])) { |
||||
886 | $cacheAnnot = $propertyAnnotations[Annotation\Cache::class]; |
||||
887 | $cacheMetadata = $this->convertCacheAnnotationToCacheMetadata($cacheAnnot, $classMetadata, $fieldName); |
||||
888 | |||||
889 | $assocMetadata->setCache($cacheMetadata); |
||||
890 | } |
||||
891 | |||||
892 | return $assocMetadata; |
||||
893 | } |
||||
894 | |||||
895 | /** |
||||
896 | * Parse the given JoinTable as JoinTableMetadata |
||||
897 | * |
||||
898 | * @return Mapping\JoinTableMetadata |
||||
899 | */ |
||||
900 | private function convertJoinTableAnnotationToJoinTableMetadata( |
||||
901 | ReflectionProperty $reflectionProperty, |
||||
902 | Annotation\JoinTable $joinTableAnnot, |
||||
903 | Mapping\ClassMetadata $classMetadata |
||||
904 | ) { |
||||
905 | $joinTable = new Mapping\JoinTableMetadata(); |
||||
906 | |||||
907 | if (! empty($joinTableAnnot->name)) { |
||||
908 | $joinTable->setName($joinTableAnnot->name); |
||||
909 | } |
||||
910 | |||||
911 | if (! empty($joinTableAnnot->schema)) { |
||||
912 | $joinTable->setSchema($joinTableAnnot->schema); |
||||
913 | } |
||||
914 | |||||
915 | foreach ($joinTableAnnot->joinColumns as $joinColumnAnnot) { |
||||
916 | $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
917 | $reflectionProperty, |
||||
918 | $joinColumnAnnot, |
||||
919 | $classMetadata |
||||
920 | ); |
||||
921 | |||||
922 | $joinTable->addJoinColumn($joinColumn); |
||||
923 | } |
||||
924 | |||||
925 | foreach ($joinTableAnnot->inverseJoinColumns as $joinColumnAnnot) { |
||||
926 | $joinColumn = $this->convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
927 | $reflectionProperty, |
||||
928 | $joinColumnAnnot, |
||||
929 | $classMetadata |
||||
930 | ); |
||||
931 | |||||
932 | $joinTable->addInverseJoinColumn($joinColumn); |
||||
933 | } |
||||
934 | |||||
935 | return $joinTable; |
||||
936 | } |
||||
937 | |||||
938 | /** |
||||
939 | * Parse the given JoinColumn as JoinColumnMetadata |
||||
940 | * |
||||
941 | * @return Mapping\JoinColumnMetadata |
||||
942 | */ |
||||
943 | private function convertJoinColumnAnnotationToJoinColumnMetadata( |
||||
944 | ReflectionProperty $reflectionProperty, |
||||
945 | Annotation\JoinColumn $joinColumnAnnot, |
||||
946 | Mapping\ClassMetadata $classMetadata |
||||
947 | ) { |
||||
948 | $fieldName = $reflectionProperty->getName(); |
||||
949 | $joinColumn = new Mapping\JoinColumnMetadata(); |
||||
950 | $columnName = empty($joinColumnAnnot->name) |
||||
951 | ? $this->namingStrategy->propertyToColumnName($fieldName, $classMetadata->getClassName()) |
||||
952 | : $joinColumnAnnot->name; |
||||
953 | $referencedColumnName = empty($joinColumnAnnot->referencedColumnName) |
||||
954 | ? $this->namingStrategy->referenceColumnName() |
||||
955 | : $joinColumnAnnot->referencedColumnName; |
||||
956 | |||||
957 | $joinColumn->setColumnName($columnName); |
||||
958 | $joinColumn->setReferencedColumnName($referencedColumnName); |
||||
959 | $joinColumn->setNullable($joinColumnAnnot->nullable); |
||||
960 | $joinColumn->setUnique($joinColumnAnnot->unique); |
||||
961 | |||||
962 | if (! empty($joinColumnAnnot->fieldName)) { |
||||
963 | $joinColumn->setAliasedName($joinColumnAnnot->fieldName); |
||||
964 | } |
||||
965 | |||||
966 | if (! empty($joinColumnAnnot->columnDefinition)) { |
||||
967 | $joinColumn->setColumnDefinition($joinColumnAnnot->columnDefinition); |
||||
968 | } |
||||
969 | |||||
970 | if ($joinColumnAnnot->onDelete) { |
||||
971 | $joinColumn->setOnDelete(strtoupper($joinColumnAnnot->onDelete)); |
||||
972 | } |
||||
973 | |||||
974 | return $joinColumn; |
||||
975 | } |
||||
976 | |||||
977 | /** |
||||
978 | * Parses the given method. |
||||
979 | * |
||||
980 | * @return string[] |
||||
981 | */ |
||||
982 | private function getMethodCallbacks(ReflectionMethod $method) |
||||
0 ignored issues
–
show
|
|||||
983 | { |
||||
984 | $annotations = $this->getMethodAnnotations($method); |
||||
985 | $events = [ |
||||
986 | Events::prePersist => Annotation\PrePersist::class, |
||||
987 | Events::postPersist => Annotation\PostPersist::class, |
||||
988 | Events::preUpdate => Annotation\PreUpdate::class, |
||||
989 | Events::postUpdate => Annotation\PostUpdate::class, |
||||
990 | Events::preRemove => Annotation\PreRemove::class, |
||||
991 | Events::postRemove => Annotation\PostRemove::class, |
||||
992 | Events::postLoad => Annotation\PostLoad::class, |
||||
993 | Events::preFlush => Annotation\PreFlush::class, |
||||
994 | ]; |
||||
995 | |||||
996 | // Check for callbacks |
||||
997 | $callbacks = []; |
||||
998 | |||||
999 | foreach ($events as $eventName => $annotationClassName) { |
||||
1000 | if (isset($annotations[$annotationClassName]) || $method->getName() === $eventName) { |
||||
1001 | $callbacks[] = $eventName; |
||||
1002 | } |
||||
1003 | } |
||||
1004 | |||||
1005 | return $callbacks; |
||||
1006 | } |
||||
1007 | |||||
1008 | /** |
||||
1009 | * Attempts to resolve the fetch mode. |
||||
1010 | * |
||||
1011 | * @param string $className The class name. |
||||
1012 | * @param string $fetchMode The fetch mode. |
||||
1013 | * |
||||
1014 | * @return int The fetch mode as defined in ClassMetadata. |
||||
1015 | * |
||||
1016 | * @throws Mapping\MappingException If the fetch mode is not valid. |
||||
1017 | */ |
||||
1018 | private function getFetchMode($className, $fetchMode) |
||||
1019 | { |
||||
1020 | $fetchModeConstant = sprintf('%s::%s', Mapping\FetchMode::class, $fetchMode); |
||||
1021 | |||||
1022 | if (! defined($fetchModeConstant)) { |
||||
1023 | throw Mapping\MappingException::invalidFetchMode($className, $fetchMode); |
||||
1024 | } |
||||
1025 | |||||
1026 | return constant($fetchModeConstant); |
||||
1027 | } |
||||
1028 | |||||
1029 | /** |
||||
1030 | * @param string $className The class name. |
||||
1031 | * @param string $fieldName The field name. |
||||
1032 | * @param string[] $originalCascades The original unprocessed field cascades. |
||||
1033 | * |
||||
1034 | * @return string[] The processed field cascades. |
||||
1035 | * |
||||
1036 | * @throws Mapping\MappingException If a cascade option is not valid. |
||||
1037 | */ |
||||
1038 | private function getCascade(string $className, string $fieldName, array $originalCascades) |
||||
1039 | { |
||||
1040 | $cascadeTypes = ['remove', 'persist', 'refresh']; |
||||
1041 | $cascades = array_map('strtolower', $originalCascades); |
||||
1042 | |||||
1043 | if (in_array('all', $cascades, true)) { |
||||
1044 | $cascades = $cascadeTypes; |
||||
1045 | } |
||||
1046 | |||||
1047 | if (count($cascades) !== count(array_intersect($cascades, $cascadeTypes))) { |
||||
1048 | $diffCascades = array_diff($cascades, array_intersect($cascades, $cascadeTypes)); |
||||
1049 | |||||
1050 | throw Mapping\MappingException::invalidCascadeOption($diffCascades, $className, $fieldName); |
||||
1051 | } |
||||
1052 | |||||
1053 | return $cascades; |
||||
1054 | } |
||||
1055 | |||||
1056 | /** |
||||
1057 | * @return Annotation\Annotation[] |
||||
1058 | */ |
||||
1059 | private function getClassAnnotations(ReflectionClass $reflectionClass) |
||||
1060 | { |
||||
1061 | $classAnnotations = $this->reader->getClassAnnotations($reflectionClass); |
||||
1062 | |||||
1063 | foreach ($classAnnotations as $key => $annot) { |
||||
1064 | if (! is_numeric($key)) { |
||||
1065 | continue; |
||||
1066 | } |
||||
1067 | |||||
1068 | $classAnnotations[get_class($annot)] = $annot; |
||||
1069 | } |
||||
1070 | |||||
1071 | return $classAnnotations; |
||||
1072 | } |
||||
1073 | |||||
1074 | /** |
||||
1075 | * @return Annotation\Annotation[] |
||||
1076 | */ |
||||
1077 | private function getPropertyAnnotations(ReflectionProperty $reflectionProperty) |
||||
1078 | { |
||||
1079 | $propertyAnnotations = $this->reader->getPropertyAnnotations($reflectionProperty); |
||||
1080 | |||||
1081 | foreach ($propertyAnnotations as $key => $annot) { |
||||
1082 | if (! is_numeric($key)) { |
||||
1083 | continue; |
||||
1084 | } |
||||
1085 | |||||
1086 | $propertyAnnotations[get_class($annot)] = $annot; |
||||
1087 | } |
||||
1088 | |||||
1089 | return $propertyAnnotations; |
||||
1090 | } |
||||
1091 | |||||
1092 | /** |
||||
1093 | * @return Annotation\Annotation[] |
||||
1094 | */ |
||||
1095 | private function getMethodAnnotations(ReflectionMethod $reflectionMethod) |
||||
1096 | { |
||||
1097 | $methodAnnotations = $this->reader->getMethodAnnotations($reflectionMethod); |
||||
1098 | |||||
1099 | foreach ($methodAnnotations as $key => $annot) { |
||||
1100 | if (! is_numeric($key)) { |
||||
1101 | continue; |
||||
1102 | } |
||||
1103 | |||||
1104 | $methodAnnotations[get_class($annot)] = $annot; |
||||
1105 | } |
||||
1106 | |||||
1107 | return $methodAnnotations; |
||||
1108 | } |
||||
1109 | } |
||||
1110 |