1 | <?php /** @noinspection ALL */ |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace Doctrine\ORM\Mapping\Driver; |
||||||
6 | |||||||
7 | use Doctrine\Common\Annotations\AnnotationReader; |
||||||
8 | use Doctrine\Common\Annotations\Reader; |
||||||
9 | use Doctrine\ORM\Annotation; |
||||||
10 | use Doctrine\ORM\Cache\Exception\CacheException; |
||||||
11 | use Doctrine\ORM\Events; |
||||||
12 | use Doctrine\ORM\Mapping; |
||||||
13 | use Doctrine\ORM\Mapping\Builder; |
||||||
14 | use FilesystemIterator; |
||||||
15 | use RecursiveDirectoryIterator; |
||||||
16 | use RecursiveIteratorIterator; |
||||||
17 | use RecursiveRegexIterator; |
||||||
18 | use ReflectionClass; |
||||||
19 | use ReflectionException; |
||||||
20 | use ReflectionMethod; |
||||||
21 | use ReflectionProperty; |
||||||
22 | use RegexIterator; |
||||||
23 | use RuntimeException; |
||||||
24 | use UnexpectedValueException; |
||||||
25 | use function array_diff; |
||||||
26 | use function array_intersect; |
||||||
27 | use function array_map; |
||||||
28 | use function array_merge; |
||||||
29 | use function array_unique; |
||||||
30 | use function class_exists; |
||||||
31 | use function constant; |
||||||
32 | use function count; |
||||||
33 | use function defined; |
||||||
34 | use function get_class; |
||||||
35 | use function get_declared_classes; |
||||||
36 | use function in_array; |
||||||
37 | use function is_dir; |
||||||
38 | use function is_numeric; |
||||||
39 | use function preg_match; |
||||||
40 | use function preg_quote; |
||||||
41 | use function realpath; |
||||||
42 | use function sprintf; |
||||||
43 | use function str_replace; |
||||||
44 | use function strpos; |
||||||
45 | |||||||
46 | /** |
||||||
47 | * The AnnotationDriver reads the mapping metadata from docblock annotations. |
||||||
48 | */ |
||||||
49 | class AnnotationDriver implements MappingDriver |
||||||
50 | { |
||||||
51 | /** @var int[] */ |
||||||
52 | protected $entityAnnotationClasses = [ |
||||||
53 | Annotation\Entity::class => 1, |
||||||
54 | Annotation\MappedSuperclass::class => 2, |
||||||
55 | ]; |
||||||
56 | |||||||
57 | /** |
||||||
58 | * The AnnotationReader. |
||||||
59 | * |
||||||
60 | * @var AnnotationReader |
||||||
61 | */ |
||||||
62 | protected $reader; |
||||||
63 | |||||||
64 | /** |
||||||
65 | * The paths where to look for mapping files. |
||||||
66 | * |
||||||
67 | * @var string[] |
||||||
68 | */ |
||||||
69 | protected $paths = []; |
||||||
70 | |||||||
71 | /** |
||||||
72 | * The paths excluded from path where to look for mapping files. |
||||||
73 | * |
||||||
74 | * @var string[] |
||||||
75 | */ |
||||||
76 | protected $excludePaths = []; |
||||||
77 | |||||||
78 | /** |
||||||
79 | * The file extension of mapping documents. |
||||||
80 | * |
||||||
81 | * @var string |
||||||
82 | */ |
||||||
83 | protected $fileExtension = '.php'; |
||||||
84 | |||||||
85 | /** |
||||||
86 | * Cache for AnnotationDriver#getAllClassNames(). |
||||||
87 | * |
||||||
88 | * @var string[]|null |
||||||
89 | */ |
||||||
90 | protected $classNames; |
||||||
91 | |||||||
92 | /** |
||||||
93 | * Initializes a new AnnotationDriver that uses the given AnnotationReader for reading |
||||||
94 | * docblock annotations. |
||||||
95 | * |
||||||
96 | * @param Reader $reader The AnnotationReader to use, duck-typed. |
||||||
97 | * @param string|string[]|null $paths One or multiple paths where mapping classes can be found. |
||||||
98 | */ |
||||||
99 | 2297 | public function __construct(Reader $reader, $paths = null) |
|||||
100 | { |
||||||
101 | 2297 | $this->reader = $reader; |
|||||
102 | |||||||
103 | 2297 | if ($paths) { |
|||||
104 | 2211 | $this->addPaths((array) $paths); |
|||||
105 | } |
||||||
106 | 2297 | } |
|||||
107 | |||||||
108 | /** |
||||||
109 | * Appends lookup paths to metadata driver. |
||||||
110 | * |
||||||
111 | * @param string[] $paths |
||||||
112 | */ |
||||||
113 | 2215 | public function addPaths(array $paths) |
|||||
114 | { |
||||||
115 | 2215 | $this->paths = array_unique(array_merge($this->paths, $paths)); |
|||||
116 | 2215 | } |
|||||
117 | |||||||
118 | /** |
||||||
119 | * Retrieves the defined metadata lookup paths. |
||||||
120 | * |
||||||
121 | * @return string[] |
||||||
122 | */ |
||||||
123 | public function getPaths() |
||||||
124 | { |
||||||
125 | return $this->paths; |
||||||
126 | } |
||||||
127 | |||||||
128 | /** |
||||||
129 | * Append exclude lookup paths to metadata driver. |
||||||
130 | * |
||||||
131 | * @param string[] $paths |
||||||
132 | */ |
||||||
133 | public function addExcludePaths(array $paths) |
||||||
134 | { |
||||||
135 | $this->excludePaths = array_unique(array_merge($this->excludePaths, $paths)); |
||||||
136 | } |
||||||
137 | |||||||
138 | /** |
||||||
139 | * Retrieve the defined metadata lookup exclude paths. |
||||||
140 | * |
||||||
141 | * @return string[] |
||||||
142 | */ |
||||||
143 | public function getExcludePaths() |
||||||
144 | { |
||||||
145 | return $this->excludePaths; |
||||||
146 | } |
||||||
147 | |||||||
148 | /** |
||||||
149 | * Retrieve the current annotation reader |
||||||
150 | * |
||||||
151 | * @return Reader |
||||||
152 | */ |
||||||
153 | 1 | public function getReader() |
|||||
154 | { |
||||||
155 | 1 | return $this->reader; |
|||||
156 | } |
||||||
157 | |||||||
158 | /** |
||||||
159 | * Gets the file extension used to look for mapping files under. |
||||||
160 | * |
||||||
161 | * @return string |
||||||
162 | */ |
||||||
163 | public function getFileExtension() |
||||||
164 | { |
||||||
165 | return $this->fileExtension; |
||||||
166 | } |
||||||
167 | |||||||
168 | /** |
||||||
169 | * Sets the file extension used to look for mapping files under. |
||||||
170 | * |
||||||
171 | * @param string $fileExtension The file extension to set. |
||||||
172 | */ |
||||||
173 | public function setFileExtension($fileExtension) |
||||||
174 | { |
||||||
175 | $this->fileExtension = $fileExtension; |
||||||
176 | } |
||||||
177 | |||||||
178 | /** |
||||||
179 | * Returns whether the class with the specified name is transient. Only non-transient |
||||||
180 | * classes, that is entities and mapped superclasses, should have their metadata loaded. |
||||||
181 | * |
||||||
182 | * A class is non-transient if it is annotated with an annotation |
||||||
183 | * from the {@see AnnotationDriver::entityAnnotationClasses}. |
||||||
184 | * |
||||||
185 | * @param string $className |
||||||
186 | * |
||||||
187 | * @throws ReflectionException |
||||||
188 | */ |
||||||
189 | 193 | public function isTransient($className) : bool |
|||||
190 | { |
||||||
191 | 193 | $classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className)); |
|||||
192 | |||||||
193 | 193 | foreach ($classAnnotations as $annotation) { |
|||||
194 | 188 | if (isset($this->entityAnnotationClasses[get_class($annotation)])) { |
|||||
195 | 188 | return false; |
|||||
196 | } |
||||||
197 | } |
||||||
198 | |||||||
199 | 12 | return true; |
|||||
200 | } |
||||||
201 | |||||||
202 | /** |
||||||
203 | * {@inheritdoc} |
||||||
204 | * |
||||||
205 | * @throws ReflectionException |
||||||
206 | */ |
||||||
207 | 60 | public function getAllClassNames() : array |
|||||
208 | { |
||||||
209 | 60 | if ($this->classNames !== null) { |
|||||
210 | 45 | return $this->classNames; |
|||||
211 | } |
||||||
212 | |||||||
213 | 60 | if (! $this->paths) { |
|||||
214 | throw Mapping\MappingException::pathRequired(); |
||||||
215 | } |
||||||
216 | |||||||
217 | 60 | $classes = []; |
|||||
218 | 60 | $includedFiles = []; |
|||||
219 | |||||||
220 | 60 | foreach ($this->paths as $path) { |
|||||
221 | 60 | if (! is_dir($path)) { |
|||||
222 | throw Mapping\MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path); |
||||||
223 | } |
||||||
224 | |||||||
225 | 60 | $iterator = new RegexIterator( |
|||||
226 | 60 | new RecursiveIteratorIterator( |
|||||
227 | 60 | new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS), |
|||||
228 | 60 | RecursiveIteratorIterator::LEAVES_ONLY |
|||||
229 | ), |
||||||
230 | 60 | '/^.+' . preg_quote($this->fileExtension) . '$/i', |
|||||
231 | 60 | RecursiveRegexIterator::GET_MATCH |
|||||
232 | ); |
||||||
233 | |||||||
234 | 60 | foreach ($iterator as $file) { |
|||||
235 | 60 | $sourceFile = $file[0]; |
|||||
236 | |||||||
237 | 60 | if (! preg_match('(^phar:)i', $sourceFile)) { |
|||||
238 | 60 | $sourceFile = realpath($sourceFile); |
|||||
239 | } |
||||||
240 | |||||||
241 | 60 | foreach ($this->excludePaths as $excludePath) { |
|||||
242 | $exclude = str_replace('\\', '/', realpath($excludePath)); |
||||||
243 | $current = str_replace('\\', '/', $sourceFile); |
||||||
244 | |||||||
245 | if (strpos($current, $exclude) !== false) { |
||||||
246 | continue 2; |
||||||
247 | } |
||||||
248 | } |
||||||
249 | |||||||
250 | 60 | require_once $sourceFile; |
|||||
251 | |||||||
252 | 60 | $includedFiles[] = $sourceFile; |
|||||
253 | } |
||||||
254 | } |
||||||
255 | |||||||
256 | 60 | $declared = get_declared_classes(); |
|||||
257 | |||||||
258 | 60 | foreach ($declared as $className) { |
|||||
259 | 60 | $reflectionClass = new ReflectionClass($className); |
|||||
260 | 60 | $sourceFile = $reflectionClass->getFileName(); |
|||||
261 | |||||||
262 | 60 | if (in_array($sourceFile, $includedFiles, true) && ! $this->isTransient($className)) { |
|||||
263 | 60 | $classes[] = $className; |
|||||
264 | } |
||||||
265 | } |
||||||
266 | |||||||
267 | 60 | $this->classNames = $classes; |
|||||
268 | |||||||
269 | 60 | return $classes; |
|||||
270 | } |
||||||
271 | |||||||
272 | /** |
||||||
273 | * {@inheritDoc} |
||||||
274 | * |
||||||
275 | * @throws CacheException |
||||||
276 | * @throws Mapping\MappingException |
||||||
277 | * @throws ReflectionException |
||||||
278 | * @throws RuntimeException |
||||||
279 | * @throws UnexpectedValueException |
||||||
280 | */ |
||||||
281 | 379 | public function loadMetadataForClass( |
|||||
282 | string $className, |
||||||
283 | ?Mapping\ComponentMetadata $parent, |
||||||
284 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||||
285 | ) : Mapping\ComponentMetadata { |
||||||
286 | 379 | $reflectionClass = new ReflectionClass($className); |
|||||
287 | 379 | $metadata = new Mapping\ClassMetadata($className, $parent, $metadataBuildingContext); |
|||||
288 | 379 | $classAnnotations = $this->getClassAnnotations($reflectionClass); |
|||||
289 | 379 | $classMetadata = $this->convertClassAnnotationsToClassMetadata( |
|||||
290 | 379 | $classAnnotations, |
|||||
291 | 379 | $reflectionClass, |
|||||
292 | 379 | $metadata, |
|||||
293 | 379 | $metadataBuildingContext |
|||||
294 | ); |
||||||
295 | |||||||
296 | // Evaluate @Cache annotation |
||||||
297 | 373 | if (isset($classAnnotations[Annotation\Cache::class])) { |
|||||
298 | 18 | $cacheBuilder = new Builder\CacheMetadataBuilder($metadataBuildingContext); |
|||||
299 | |||||||
300 | $cacheBuilder |
||||||
301 | 18 | ->withComponentMetadata($metadata) |
|||||
302 | 18 | ->withCacheAnnotation($classAnnotations[Annotation\Cache::class]); |
|||||
303 | |||||||
304 | 18 | $metadata->setCache($cacheBuilder->build()); |
|||||
305 | } |
||||||
306 | |||||||
307 | // Evaluate annotations on properties/fields |
||||||
308 | /** @var ReflectionProperty $reflProperty */ |
||||||
309 | 373 | foreach ($reflectionClass->getProperties() as $reflectionProperty) { |
|||||
310 | 373 | if ($reflectionProperty->getDeclaringClass()->getName() !== $reflectionClass->getName()) { |
|||||
311 | 74 | continue; |
|||||
312 | } |
||||||
313 | |||||||
314 | 373 | $propertyAnnotations = $this->getPropertyAnnotations($reflectionProperty); |
|||||
315 | 372 | $property = $this->convertPropertyAnnotationsToProperty( |
|||||
316 | 372 | $propertyAnnotations, |
|||||
317 | 372 | $reflectionProperty, |
|||||
318 | 372 | $classMetadata, |
|||||
319 | 372 | $metadataBuildingContext |
|||||
320 | ); |
||||||
321 | |||||||
322 | 371 | if ($classMetadata->isMappedSuperclass && |
|||||
323 | 371 | $property instanceof Mapping\ToManyAssociationMetadata && |
|||||
324 | 371 | ! $property->isOwningSide()) { |
|||||
325 | 1 | throw Mapping\MappingException::illegalToManyAssociationOnMappedSuperclass( |
|||||
326 | 1 | $classMetadata->getClassName(), |
|||||
327 | 1 | $property->getName() |
|||||
328 | ); |
||||||
329 | } |
||||||
330 | |||||||
331 | 370 | $metadata->addProperty($property); |
|||||
332 | } |
||||||
333 | |||||||
334 | 370 | $this->attachPropertyOverrides($classAnnotations, $reflectionClass, $metadata, $metadataBuildingContext); |
|||||
335 | |||||||
336 | 370 | return $classMetadata; |
|||||
337 | } |
||||||
338 | |||||||
339 | /** |
||||||
340 | * @param Annotation\Annotation[] $classAnnotations |
||||||
341 | * |
||||||
342 | * @throws Mapping\MappingException |
||||||
343 | * @throws UnexpectedValueException |
||||||
344 | * @throws ReflectionException |
||||||
345 | */ |
||||||
346 | 379 | private function convertClassAnnotationsToClassMetadata( |
|||||
347 | array $classAnnotations, |
||||||
348 | ReflectionClass $reflectionClass, |
||||||
349 | Mapping\ClassMetadata $metadata, |
||||||
350 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||||
351 | ) : Mapping\ClassMetadata { |
||||||
352 | switch (true) { |
||||||
353 | 379 | case isset($classAnnotations[Annotation\Entity::class]): |
|||||
354 | 372 | return $this->convertClassAnnotationsToEntityClassMetadata( |
|||||
355 | 372 | $classAnnotations, |
|||||
356 | 372 | $reflectionClass, |
|||||
357 | 372 | $metadata, |
|||||
358 | 372 | $metadataBuildingContext |
|||||
359 | ); |
||||||
360 | |||||||
361 | break; |
||||||
362 | |||||||
363 | 29 | case isset($classAnnotations[Annotation\MappedSuperclass::class]): |
|||||
364 | 23 | return $this->convertClassAnnotationsToMappedSuperClassMetadata( |
|||||
365 | 23 | $classAnnotations, |
|||||
366 | 23 | $reflectionClass, |
|||||
367 | 23 | $metadata |
|||||
368 | ); |
||||||
369 | 6 | case isset($classAnnotations[Annotation\Embeddable::class]): |
|||||
370 | return $this->convertClassAnnotationsToEmbeddableClassMetadata( |
||||||
371 | $classAnnotations, |
||||||
372 | $reflectionClass, |
||||||
373 | $metadata |
||||||
374 | ); |
||||||
375 | default: |
||||||
376 | 6 | throw Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass($reflectionClass->getName()); |
|||||
377 | } |
||||||
378 | } |
||||||
379 | |||||||
380 | /** |
||||||
381 | * @param Annotation\Annotation[] $classAnnotations |
||||||
382 | * |
||||||
383 | * @return Mapping\ClassMetadata |
||||||
384 | * |
||||||
385 | * @throws Mapping\MappingException |
||||||
386 | * @throws ReflectionException |
||||||
387 | * @throws UnexpectedValueException |
||||||
388 | */ |
||||||
389 | 372 | private function convertClassAnnotationsToEntityClassMetadata( |
|||||
390 | array $classAnnotations, |
||||||
391 | ReflectionClass $reflectionClass, |
||||||
392 | Mapping\ClassMetadata $metadata, |
||||||
393 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||||
394 | ) { |
||||||
395 | /** @var Annotation\Entity $entityAnnot */ |
||||||
396 | 372 | $entityAnnot = $classAnnotations[Annotation\Entity::class]; |
|||||
397 | |||||||
398 | 372 | if ($entityAnnot->repositoryClass !== null) { |
|||||
399 | 3 | $metadata->setCustomRepositoryClassName($entityAnnot->repositoryClass); |
|||||
400 | } |
||||||
401 | |||||||
402 | 372 | if ($entityAnnot->readOnly) { |
|||||
403 | 1 | $metadata->asReadOnly(); |
|||||
404 | } |
||||||
405 | |||||||
406 | 372 | $metadata->isMappedSuperclass = false; |
|||||
407 | 372 | $metadata->isEmbeddedClass = false; |
|||||
408 | |||||||
409 | // Process table information |
||||||
410 | 372 | $parent = $metadata->getParent(); |
|||||
411 | |||||||
412 | 372 | if ($parent && $parent->inheritanceType === Mapping\InheritanceType::SINGLE_TABLE) { |
|||||
413 | // Handle the case where a middle mapped super class inherits from a single table inheritance tree. |
||||||
414 | do { |
||||||
415 | 29 | if (! $parent->isMappedSuperclass) { |
|||||
416 | 29 | $metadata->setTable($parent->table); |
|||||
417 | |||||||
418 | 29 | break; |
|||||
419 | } |
||||||
420 | |||||||
421 | 4 | $parent = $parent->getParent(); |
|||||
422 | 29 | } while ($parent !== null); |
|||||
423 | } else { |
||||||
424 | 372 | $tableBuilder = new Builder\TableMetadataBuilder($metadataBuildingContext); |
|||||
425 | |||||||
426 | $tableBuilder |
||||||
427 | 372 | ->withEntityClassMetadata($metadata) |
|||||
428 | 372 | ->withTableAnnotation($classAnnotations[Annotation\Table::class] ?? null); |
|||||
429 | |||||||
430 | 372 | $metadata->setTable($tableBuilder->build()); |
|||||
431 | } |
||||||
432 | |||||||
433 | // Evaluate @ChangeTrackingPolicy annotation |
||||||
434 | 372 | if (isset($classAnnotations[Annotation\ChangeTrackingPolicy::class])) { |
|||||
435 | 6 | $changeTrackingAnnot = $classAnnotations[Annotation\ChangeTrackingPolicy::class]; |
|||||
436 | |||||||
437 | 6 | $metadata->setChangeTrackingPolicy( |
|||||
438 | 6 | constant(sprintf('%s::%s', Mapping\ChangeTrackingPolicy::class, $changeTrackingAnnot->value)) |
|||||
439 | ); |
||||||
440 | } |
||||||
441 | |||||||
442 | // Evaluate @InheritanceType annotation |
||||||
443 | 372 | if (isset($classAnnotations[Annotation\InheritanceType::class])) { |
|||||
444 | 80 | $inheritanceTypeAnnot = $classAnnotations[Annotation\InheritanceType::class]; |
|||||
445 | |||||||
446 | 80 | $metadata->setInheritanceType( |
|||||
447 | 80 | constant(sprintf('%s::%s', Mapping\InheritanceType::class, $inheritanceTypeAnnot->value)) |
|||||
448 | ); |
||||||
449 | |||||||
450 | 80 | if ($metadata->inheritanceType !== Mapping\InheritanceType::NONE) { |
|||||
451 | 80 | $discriminatorColumnBuilder = new Builder\DiscriminatorColumnMetadataBuilder($metadataBuildingContext); |
|||||
452 | |||||||
453 | $discriminatorColumnBuilder |
||||||
454 | 80 | ->withComponentMetadata($metadata) |
|||||
455 | 80 | ->withDiscriminatorColumnAnnotation($classAnnotations[Annotation\DiscriminatorColumn::class] ?? null); |
|||||
456 | |||||||
457 | 80 | $metadata->setDiscriminatorColumn($discriminatorColumnBuilder->build()); |
|||||
458 | |||||||
459 | // Evaluate DiscriminatorMap annotation |
||||||
460 | 80 | if (isset($classAnnotations[Annotation\DiscriminatorMap::class])) { |
|||||
461 | 77 | $discriminatorMapAnnotation = $classAnnotations[Annotation\DiscriminatorMap::class]; |
|||||
462 | 77 | $discriminatorMap = $discriminatorMapAnnotation->value; |
|||||
463 | |||||||
464 | 77 | $metadata->setDiscriminatorMap($discriminatorMap); |
|||||
465 | } |
||||||
466 | } |
||||||
467 | } |
||||||
468 | |||||||
469 | 372 | $this->attachLifecycleCallbacks($classAnnotations, $reflectionClass, $metadata); |
|||||
470 | 372 | $this->attachEntityListeners($classAnnotations, $metadata); |
|||||
471 | |||||||
472 | 372 | return $metadata; |
|||||
473 | } |
||||||
474 | |||||||
475 | /** |
||||||
476 | * @param Annotation\Annotation[] $classAnnotations |
||||||
477 | * |
||||||
478 | * @throws Mapping\MappingException |
||||||
479 | * @throws ReflectionException |
||||||
480 | */ |
||||||
481 | 23 | private function convertClassAnnotationsToMappedSuperClassMetadata( |
|||||
482 | array $classAnnotations, |
||||||
483 | ReflectionClass $reflectionClass, |
||||||
484 | Mapping\ClassMetadata $metadata |
||||||
485 | ) : Mapping\ClassMetadata { |
||||||
486 | /** @var Annotation\MappedSuperclass $mappedSuperclassAnnot */ |
||||||
487 | 23 | $mappedSuperclassAnnot = $classAnnotations[Annotation\MappedSuperclass::class]; |
|||||
488 | |||||||
489 | 23 | if ($mappedSuperclassAnnot->repositoryClass !== null) { |
|||||
490 | 2 | $metadata->setCustomRepositoryClassName($mappedSuperclassAnnot->repositoryClass); |
|||||
491 | } |
||||||
492 | |||||||
493 | 23 | $metadata->isMappedSuperclass = true; |
|||||
494 | 23 | $metadata->isEmbeddedClass = false; |
|||||
495 | |||||||
496 | 23 | $this->attachLifecycleCallbacks($classAnnotations, $reflectionClass, $metadata); |
|||||
497 | 23 | $this->attachEntityListeners($classAnnotations, $metadata); |
|||||
498 | |||||||
499 | 23 | return $metadata; |
|||||
500 | } |
||||||
501 | |||||||
502 | /** |
||||||
503 | * @param Annotation\Annotation[] $classAnnotations |
||||||
504 | */ |
||||||
505 | private function convertClassAnnotationsToEmbeddableClassMetadata( |
||||||
506 | array $classAnnotations, |
||||||
507 | ReflectionClass $reflectionClass, |
||||||
508 | Mapping\ClassMetadata $metadata |
||||||
509 | ) : Mapping\ClassMetadata { |
||||||
510 | $metadata->isMappedSuperclass = false; |
||||||
511 | $metadata->isEmbeddedClass = true; |
||||||
512 | |||||||
513 | return $metadata; |
||||||
514 | } |
||||||
515 | |||||||
516 | /** |
||||||
517 | * @param Annotation\Annotation[] $propertyAnnotations |
||||||
518 | * |
||||||
519 | * @todo guilhermeblanco Remove nullable typehint once embeddables are back |
||||||
520 | */ |
||||||
521 | 372 | private function convertPropertyAnnotationsToProperty( |
|||||
522 | array $propertyAnnotations, |
||||||
523 | ReflectionProperty $reflectionProperty, |
||||||
524 | Mapping\ClassMetadata $metadata, |
||||||
525 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||||
526 | ) : ?Mapping\Property { |
||||||
527 | switch (true) { |
||||||
528 | 372 | case isset($propertyAnnotations[Annotation\Column::class]): |
|||||
529 | 367 | $fieldBuilder = new Builder\FieldMetadataBuilder($metadataBuildingContext); |
|||||
530 | $fieldMetadata = $fieldBuilder |
||||||
531 | 367 | ->withComponentMetadata($metadata) |
|||||
532 | 367 | ->withFieldName($reflectionProperty->getName()) |
|||||
533 | 367 | ->withColumnAnnotation($propertyAnnotations[Annotation\Column::class]) |
|||||
534 | 367 | ->withIdAnnotation($propertyAnnotations[Annotation\Id::class] ?? null) |
|||||
535 | 367 | ->withVersionAnnotation($propertyAnnotations[Annotation\Version::class] ?? null) |
|||||
536 | 367 | ->withGeneratedValueAnnotation($propertyAnnotations[Annotation\GeneratedValue::class] ?? null) |
|||||
537 | 367 | ->withSequenceGeneratorAnnotation($propertyAnnotations[Annotation\SequenceGenerator::class] ?? null) |
|||||
538 | 367 | ->withCustomIdGeneratorAnnotation($propertyAnnotations[Annotation\CustomIdGenerator::class] ?? null) |
|||||
539 | 367 | ->build(); |
|||||
540 | |||||||
541 | // Prevent column duplication |
||||||
542 | 367 | $columnName = $fieldMetadata->getColumnName(); |
|||||
543 | |||||||
544 | 367 | if ($metadata->checkPropertyDuplication($columnName)) { |
|||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
545 | throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName); |
||||||
546 | } |
||||||
547 | |||||||
548 | 367 | $metadata->fieldNames[$fieldMetadata->getColumnName()] = $fieldMetadata->getName(); |
|||||
549 | |||||||
550 | 367 | return $fieldMetadata; |
|||||
551 | 254 | case isset($propertyAnnotations[Annotation\OneToOne::class]): |
|||||
552 | 111 | $oneToOneAssociationBuilder = new Builder\OneToOneAssociationMetadataBuilder($metadataBuildingContext); |
|||||
553 | $associationMetadata = $oneToOneAssociationBuilder |
||||||
554 | 111 | ->withComponentMetadata($metadata) |
|||||
555 | 111 | ->withFieldName($reflectionProperty->getName()) |
|||||
556 | 111 | ->withOneToOneAnnotation($propertyAnnotations[Annotation\OneToOne::class] ?? null) |
|||||
0 ignored issues
–
show
It seems like
$propertyAnnotations[Doc...neToOne::class] ?? null can also be of type null ; however, parameter $oneToOneAnnotation of Doctrine\ORM\Mapping\Bui...ithOneToOneAnnotation() does only seem to accept Doctrine\ORM\Annotation\OneToOne , 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...
|
|||||||
557 | 111 | ->withIdAnnotation($propertyAnnotations[Annotation\Id::class] ?? null) |
|||||
558 | 111 | ->withCacheAnnotation($propertyAnnotations[Annotation\Cache::class] ?? null) |
|||||
559 | 111 | ->withJoinColumnsAnnotation($propertyAnnotations[Annotation\JoinColumns::class] ?? null) |
|||||
560 | 111 | ->withJoinColumnAnnotation($propertyAnnotations[Annotation\JoinColumn::class] ?? null) |
|||||
561 | 111 | ->build(); |
|||||
562 | |||||||
563 | // Prevent column duplication |
||||||
564 | 111 | foreach ($associationMetadata->getJoinColumns() as $joinColumnMetadata) { |
|||||
565 | 105 | $columnName = $joinColumnMetadata->getColumnName(); |
|||||
566 | |||||||
567 | // @todo guilhermeblanco Open an issue to discuss making this scenario impossible. |
||||||
568 | //if ($metadata->checkPropertyDuplication($columnName)) { |
||||||
569 | // throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName); |
||||||
570 | //} |
||||||
571 | |||||||
572 | 105 | if ($associationMetadata->isOwningSide()) { |
|||||
573 | 105 | $metadata->fieldNames[$columnName] = $associationMetadata->getName(); |
|||||
574 | } |
||||||
575 | } |
||||||
576 | |||||||
577 | 111 | return $associationMetadata; |
|||||
578 | 202 | case isset($propertyAnnotations[Annotation\ManyToOne::class]): |
|||||
579 | 141 | $manyToOneAssociationBuilder = new Builder\ManyToOneAssociationMetadataBuilder($metadataBuildingContext); |
|||||
580 | $associationMetadata = $manyToOneAssociationBuilder |
||||||
581 | 141 | ->withComponentMetadata($metadata) |
|||||
582 | 141 | ->withFieldName($reflectionProperty->getName()) |
|||||
583 | 141 | ->withManyToOneAnnotation($propertyAnnotations[Annotation\ManyToOne::class] ?? null) |
|||||
0 ignored issues
–
show
It seems like
$propertyAnnotations[Doc...nyToOne::class] ?? null can also be of type null ; however, parameter $manyToOneAnnotation of Doctrine\ORM\Mapping\Bui...thManyToOneAnnotation() does only seem to accept Doctrine\ORM\Annotation\ManyToOne , 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...
|
|||||||
584 | 141 | ->withIdAnnotation($propertyAnnotations[Annotation\Id::class] ?? null) |
|||||
585 | 141 | ->withCacheAnnotation($propertyAnnotations[Annotation\Cache::class] ?? null) |
|||||
586 | 141 | ->withJoinColumnsAnnotation($propertyAnnotations[Annotation\JoinColumns::class] ?? null) |
|||||
587 | 141 | ->withJoinColumnAnnotation($propertyAnnotations[Annotation\JoinColumn::class] ?? null) |
|||||
588 | 141 | ->build(); |
|||||
589 | |||||||
590 | // Prevent column duplication |
||||||
591 | 140 | foreach ($associationMetadata->getJoinColumns() as $joinColumnMetadata) { |
|||||
592 | 140 | $columnName = $joinColumnMetadata->getColumnName(); |
|||||
593 | |||||||
594 | // @todo guilhermeblanco Open an issue to discuss making this scenario impossible. |
||||||
595 | //if ($metadata->checkPropertyDuplication($columnName)) { |
||||||
596 | // throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName); |
||||||
597 | //} |
||||||
598 | |||||||
599 | 140 | if ($associationMetadata->isOwningSide()) { |
|||||
600 | 140 | $metadata->fieldNames[$columnName] = $associationMetadata->getName(); |
|||||
601 | } |
||||||
602 | } |
||||||
603 | |||||||
604 | 140 | return $associationMetadata; |
|||||
605 | 163 | case isset($propertyAnnotations[Annotation\OneToMany::class]): |
|||||
606 | 109 | $oneToManyAssociationBuilder = new Builder\OneToManyAssociationMetadataBuilder($metadataBuildingContext); |
|||||
607 | |||||||
608 | return $oneToManyAssociationBuilder |
||||||
609 | 109 | ->withComponentMetadata($metadata) |
|||||
610 | 109 | ->withFieldName($reflectionProperty->getName()) |
|||||
611 | 109 | ->withOneToManyAnnotation($propertyAnnotations[Annotation\OneToMany::class] ?? null) |
|||||
0 ignored issues
–
show
It seems like
$propertyAnnotations[Doc...eToMany::class] ?? null can also be of type null ; however, parameter $oneToManyAnnotation of Doctrine\ORM\Mapping\Bui...thOneToManyAnnotation() does only seem to accept Doctrine\ORM\Annotation\OneToMany , 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...
|
|||||||
612 | 109 | ->withIdAnnotation($propertyAnnotations[Annotation\Id::class] ?? null) |
|||||
613 | 109 | ->withCacheAnnotation($propertyAnnotations[Annotation\Cache::class] ?? null) |
|||||
614 | 109 | ->withOrderByAnnotation($propertyAnnotations[Annotation\OrderBy::class] ?? null) |
|||||
615 | 109 | ->build(); |
|||||
616 | 104 | case isset($propertyAnnotations[Annotation\ManyToMany::class]): |
|||||
617 | 89 | $manyToManyAssociationBuilder = new Builder\ManyToManyAssociationMetadataBuilder($metadataBuildingContext); |
|||||
618 | |||||||
619 | return $manyToManyAssociationBuilder |
||||||
620 | 89 | ->withComponentMetadata($metadata) |
|||||
621 | 89 | ->withFieldName($reflectionProperty->getName()) |
|||||
622 | 89 | ->withManyToManyAnnotation($propertyAnnotations[Annotation\ManyToMany::class] ?? null) |
|||||
0 ignored issues
–
show
It seems like
$propertyAnnotations[Doc...yToMany::class] ?? null can also be of type null ; however, parameter $manyToManyAnnotation of Doctrine\ORM\Mapping\Bui...hManyToManyAnnotation() does only seem to accept Doctrine\ORM\Annotation\ManyToMany , 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...
|
|||||||
623 | 89 | ->withIdAnnotation($propertyAnnotations[Annotation\Id::class] ?? null) |
|||||
624 | 89 | ->withCacheAnnotation($propertyAnnotations[Annotation\Cache::class] ?? null) |
|||||
625 | 89 | ->withJoinTableAnnotation($propertyAnnotations[Annotation\JoinTable::class] ?? null) |
|||||
626 | 89 | ->withOrderByAnnotation($propertyAnnotations[Annotation\OrderBy::class] ?? null) |
|||||
627 | 89 | ->build(); |
|||||
628 | 29 | case isset($propertyAnnotations[Annotation\Embedded::class]): |
|||||
629 | return null; |
||||||
630 | default: |
||||||
631 | 29 | $transientBuilder = new Builder\TransientMetadataBuilder($metadataBuildingContext); |
|||||
632 | |||||||
633 | return $transientBuilder |
||||||
634 | 29 | ->withComponentMetadata($metadata) |
|||||
635 | 29 | ->withFieldName($reflectionProperty->getName()) |
|||||
636 | 29 | ->build(); |
|||||
637 | } |
||||||
638 | } |
||||||
639 | |||||||
640 | /** |
||||||
641 | * @param Annotation\Annotation[] $classAnnotations |
||||||
642 | */ |
||||||
643 | 373 | private function attachLifecycleCallbacks( |
|||||
644 | array $classAnnotations, |
||||||
645 | ReflectionClass $reflectionClass, |
||||||
646 | Mapping\ClassMetadata $metadata |
||||||
647 | ) : void { |
||||||
648 | // Evaluate @HasLifecycleCallbacks annotation |
||||||
649 | 373 | if (isset($classAnnotations[Annotation\HasLifecycleCallbacks::class])) { |
|||||
650 | $eventMap = [ |
||||||
651 | 14 | Events::prePersist => Annotation\PrePersist::class, |
|||||
652 | 14 | Events::postPersist => Annotation\PostPersist::class, |
|||||
653 | 14 | Events::preUpdate => Annotation\PreUpdate::class, |
|||||
654 | 14 | Events::postUpdate => Annotation\PostUpdate::class, |
|||||
655 | 14 | Events::preRemove => Annotation\PreRemove::class, |
|||||
656 | 14 | Events::postRemove => Annotation\PostRemove::class, |
|||||
657 | 14 | Events::postLoad => Annotation\PostLoad::class, |
|||||
658 | 14 | Events::preFlush => Annotation\PreFlush::class, |
|||||
659 | ]; |
||||||
660 | |||||||
661 | /** @var ReflectionMethod $reflectionMethod */ |
||||||
662 | 14 | foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { |
|||||
663 | 13 | $annotations = $this->getMethodAnnotations($reflectionMethod); |
|||||
664 | |||||||
665 | 13 | foreach ($eventMap as $eventName => $annotationClassName) { |
|||||
666 | 13 | if (isset($annotations[$annotationClassName])) { |
|||||
667 | 12 | $metadata->addLifecycleCallback($eventName, $reflectionMethod->getName()); |
|||||
668 | } |
||||||
669 | } |
||||||
670 | } |
||||||
671 | } |
||||||
672 | 373 | } |
|||||
673 | |||||||
674 | /** |
||||||
675 | * @param Annotation\Annotation[] $classAnnotations |
||||||
676 | * |
||||||
677 | * @throws ReflectionException |
||||||
678 | * @throws Mapping\MappingException |
||||||
679 | */ |
||||||
680 | 373 | private function attachEntityListeners( |
|||||
681 | array $classAnnotations, |
||||||
682 | Mapping\ClassMetadata $metadata |
||||||
683 | ) : void { |
||||||
684 | // Evaluate @EntityListeners annotation |
||||||
685 | 373 | if (isset($classAnnotations[Annotation\EntityListeners::class])) { |
|||||
686 | /** @var Annotation\EntityListeners $entityListenersAnnot */ |
||||||
687 | 8 | $entityListenersAnnot = $classAnnotations[Annotation\EntityListeners::class]; |
|||||
688 | $eventMap = [ |
||||||
689 | 8 | Events::prePersist => Annotation\PrePersist::class, |
|||||
690 | 8 | Events::postPersist => Annotation\PostPersist::class, |
|||||
691 | 8 | Events::preUpdate => Annotation\PreUpdate::class, |
|||||
692 | 8 | Events::postUpdate => Annotation\PostUpdate::class, |
|||||
693 | 8 | Events::preRemove => Annotation\PreRemove::class, |
|||||
694 | 8 | Events::postRemove => Annotation\PostRemove::class, |
|||||
695 | 8 | Events::postLoad => Annotation\PostLoad::class, |
|||||
696 | 8 | Events::preFlush => Annotation\PreFlush::class, |
|||||
697 | ]; |
||||||
698 | |||||||
699 | 8 | foreach ($entityListenersAnnot->value as $listenerClassName) { |
|||||
700 | 8 | if (! class_exists($listenerClassName)) { |
|||||
701 | throw Mapping\MappingException::entityListenerClassNotFound( |
||||||
702 | $listenerClassName, |
||||||
703 | $metadata->getClassName() |
||||||
704 | ); |
||||||
705 | } |
||||||
706 | |||||||
707 | 8 | $listenerClass = new ReflectionClass($listenerClassName); |
|||||
708 | |||||||
709 | /** @var ReflectionMethod $reflectionMethod */ |
||||||
710 | 8 | foreach ($listenerClass->getMethods(ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { |
|||||
711 | 8 | $annotations = $this->getMethodAnnotations($reflectionMethod); |
|||||
712 | |||||||
713 | 8 | foreach ($eventMap as $eventName => $annotationClassName) { |
|||||
714 | 8 | if (isset($annotations[$annotationClassName])) { |
|||||
715 | 6 | $metadata->addEntityListener($eventName, $listenerClassName, $reflectionMethod->getName()); |
|||||
716 | } |
||||||
717 | } |
||||||
718 | } |
||||||
719 | } |
||||||
720 | } |
||||||
721 | 373 | } |
|||||
722 | |||||||
723 | /** |
||||||
724 | * @param Annotation\Annotation[] $classAnnotations |
||||||
725 | * |
||||||
726 | * @throws Mapping\MappingException |
||||||
727 | */ |
||||||
728 | 370 | private function attachPropertyOverrides( |
|||||
729 | array $classAnnotations, |
||||||
730 | ReflectionClass $reflectionClass, |
||||||
731 | Mapping\ClassMetadata $metadata, |
||||||
732 | Mapping\ClassMetadataBuildingContext $metadataBuildingContext |
||||||
733 | ) : void { |
||||||
734 | // Evaluate AssociationOverrides annotation |
||||||
735 | 370 | if (isset($classAnnotations[Annotation\AssociationOverrides::class])) { |
|||||
736 | 5 | $associationOverridesAnnot = $classAnnotations[Annotation\AssociationOverrides::class]; |
|||||
737 | |||||||
738 | 5 | foreach ($associationOverridesAnnot->value as $associationOverrideAnnotation) { |
|||||
739 | 5 | $fieldName = $associationOverrideAnnotation->name; |
|||||
740 | 5 | $property = $metadata->getProperty($fieldName); |
|||||
741 | |||||||
742 | 5 | if (! $property) { |
|||||
743 | throw Mapping\MappingException::invalidOverrideFieldName($metadata->getClassName(), $fieldName); |
||||||
744 | } |
||||||
745 | |||||||
746 | 5 | $override = clone $property; |
|||||
747 | |||||||
748 | // Check for JoinColumn/JoinColumns annotations |
||||||
749 | 5 | if ($associationOverrideAnnotation->joinColumns) { |
|||||
750 | 3 | $joinColumnBuilder = new Builder\JoinColumnMetadataBuilder($metadataBuildingContext); |
|||||
751 | |||||||
752 | $joinColumnBuilder |
||||||
753 | 3 | ->withComponentMetadata($metadata) |
|||||
754 | 3 | ->withFieldName($fieldName); |
|||||
755 | |||||||
756 | 3 | $joinColumns = []; |
|||||
757 | |||||||
758 | 3 | foreach ($associationOverrideAnnotation->joinColumns as $joinColumnAnnotation) { |
|||||
759 | 3 | $joinColumnBuilder->withJoinColumnAnnotation($joinColumnAnnotation); |
|||||
760 | |||||||
761 | 3 | $joinColumnMetadata = $joinColumnBuilder->build(); |
|||||
762 | 3 | $columnName = $joinColumnMetadata->getColumnName(); |
|||||
763 | |||||||
764 | // @todo guilhermeblanco Open an issue to discuss making this scenario impossible. |
||||||
765 | //if ($metadata->checkPropertyDuplication($columnName)) { |
||||||
766 | // throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName); |
||||||
767 | //} |
||||||
768 | |||||||
769 | 3 | if ($override->isOwningSide()) { |
|||||
0 ignored issues
–
show
The method
isOwningSide() does not exist on Doctrine\ORM\Mapping\Property . It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
770 | 3 | $metadata->fieldNames[$columnName] = $fieldName; |
|||||
771 | } |
||||||
772 | |||||||
773 | 3 | $joinColumns[] = $joinColumnMetadata; |
|||||
774 | } |
||||||
775 | |||||||
776 | 3 | $override->setJoinColumns($joinColumns); |
|||||
0 ignored issues
–
show
The method
setJoinColumns() does not exist on Doctrine\ORM\Mapping\Property . It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\ToOneAssociationMetadata .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
777 | } |
||||||
778 | |||||||
779 | // Check for JoinTable annotations |
||||||
780 | 5 | if ($associationOverrideAnnotation->joinTable) { |
|||||
781 | 2 | $joinTableBuilder = new Builder\JoinTableMetadataBuilder($metadataBuildingContext); |
|||||
782 | |||||||
783 | $joinTableBuilder |
||||||
784 | 2 | ->withComponentMetadata($metadata) |
|||||
785 | 2 | ->withFieldName($fieldName) |
|||||
786 | 2 | ->withTargetEntity($property->getTargetEntity()) |
|||||
0 ignored issues
–
show
The method
getTargetEntity() does not exist on Doctrine\ORM\Mapping\Property . It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
787 | 2 | ->withJoinTableAnnotation($associationOverrideAnnotation->joinTable); |
|||||
788 | |||||||
789 | 2 | $override->setJoinTable($joinTableBuilder->build()); |
|||||
0 ignored issues
–
show
The method
setJoinTable() does not exist on Doctrine\ORM\Mapping\Property . It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\ManyToManyAssociationMetadata .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
790 | } |
||||||
791 | |||||||
792 | // Check for inversedBy |
||||||
793 | 5 | if ($associationOverrideAnnotation->inversedBy) { |
|||||
794 | 1 | $override->setInversedBy($associationOverrideAnnotation->inversedBy); |
|||||
0 ignored issues
–
show
The method
setInversedBy() does not exist on Doctrine\ORM\Mapping\Property . It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
795 | } |
||||||
796 | |||||||
797 | // Check for fetch |
||||||
798 | 5 | if ($associationOverrideAnnotation->fetch) { |
|||||
799 | 1 | $override->setFetchMode(constant(Mapping\FetchMode::class . '::' . $associationOverrideAnnotation->fetch)); |
|||||
0 ignored issues
–
show
The method
setFetchMode() does not exist on Doctrine\ORM\Mapping\Property . It seems like you code against a sub-type of Doctrine\ORM\Mapping\Property such as Doctrine\ORM\Mapping\AssociationMetadata .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
800 | } |
||||||
801 | |||||||
802 | 5 | $metadata->setPropertyOverride($override); |
|||||
803 | } |
||||||
804 | } |
||||||
805 | |||||||
806 | // Evaluate AttributeOverrides annotation |
||||||
807 | 370 | if (isset($classAnnotations[Annotation\AttributeOverrides::class])) { |
|||||
808 | 3 | $attributeOverridesAnnot = $classAnnotations[Annotation\AttributeOverrides::class]; |
|||||
809 | 3 | $fieldBuilder = new Builder\FieldMetadataBuilder($metadataBuildingContext); |
|||||
810 | |||||||
811 | $fieldBuilder |
||||||
812 | 3 | ->withComponentMetadata($metadata) |
|||||
813 | 3 | ->withIdAnnotation(null) |
|||||
814 | 3 | ->withVersionAnnotation(null); |
|||||
815 | |||||||
816 | 3 | foreach ($attributeOverridesAnnot->value as $attributeOverrideAnnotation) { |
|||||
817 | 3 | $fieldName = $attributeOverrideAnnotation->name; |
|||||
818 | 3 | $property = $metadata->getProperty($fieldName); |
|||||
819 | |||||||
820 | 3 | if (! $property) { |
|||||
821 | throw Mapping\MappingException::invalidOverrideFieldName($metadata->getClassName(), $fieldName); |
||||||
822 | } |
||||||
823 | |||||||
824 | $fieldBuilder |
||||||
825 | 3 | ->withFieldName($fieldName) |
|||||
826 | 3 | ->withColumnAnnotation($attributeOverrideAnnotation->column); |
|||||
827 | |||||||
828 | 3 | $fieldMetadata = $fieldBuilder->build(); |
|||||
829 | 3 | $columnName = $fieldMetadata->getColumnName(); |
|||||
830 | |||||||
831 | // Prevent column duplication |
||||||
832 | 3 | if ($metadata->checkPropertyDuplication($columnName)) { |
|||||
0 ignored issues
–
show
It seems like
$columnName can also be of type null ; however, parameter $columnName of Doctrine\ORM\Mapping\Cla...ckPropertyDuplication() does only seem to accept string , 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...
|
|||||||
833 | throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName); |
||||||
834 | } |
||||||
835 | |||||||
836 | 3 | $metadata->fieldNames[$fieldMetadata->getColumnName()] = $fieldName; |
|||||
837 | |||||||
838 | 3 | $metadata->setPropertyOverride($fieldMetadata); |
|||||
839 | } |
||||||
840 | } |
||||||
841 | 370 | } |
|||||
842 | |||||||
843 | /** |
||||||
844 | * Attempts to resolve the cascade modes. |
||||||
845 | * |
||||||
846 | * @param string $className The class name. |
||||||
847 | * @param string $fieldName The field name. |
||||||
848 | * @param string[] $originalCascades The original unprocessed field cascades. |
||||||
849 | * |
||||||
850 | * @return string[] The processed field cascades. |
||||||
851 | * |
||||||
852 | * @throws Mapping\MappingException If a cascade option is not valid. |
||||||
853 | */ |
||||||
854 | private function getCascade(string $className, string $fieldName, array $originalCascades) : array |
||||||
0 ignored issues
–
show
|
|||||||
855 | { |
||||||
856 | $cascadeTypes = ['remove', 'persist', 'refresh']; |
||||||
857 | $cascades = array_map('strtolower', $originalCascades); |
||||||
858 | |||||||
859 | if (in_array('all', $cascades, true)) { |
||||||
860 | $cascades = $cascadeTypes; |
||||||
861 | } |
||||||
862 | |||||||
863 | if (count($cascades) !== count(array_intersect($cascades, $cascadeTypes))) { |
||||||
864 | $diffCascades = array_diff($cascades, array_intersect($cascades, $cascadeTypes)); |
||||||
865 | |||||||
866 | throw Mapping\MappingException::invalidCascadeOption($diffCascades, $className, $fieldName); |
||||||
867 | } |
||||||
868 | |||||||
869 | return $cascades; |
||||||
870 | } |
||||||
871 | |||||||
872 | /** |
||||||
873 | * Attempts to resolve the fetch mode. |
||||||
874 | * |
||||||
875 | * @param string $className The class name. |
||||||
876 | * @param string $fetchMode The fetch mode. |
||||||
877 | * |
||||||
878 | * @return string The fetch mode as defined in ClassMetadata. |
||||||
879 | * |
||||||
880 | * @throws Mapping\MappingException If the fetch mode is not valid. |
||||||
881 | */ |
||||||
882 | private function getFetchMode($className, $fetchMode) : string |
||||||
0 ignored issues
–
show
|
|||||||
883 | { |
||||||
884 | $fetchModeConstant = sprintf('%s::%s', Mapping\FetchMode::class, $fetchMode); |
||||||
885 | |||||||
886 | if (! defined($fetchModeConstant)) { |
||||||
887 | throw Mapping\MappingException::invalidFetchMode($className, $fetchMode); |
||||||
888 | } |
||||||
889 | |||||||
890 | return constant($fetchModeConstant); |
||||||
891 | } |
||||||
892 | |||||||
893 | /** |
||||||
894 | * @return Annotation\Annotation[] |
||||||
895 | */ |
||||||
896 | 379 | private function getClassAnnotations(ReflectionClass $reflectionClass) : array |
|||||
897 | { |
||||||
898 | 379 | $classAnnotations = $this->reader->getClassAnnotations($reflectionClass); |
|||||
899 | |||||||
900 | 379 | foreach ($classAnnotations as $key => $annot) { |
|||||
901 | 373 | if (! is_numeric($key)) { |
|||||
902 | continue; |
||||||
903 | } |
||||||
904 | |||||||
905 | 373 | $classAnnotations[get_class($annot)] = $annot; |
|||||
906 | } |
||||||
907 | |||||||
908 | 379 | return $classAnnotations; |
|||||
909 | } |
||||||
910 | |||||||
911 | /** |
||||||
912 | * @return Annotation\Annotation[] |
||||||
913 | */ |
||||||
914 | 373 | private function getPropertyAnnotations(ReflectionProperty $reflectionProperty) : array |
|||||
915 | { |
||||||
916 | 373 | $propertyAnnotations = $this->reader->getPropertyAnnotations($reflectionProperty); |
|||||
917 | |||||||
918 | 372 | foreach ($propertyAnnotations as $key => $annot) { |
|||||
919 | 372 | if (! is_numeric($key)) { |
|||||
920 | continue; |
||||||
921 | } |
||||||
922 | |||||||
923 | 372 | $propertyAnnotations[get_class($annot)] = $annot; |
|||||
924 | } |
||||||
925 | |||||||
926 | 372 | return $propertyAnnotations; |
|||||
927 | } |
||||||
928 | |||||||
929 | /** |
||||||
930 | * @return Annotation\Annotation[] |
||||||
931 | */ |
||||||
932 | 21 | private function getMethodAnnotations(ReflectionMethod $reflectionMethod) : array |
|||||
933 | { |
||||||
934 | 21 | $methodAnnotations = $this->reader->getMethodAnnotations($reflectionMethod); |
|||||
935 | |||||||
936 | 21 | foreach ($methodAnnotations as $key => $annot) { |
|||||
937 | 18 | if (! is_numeric($key)) { |
|||||
938 | continue; |
||||||
939 | } |
||||||
940 | |||||||
941 | 18 | $methodAnnotations[get_class($annot)] = $annot; |
|||||
942 | } |
||||||
943 | |||||||
944 | 21 | return $methodAnnotations; |
|||||
945 | } |
||||||
946 | } |
||||||
947 |