Failed Conditions
Pull Request — master (#7799)
by Guilherme
10:54
created

convertOneToOneElementToOneToOneAnnotation()   A

Complexity

Conditions 6
Paths 32

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 6.0131

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 32
nop 1
dl 0
loc 28
ccs 13
cts 14
cp 0.9286
crap 6.0131
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ORM\Mapping\Driver;
6
7
use Doctrine\Common\Collections\Criteria;
8
use Doctrine\DBAL\DBALException;
9
use Doctrine\ORM\Annotation;
10
use Doctrine\ORM\Events;
11
use Doctrine\ORM\Mapping;
12
use Doctrine\ORM\Mapping\Builder;
13
use InvalidArgumentException;
14
use SimpleXMLElement;
15
use function class_exists;
16
use function constant;
17
use function explode;
18
use function file_get_contents;
19
use function get_class;
20
use function in_array;
21
use function simplexml_load_string;
22
use function sprintf;
23
use function str_replace;
24
use function strtoupper;
25
26
/**
27
 * XmlDriver is a metadata driver that enables mapping through XML files.
28
 */
29
class XmlDriver extends FileDriver
30
{
31
    public const DEFAULT_FILE_EXTENSION = '.dcm.xml';
32
33
    /**
34
     * {@inheritDoc}
35
     */
36 41
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
37
    {
38 41
        parent::__construct($locator, $fileExtension);
39 41
    }
40
41
    /**
42
     * {@inheritDoc}
43
     *
44
     * @throws DBALException
45
     */
46 36
    public function loadMetadataForClass(
47
        string $className,
48
        ?Mapping\ComponentMetadata $parent,
49
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
50
    ) : Mapping\ComponentMetadata {
51 36
        $metadata = new Mapping\ClassMetadata($className, $parent, $metadataBuildingContext);
52
53
        /** @var SimpleXMLElement $xmlRoot */
54 36
        $xmlRoot = $this->getElement($className);
55
56 34
        if ($xmlRoot->getName() === 'entity') {
57 34
            if (isset($xmlRoot['repository-class'])) {
58
                $metadata->setCustomRepositoryClassName((string) $xmlRoot['repository-class']);
59
            }
60
61 34
            if (isset($xmlRoot['read-only']) && $this->evaluateBoolean($xmlRoot['read-only'])) {
62 34
                $metadata->asReadOnly();
63
            }
64 5
        } elseif ($xmlRoot->getName() === 'mapped-superclass') {
65 5
            if (isset($xmlRoot['repository-class'])) {
66 1
                $metadata->setCustomRepositoryClassName((string) $xmlRoot['repository-class']);
67
            }
68
69 5
            $metadata->isMappedSuperclass = true;
70
        } elseif ($xmlRoot->getName() === 'embeddable') {
71
            $metadata->isEmbeddedClass = true;
72
        } else {
73
            throw Mapping\MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
74
        }
75
76
        // Process table information
77 34
        $parent = $metadata->getParent();
78
79 34
        if ($parent && $parent->inheritanceType === Mapping\InheritanceType::SINGLE_TABLE) {
80
            // Handle the case where a middle mapped super class inherits from a single table inheritance tree.
81
            do {
82 2
                if (! $parent->isMappedSuperclass) {
83 2
                    $metadata->setTable($parent->table);
84
85 2
                    break;
86
                }
87
88
                $parent = $parent->getParent();
89 2
            } while ($parent !== null);
90
        } else {
91 34
            $tableAnnotation = new Annotation\Table();
92
93
            // Evaluate <entity...> attributes
94 34
            if (isset($xmlRoot['table'])) {
95 12
                $tableAnnotation->name = (string) $xmlRoot['table'];
96
            }
97
98 34
            if (isset($xmlRoot['schema'])) {
99 2
                $tableAnnotation->schema = (string) $xmlRoot['schema'];
100
            }
101
102
            // Evaluate <indexes...>
103 34
            if (isset($xmlRoot->indexes)) {
104 4
                $tableAnnotation->indexes = $this->parseIndexes($xmlRoot->indexes->children());
105
            }
106
107
            // Evaluate <unique-constraints..>
108 34
            if (isset($xmlRoot->{'unique-constraints'})) {
109 3
                $tableAnnotation->uniqueConstraints = $this->parseUniqueConstraints($xmlRoot->{'unique-constraints'}->children());
110
            }
111
112 34
            if (isset($xmlRoot->options)) {
113 3
                $tableAnnotation->options = $this->parseOptions($xmlRoot->options->children());
114
            }
115
116 34
            $tableBuilder = new Builder\TableMetadataBuilder($metadataBuildingContext);
117
118
            $tableBuilder
119 34
                ->withEntityClassMetadata($metadata)
120 34
                ->withTableAnnotation($tableAnnotation);
121
122 34
            $metadata->setTable($tableBuilder->build());
123
        }
124
125
        // Evaluate second level cache
126 34
        if (isset($xmlRoot->cache)) {
127 2
            $cacheBuilder = new Builder\CacheMetadataBuilder($metadataBuildingContext);
128
129
            $cacheBuilder
130 2
                ->withComponentMetadata($metadata)
131 2
                ->withCacheAnnotation($this->convertCacheElementToCacheAnnotation($xmlRoot->cache));
132
133 2
            $metadata->setCache($cacheBuilder->build());
134
        }
135
136 34
        if (isset($xmlRoot['inheritance-type'])) {
137 10
            $inheritanceType = strtoupper((string) $xmlRoot['inheritance-type']);
138
139 10
            $metadata->setInheritanceType(
140 10
                constant(sprintf('%s::%s', Mapping\InheritanceType::class, $inheritanceType))
141
            );
142
143 10
            if ($metadata->inheritanceType !== Mapping\InheritanceType::NONE) {
144 10
                $discriminatorColumnBuilder = new Builder\DiscriminatorColumnMetadataBuilder($metadataBuildingContext);
145
146
                $discriminatorColumnBuilder
147 10
                    ->withComponentMetadata($metadata)
148 10
                    ->withDiscriminatorColumnAnnotation(
149 10
                        isset($xmlRoot->{'discriminator-column'})
150 8
                            ? $this->convertDiscrimininatorColumnElementToDiscriminatorColumnAnnotation($xmlRoot->{'discriminator-column'})
151 10
                            : null
152
                    );
153
154 10
                $metadata->setDiscriminatorColumn($discriminatorColumnBuilder->build());
155
156
                // Evaluate <discriminator-map...>
157 10
                if (isset($xmlRoot->{'discriminator-map'})) {
158 10
                    $map = [];
159
160 10
                    foreach ($xmlRoot->{'discriminator-map'}->{'discriminator-mapping'} as $discrMapElement) {
161 10
                        $map[(string) $discrMapElement['value']] = (string) $discrMapElement['class'];
162
                    }
163
164 10
                    $metadata->setDiscriminatorMap($map);
165
                }
166
            }
167
        }
168
169
        // Evaluate <change-tracking-policy...>
170 34
        if (isset($xmlRoot['change-tracking-policy'])) {
171
            $changeTrackingPolicy = strtoupper((string) $xmlRoot['change-tracking-policy']);
172
173
            $metadata->setChangeTrackingPolicy(
174
                constant(sprintf('%s::%s', Mapping\ChangeTrackingPolicy::class, $changeTrackingPolicy))
175
            );
176
        }
177
178
        // Evaluate <field ...> mappings
179 34
        if (isset($xmlRoot->field)) {
180 20
            $fieldBuilder = new Builder\FieldMetadataBuilder($metadataBuildingContext);
181
182
            $fieldBuilder
183 20
                ->withComponentMetadata($metadata);
184
185 20
            foreach ($xmlRoot->field as $fieldElement) {
186 20
                $versionAnnotation = isset($fieldElement['version']) && $this->evaluateBoolean($fieldElement['version'])
187 3
                    ? new Annotation\Version()
188 20
                    : null;
189
190
                $fieldBuilder
191 20
                    ->withFieldName((string) $fieldElement['name'])
192 20
                    ->withColumnAnnotation($this->convertFieldElementToColumnAnnotation($fieldElement))
193 20
                    ->withIdAnnotation(null)
194 20
                    ->withVersionAnnotation($versionAnnotation);
195
196 20
                $fieldMetadata = $fieldBuilder->build();
197
198
                // Prevent column duplication
199 20
                if ($metadata->checkPropertyDuplication($fieldMetadata->getColumnName())) {
0 ignored issues
show
Bug introduced by
It seems like $fieldMetadata->getColumnName() 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 ignore-type  annotation

199
                if ($metadata->checkPropertyDuplication(/** @scrutinizer ignore-type */ $fieldMetadata->getColumnName())) {
Loading history...
200
                    throw Mapping\MappingException::duplicateColumnName(
201
                        $metadata->getClassName(),
202
                        $fieldMetadata->getColumnName()
203
                    );
204
                }
205
206 20
                $metadata->addProperty($fieldMetadata);
207
            }
208
        }
209
210 34
        if (isset($xmlRoot->embedded)) {
211
            foreach ($xmlRoot->embedded as $embeddedMapping) {
212
                $columnPrefix = isset($embeddedMapping['column-prefix'])
213
                    ? (string) $embeddedMapping['column-prefix']
214
                    : null;
215
216
                $useColumnPrefix = isset($embeddedMapping['use-column-prefix'])
217
                    ? $this->evaluateBoolean($embeddedMapping['use-column-prefix'])
218
                    : true;
219
220
                $mapping = [
221
                    'fieldName'    => (string) $embeddedMapping['name'],
222
                    'class'        => (string) $embeddedMapping['class'],
223
                    'columnPrefix' => $useColumnPrefix ? $columnPrefix : false,
224
                ];
225
226
                $metadata->mapEmbedded($mapping);
227
            }
228
        }
229
230
        // Evaluate <id ...> mappings
231 34
        $associationIds = [];
232
233 34
        $fieldBuilder = new Builder\FieldMetadataBuilder($metadataBuildingContext);
234
235
        $fieldBuilder
236 34
            ->withComponentMetadata($metadata);
237
238 34
        foreach ($xmlRoot->id as $idElement) {
239 29
            $fieldName = (string) $idElement['name'];
240
241 29
            if (isset($idElement['association-key']) && $this->evaluateBoolean($idElement['association-key'])) {
242 2
                $associationIds[$fieldName] = true;
243
244 2
                continue;
245
            }
246
247 28
            $versionAnnotation = isset($idElement['version']) && $this->evaluateBoolean($idElement['version'])
248
                ? new Annotation\Version()
249 28
                : null;
250
251
            $fieldMetadata = $fieldBuilder
252 28
                ->withFieldName($fieldName)
253 28
                ->withColumnAnnotation($this->convertFieldElementToColumnAnnotation($idElement))
254 28
                ->withIdAnnotation(new Annotation\Id())
255 28
                ->withVersionAnnotation($versionAnnotation)
256 28
                ->withGeneratedValueAnnotation(
257 28
                    isset($idElement->generator)
258 27
                        ? $this->convertGeneratorElementToGeneratedValueAnnotation($idElement->generator)
259 28
                        : null
260
                )
261 28
                ->withSequenceGeneratorAnnotation(
262 28
                    isset($idElement->{'sequence-generator'})
263 3
                        ? $this->convertSequenceGeneratorElementToSequenceGeneratorAnnotation($idElement->{'sequence-generator'})
264 28
                        : null
265
                )
266 28
                ->withCustomIdGeneratorAnnotation(
267 28
                    isset($idElement->{'custom-id-generator'})
268 2
                        ? $this->convertCustomIdGeneratorElementToCustomIdGeneratorAnnotation($idElement->{'custom-id-generator'})
269 28
                        : null
270
                )
271 28
                ->build();
272
273
            // Prevent column duplication
274 28
            if ($metadata->checkPropertyDuplication($fieldMetadata->getColumnName())) {
275
                throw Mapping\MappingException::duplicateColumnName(
276
                    $metadata->getClassName(),
277
                    $fieldMetadata->getColumnName()
278
                );
279
            }
280
281 28
            $metadata->fieldNames[$fieldMetadata->getColumnName()] = $fieldMetadata->getName();
282
283 28
            $metadata->addProperty($fieldMetadata);
284
        }
285
286
        // Evaluate <one-to-one ...> mappings
287 34
        if (isset($xmlRoot->{'one-to-one'})) {
288 7
            $oneToOneAssociationBuilder = new Builder\OneToOneAssociationMetadataBuilder($metadataBuildingContext);
289
290
            $oneToOneAssociationBuilder
291 7
                ->withComponentMetadata($metadata);
292
293 7
            foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) {
294 7
                $fieldName           = (string) $oneToOneElement['field'];
295
                $associationMetadata = $oneToOneAssociationBuilder
296 7
                    ->withFieldName($fieldName)
297 7
                    ->withCacheAnnotation($this->convertCacheElementToCacheAnnotation($oneToOneElement->cache))
298 7
                    ->withOneToOneAnnotation($this->convertOneToOneElementToOneToOneAnnotation($oneToOneElement))
299 7
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
300 7
                    ->withJoinColumnAnnotation(
301 7
                        isset($oneToOneElement->{'join-column'})
302 5
                            ? $this->convertJoinColumnElementToJoinColumnAnnotation($oneToOneElement->{'join-column'})
303 7
                            : null
304
                    )
305 7
                    ->withJoinColumnsAnnotation(
306 7
                        isset($oneToOneElement->{'join-columns'})
307
                            ? $this->convertJoinColumnsElementToJoinColumnsAnnotation($oneToOneElement->{'join-columns'})
308 7
                            : null
309
                    )
310 7
                    ->build();
311
312
                // Prevent column duplication
313 7
                foreach ($associationMetadata->getJoinColumns() as $joinColumnMetadata) {
314 5
                    $columnName = $joinColumnMetadata->getColumnName();
315
316 5
                    if ($metadata->checkPropertyDuplication($columnName)) {
317
                        throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName);
318
                    }
319
320 5
                    if ($associationMetadata->isOwningSide()) {
321 5
                        $metadata->fieldNames[$columnName] = $associationMetadata->getName();
322
                    }
323
                }
324
325 7
                $metadata->addProperty($associationMetadata);
326
            }
327
        }
328
329
        // Evaluate <many-to-one ...> mappings
330 34
        if (isset($xmlRoot->{'many-to-one'})) {
331 8
            $manyToOneAssociationBuilder = new Builder\ManyToOneAssociationMetadataBuilder($metadataBuildingContext);
332
333
            $manyToOneAssociationBuilder
334 8
                ->withComponentMetadata($metadata);
335
336 8
            foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) {
337 8
                $fieldName           = (string) $manyToOneElement['field'];
338
                $associationMetadata = $manyToOneAssociationBuilder
339 8
                    ->withFieldName($fieldName)
340 8
                    ->withCacheAnnotation($this->convertCacheElementToCacheAnnotation($manyToOneElement->cache))
341 8
                    ->withManyToOneAnnotation($this->convertManyToOneElementToManyToOneAnnotation($manyToOneElement))
342 8
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
343 8
                    ->withJoinColumnAnnotation(
344 8
                        isset($manyToOneElement->{'join-column'})
345 7
                            ? $this->convertJoinColumnElementToJoinColumnAnnotation($manyToOneElement->{'join-column'})
346 8
                            : null
347
                    )
348 8
                    ->withJoinColumnsAnnotation(
349 8
                        isset($manyToOneElement->{'join-columns'})
350 1
                            ? $this->convertJoinColumnsElementToJoinColumnsAnnotation($manyToOneElement->{'join-columns'})
351 8
                            : null
352
                    )
353 8
                    ->build();
354
355
                // Prevent column duplication
356 8
                foreach ($associationMetadata->getJoinColumns() as $joinColumnMetadata) {
357 8
                    $columnName = $joinColumnMetadata->getColumnName();
358
359 8
                    if ($metadata->checkPropertyDuplication($columnName)) {
360
                        throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName);
361
                    }
362
363 8
                    if ($associationMetadata->isOwningSide()) {
364 8
                        $metadata->fieldNames[$columnName] = $associationMetadata->getName();
365
                    }
366
                }
367
368 8
                $metadata->addProperty($associationMetadata);
369
            }
370
        }
371
372
        // Evaluate <one-to-many ...> mappings
373 34
        if (isset($xmlRoot->{'one-to-many'})) {
374 9
            $oneToManyAssociationBuilder = new Builder\OneToManyAssociationMetadataBuilder($metadataBuildingContext);
375
376
            $oneToManyAssociationBuilder
377 9
                ->withComponentMetadata($metadata);
378
379 9
            foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) {
380 9
                $fieldName           = (string) $oneToManyElement['field'];
381
                $associationMetadata = $oneToManyAssociationBuilder
382 9
                    ->withFieldName($fieldName)
383 9
                    ->withCacheAnnotation($this->convertCacheElementToCacheAnnotation($oneToManyElement->cache))
384 9
                    ->withOneToManyAnnotation($this->convertOneToManyElementToOneToManyAnnotation($oneToManyElement))
385 9
                    ->withOrderByAnnotation(
386 9
                        isset($oneToManyElement->{'order-by'})
387 5
                            ? $this->convertOrderByElementToOrderByAnnotation($oneToManyElement->{'order-by'})
388 9
                            : null
389
                    )
390 9
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
391 9
                    ->build();
392
393 9
                $metadata->addProperty($associationMetadata);
394
            }
395
        }
396
397
        // Evaluate <many-to-many ...> mappings
398 34
        if (isset($xmlRoot->{'many-to-many'})) {
399 14
            foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) {
400 14
                $association  = new Mapping\ManyToManyAssociationMetadata((string) $manyToManyElement['field']);
401 14
                $targetEntity = (string) $manyToManyElement['target-entity'];
402
403 14
                $association->setTargetEntity($targetEntity);
404
405 14
                if (isset($associationIds[$association->getName()])) {
406
                    throw Mapping\MappingException::illegalToManyIdentifierAssociation($className, $association->getName());
407
                }
408
409 14
                if (isset($manyToManyElement['fetch'])) {
410 4
                    $association->setFetchMode(
411 4
                        constant(sprintf('%s::%s', Mapping\FetchMode::class, (string) $manyToManyElement['fetch']))
412
                    );
413
                }
414
415 14
                if (isset($manyToManyElement->cascade)) {
416 8
                    $association->setCascade($this->getCascadeMappings($manyToManyElement->cascade));
417
                }
418
419 14
                if (isset($manyToManyElement['orphan-removal'])) {
420
                    $association->setOrphanRemoval($this->evaluateBoolean($manyToManyElement['orphan-removal']));
421
                }
422
423 14
                if (isset($manyToManyElement['mapped-by'])) {
424 5
                    $association->setMappedBy((string) $manyToManyElement['mapped-by']);
425 5
                    $association->setOwningSide(false);
426
                }
427
428 14
                if (isset($manyToManyElement['inversed-by'])) {
429 6
                    $association->setInversedBy((string) $manyToManyElement['inversed-by']);
430
                }
431
432 14
                if (isset($manyToManyElement['index-by'])) {
433
                    $association->setIndexedBy((string) $manyToManyElement['index-by']);
434 14
                } elseif (isset($manyToManyElement->{'index-by'})) {
435
                    throw new InvalidArgumentException('<index-by /> is not a valid tag');
436
                }
437
438 14
                if (isset($manyToManyElement->{'order-by'})) {
439 1
                    $orderBy = [];
440
441 1
                    foreach ($manyToManyElement->{'order-by'}->{'order-by-field'} as $orderByField) {
442 1
                        $orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
443
                            ? (string) $orderByField['direction']
444 1
                            : Criteria::ASC;
445
                    }
446
447 1
                    $association->setOrderBy($orderBy);
448
                }
449
450
                // Check for cache
451 14
                if (isset($manyToManyElement->cache)) {
452
                    $cacheBuilder = new Builder\CacheMetadataBuilder($metadataBuildingContext);
453
454
                    $cacheBuilder
455
                        ->withComponentMetadata($metadata)
456
                        ->withFieldName($association->getName())
457
                        ->withCacheAnnotation($this->convertCacheElementToCacheAnnotation($manyToManyElement->cache));
458
459
                    $association->setCache($cacheBuilder->build());
460
                }
461
462
                // Check for owning side to consider join column
463 14
                if (! $association->isOwningSide()) {
464 5
                    $metadata->addProperty($association);
465
466 5
                    continue;
467
                }
468
469 10
                $joinTableBuilder = new Builder\JoinTableMetadataBuilder($metadataBuildingContext);
470
471
                $joinTableBuilder
472 10
                    ->withComponentMetadata($metadata)
473 10
                    ->withFieldName($association->getName())
474 10
                    ->withTargetEntity($targetEntity);
475
476 10
                if (isset($manyToManyElement->{'join-table'})) {
477 8
                    $joinTableElement    = $manyToManyElement->{'join-table'};
478 8
                    $joinTableAnnotation = $this->convertJoinTableElementToJoinTableAnnotation($joinTableElement);
479
480 8
                    $joinTableBuilder->withJoinTableAnnotation($joinTableAnnotation);
481
                }
482
483 10
                $association->setJoinTable($joinTableBuilder->build());
484
485 10
                $metadata->addProperty($association);
486
            }
487
        }
488
489
        // Evaluate association-overrides
490 34
        if (isset($xmlRoot->{'attribute-overrides'})) {
491 1
            $fieldBuilder = new Builder\FieldMetadataBuilder($metadataBuildingContext);
492
493
            $fieldBuilder
494 1
                ->withComponentMetadata($metadata);
495
496 1
            foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} as $overrideElement) {
497 1
                $fieldName = (string) $overrideElement['name'];
498
499 1
                foreach ($overrideElement->field as $fieldElement) {
500 1
                    $versionAnnotation = isset($fieldElement['version']) && $this->evaluateBoolean($fieldElement['version'])
501
                        ? new Annotation\Version()
502 1
                        : null;
503
504
                    $fieldBuilder
505 1
                        ->withFieldName($fieldName)
506 1
                        ->withColumnAnnotation($this->convertFieldElementToColumnAnnotation($fieldElement))
507 1
                        ->withIdAnnotation(null)
508 1
                        ->withVersionAnnotation($versionAnnotation);
509
510 1
                    $fieldMetadata = $fieldBuilder->build();
511
512
                    // Prevent column duplication
513 1
                    if ($metadata->checkPropertyDuplication($fieldMetadata->getColumnName())) {
514
                        throw Mapping\MappingException::duplicateColumnName(
515
                            $metadata->getClassName(),
516
                            $fieldMetadata->getColumnName()
517
                        );
518
                    }
519
520 1
                    $metadata->setPropertyOverride($fieldMetadata);
521
                }
522
            }
523
        }
524
525
        // Evaluate association-overrides
526 34
        if (isset($xmlRoot->{'association-overrides'})) {
527 4
            foreach ($xmlRoot->{'association-overrides'}->{'association-override'} as $overrideElement) {
528 4
                $fieldName = (string) $overrideElement['name'];
529 4
                $property  = $metadata->getProperty($fieldName);
530
531 4
                if (! $property) {
532
                    throw Mapping\MappingException::invalidOverrideFieldName($metadata->getClassName(), $fieldName);
533
                }
534
535 4
                $existingClass = get_class($property);
536 4
                $override      = new $existingClass($fieldName);
537
538 4
                $override->setTargetEntity($property->getTargetEntity());
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

538
                $override->setTargetEntity($property->/** @scrutinizer ignore-call */ getTargetEntity());
Loading history...
539
540
                // Check for join-columns
541 4
                if (isset($overrideElement->{'join-columns'})) {
542 2
                    $joinColumnBuilder = new Builder\JoinColumnMetadataBuilder($metadataBuildingContext);
543
544
                    $joinColumnBuilder
545 2
                        ->withComponentMetadata($metadata)
546 2
                        ->withFieldName($override->getName());
547
548 2
                    foreach ($overrideElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
549 2
                        $joinColumnAnnotation = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
550
551 2
                        $joinColumnBuilder->withJoinColumnAnnotation($joinColumnAnnotation);
552
553 2
                        $override->addJoinColumn($joinColumnBuilder->build());
554
                    }
555
                }
556
557
                // Check for join-table
558 4
                if ($overrideElement->{'join-table'}) {
559 2
                    $joinTableElement    = $overrideElement->{'join-table'};
560 2
                    $joinTableAnnotation = $this->convertJoinTableElementToJoinTableAnnotation($joinTableElement);
561 2
                    $joinTableBuilder    = new Builder\JoinTableMetadataBuilder($metadataBuildingContext);
562
563
                    $joinTableBuilder
564 2
                        ->withComponentMetadata($metadata)
565 2
                        ->withFieldName($property->getName())
566 2
                        ->withTargetEntity($property->getTargetEntity())
567 2
                        ->withJoinTableAnnotation($joinTableAnnotation);
568
569 2
                    $override->setJoinTable($joinTableBuilder->build());
570
                }
571
572
                // Check for inversed-by
573 4
                if (isset($overrideElement->{'inversed-by'})) {
574 1
                    $override->setInversedBy((string) $overrideElement->{'inversed-by'}['name']);
575
                }
576
577
                // Check for fetch
578 4
                if (isset($overrideElement['fetch'])) {
579 1
                    $override->setFetchMode(
580 1
                        constant('Doctrine\ORM\Mapping\FetchMode::' . (string) $overrideElement['fetch'])
581
                    );
582
                }
583
584 4
                $metadata->setPropertyOverride($override);
585
            }
586
        }
587
588
        // Evaluate <lifecycle-callbacks...>
589 34
        if (isset($xmlRoot->{'lifecycle-callbacks'})) {
590 3
            foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
591 3
                $eventName  = constant(Events::class . '::' . (string) $lifecycleCallback['type']);
592 3
                $methodName = (string) $lifecycleCallback['method'];
593
594 3
                $metadata->addLifecycleCallback($eventName, $methodName);
595
            }
596
        }
597
598
        // Evaluate entity listener
599 34
        if (isset($xmlRoot->{'entity-listeners'})) {
600 2
            foreach ($xmlRoot->{'entity-listeners'}->{'entity-listener'} as $listenerElement) {
601 2
                $listenerClassName = (string) $listenerElement['class'];
602
603 2
                if (! class_exists($listenerClassName)) {
604
                    throw Mapping\MappingException::entityListenerClassNotFound(
605
                        $listenerClassName,
606
                        $metadata->getClassName()
607
                    );
608
                }
609
610 2
                foreach ($listenerElement as $callbackElement) {
611 2
                    $eventName  = (string) $callbackElement['type'];
612 2
                    $methodName = (string) $callbackElement['method'];
613
614 2
                    $metadata->addEntityListener($eventName, $listenerClassName, $methodName);
615
                }
616
            }
617
        }
618
619 34
        return $metadata;
620
    }
621
622
    /**
623
     * Parses (nested) index elements.
624
     *
625
     * @param SimpleXMLElement $indexes The XML element.
626
     *
627
     * @return Annotation\Index[] The indexes array.
628
     */
629 4
    private function parseIndexes(SimpleXMLElement $indexes) : array
630
    {
631 4
        $array = [];
632
633
        /** @var SimpleXMLElement $index */
634 4
        foreach ($indexes as $index) {
635 4
            $indexAnnotation = new Annotation\Index();
636
637 4
            $indexAnnotation->columns = explode(',', (string) $index['columns']);
638 4
            $indexAnnotation->options = isset($index->options) ? $this->parseOptions($index->options->children()) : [];
639 4
            $indexAnnotation->flags   = isset($index['flags']) ? explode(',', (string) $index['flags']) : [];
640
641 4
            if (isset($index['name'])) {
642 3
                $indexAnnotation->name = (string) $index['name'];
643
            }
644
645 4
            if (isset($index['unique'])) {
646
                $indexAnnotation->unique = $this->evaluateBoolean($index['unique']);
647
            }
648
649 4
            $array[] = $indexAnnotation;
650
        }
651
652 4
        return $array;
653
    }
654
655
    /**
656
     * Parses (nested) unique constraint elements.
657
     *
658
     * @param SimpleXMLElement $uniqueConstraints The XML element.
659
     *
660
     * @return Annotation\UniqueConstraint[] The unique constraints array.
661
     */
662 3
    private function parseUniqueConstraints(SimpleXMLElement $uniqueConstraints) : array
663
    {
664 3
        $array = [];
665
666
        /** @var SimpleXMLElement $uniqueConstraint */
667 3
        foreach ($uniqueConstraints as $uniqueConstraint) {
668 3
            $uniqueConstraintAnnotation = new Annotation\UniqueConstraint();
669
670 3
            $uniqueConstraintAnnotation->columns = explode(',', (string) $uniqueConstraint['columns']);
671 3
            $uniqueConstraintAnnotation->options = isset($uniqueConstraint->options) ? $this->parseOptions($uniqueConstraint->options->children()) : [];
672 3
            $uniqueConstraintAnnotation->flags   = isset($uniqueConstraint['flags']) ? explode(',', (string) $uniqueConstraint['flags']) : [];
673
674 3
            if (isset($uniqueConstraint['name'])) {
675 3
                $uniqueConstraintAnnotation->name = (string) $uniqueConstraint['name'];
676
            }
677
678 3
            $array[] = $uniqueConstraintAnnotation;
679
        }
680
681 3
        return $array;
682
    }
683
684
    /**
685
     * Parses (nested) option elements.
686
     *
687
     * @param SimpleXMLElement $options The XML element.
688
     *
689
     * @return mixed[] The options array.
690
     */
691 4
    private function parseOptions(SimpleXMLElement $options) : array
692
    {
693 4
        $array = [];
694
695
        /** @var SimpleXMLElement $option */
696 4
        foreach ($options as $option) {
697 4
            if ($option->count()) {
698 3
                $value = $this->parseOptions($option->children());
699
            } else {
700 4
                $value = (string) $option;
701
            }
702
703 4
            $attributes = $option->attributes();
704
705 4
            if (isset($attributes->name)) {
706 4
                $nameAttribute = (string) $attributes->name;
707
708 4
                $array[$nameAttribute] = in_array($nameAttribute, ['unsigned', 'fixed'], true)
709 3
                    ? $this->evaluateBoolean($value)
710 4
                    : $value;
711
            } else {
712
                $array[] = $value;
713
            }
714
        }
715
716 4
        return $array;
717
    }
718
719 7
    private function convertOneToOneElementToOneToOneAnnotation(
720
        SimpleXMLElement $oneToOneElement
721
    ) : Annotation\OneToOne {
722 7
        $oneToOneAnnotation = new Annotation\OneToOne();
723
724 7
        $oneToOneAnnotation->targetEntity = (string) $oneToOneElement['target-entity'];
725
726 7
        if (isset($oneToOneElement['mapped-by'])) {
727 3
            $oneToOneAnnotation->mappedBy = (string) $oneToOneElement['mapped-by'];
728
        }
729
730 7
        if (isset($oneToOneElement['inversed-by'])) {
731 4
            $oneToOneAnnotation->inversedBy = (string) $oneToOneElement['inversed-by'];
732
        }
733
734 7
        if (isset($oneToOneElement['orphan-removal'])) {
735
            $oneToOneAnnotation->orphanRemoval = $this->evaluateBoolean($oneToOneElement['orphan-removal']);
736
        }
737
738 7
        if (isset($oneToOneElement['fetch'])) {
739 3
            $oneToOneAnnotation->fetch = (string) $oneToOneElement['fetch'];
740
        }
741
742 7
        if (isset($oneToOneElement->cascade)) {
743 7
            $oneToOneAnnotation->cascade = $this->getCascadeMappings($oneToOneElement->cascade);
744
        }
745
746 7
        return $oneToOneAnnotation;
747
    }
748
749 8
    private function convertManyToOneElementToManyToOneAnnotation(
750
        SimpleXMLElement $manyToOneElement
751
    ) : Annotation\ManyToOne {
752 8
        $manyToOneAnnotation = new Annotation\ManyToOne();
753
754 8
        $manyToOneAnnotation->targetEntity = (string) $manyToOneElement['target-entity'];
755
756 8
        if (isset($manyToOneElement['inversed-by'])) {
757 2
            $manyToOneAnnotation->inversedBy = (string) $manyToOneElement['inversed-by'];
758
        }
759
760 8
        if (isset($manyToOneElement['fetch'])) {
761
            $manyToOneAnnotation->fetch = (string) $manyToOneElement['fetch'];
762
        }
763
764 8
        if (isset($manyToOneElement->cascade)) {
765 4
            $manyToOneAnnotation->cascade = $this->getCascadeMappings($manyToOneElement->cascade);
766
        }
767
768 8
        return $manyToOneAnnotation;
769
    }
770
771 9
    private function convertOneToManyElementToOneToManyAnnotation(
772
        SimpleXMLElement $oneToManyElement
773
    ) : Annotation\OneToMany {
774 9
        $oneToManyAnnotation = new Annotation\OneToMany();
775
776 9
        $oneToManyAnnotation->targetEntity = (string) $oneToManyElement['target-entity'];
777
778 9
        if (isset($oneToManyElement['mapped-by'])) {
779 9
            $oneToManyAnnotation->mappedBy = (string) $oneToManyElement['mapped-by'];
780
        }
781
782 9
        if (isset($manyToOneElement['fetch'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $manyToOneElement seems to never exist and therefore isset should always be false.
Loading history...
783
            $oneToManyAnnotation->fetch = (string) $oneToManyElement['fetch'];
784
        }
785
786 9
        if (isset($oneToManyElement->cascade)) {
787 6
            $oneToManyAnnotation->cascade = $this->getCascadeMappings($oneToManyElement->cascade);
788
        }
789
790 9
        if (isset($oneToManyElement['orphan-removal'])) {
791 3
            $oneToManyAnnotation->orphanRemoval = $this->evaluateBoolean($oneToManyElement['orphan-removal']);
792
        }
793
794 9
        if (isset($oneToManyElement['index-by'])) {
795 3
            $oneToManyAnnotation->indexBy = (string) $oneToManyElement['index-by'];
796 6
        } elseif (isset($oneToManyElement->{'index-by'})) {
797
            throw new InvalidArgumentException('<index-by /> is not a valid tag');
798
        }
799
800 9
        return $oneToManyAnnotation;
801
    }
802
803 30
    private function convertFieldElementToColumnAnnotation(
804
        SimpleXMLElement $fieldElement
805
    ) : Annotation\Column {
806 30
        $columnAnnotation = new Annotation\Column();
807
808 30
        $columnAnnotation->type = isset($fieldElement['type']) ? (string) $fieldElement['type'] : 'string';
809
810 30
        if (isset($fieldElement['column'])) {
811 20
            $columnAnnotation->name = (string) $fieldElement['column'];
812
        }
813
814 30
        if (isset($fieldElement['length'])) {
815 6
            $columnAnnotation->length = (int) $fieldElement['length'];
816
        }
817
818 30
        if (isset($fieldElement['precision'])) {
819 1
            $columnAnnotation->precision = (int) $fieldElement['precision'];
820
        }
821
822 30
        if (isset($fieldElement['scale'])) {
823 1
            $columnAnnotation->scale = (int) $fieldElement['scale'];
824
        }
825
826 30
        if (isset($fieldElement['unique'])) {
827 7
            $columnAnnotation->unique = $this->evaluateBoolean($fieldElement['unique']);
828
        }
829
830 30
        if (isset($fieldElement['nullable'])) {
831 7
            $columnAnnotation->nullable = $this->evaluateBoolean($fieldElement['nullable']);
832
        }
833
834 30
        if (isset($fieldElement['column-definition'])) {
835 4
            $columnAnnotation->columnDefinition = (string) $fieldElement['column-definition'];
836
        }
837
838 30
        if (isset($fieldElement->options)) {
839 3
            $columnAnnotation->options = $this->parseOptions($fieldElement->options->children());
840
        }
841
842 30
        return $columnAnnotation;
843
    }
844
845 27
    private function convertGeneratorElementToGeneratedValueAnnotation(
846
        SimpleXMLElement $generatorElement
847
    ) : Annotation\GeneratedValue {
848 27
        $generatedValueAnnotation = new Annotation\GeneratedValue();
849
850 27
        $generatedValueAnnotation->strategy = (string) ($generatorElement['strategy'] ?? 'AUTO');
851
852 27
        return $generatedValueAnnotation;
853
    }
854
855 3
    private function convertSequenceGeneratorElementToSequenceGeneratorAnnotation(
856
        SimpleXMLElement $sequenceGeneratorElement
857
    ) : Annotation\SequenceGenerator {
858 3
        $sequenceGeneratorAnnotation = new Annotation\SequenceGenerator();
859
860 3
        $sequenceGeneratorAnnotation->sequenceName   = (string) ($sequenceGeneratorElement['sequence-name'] ?? null);
861 3
        $sequenceGeneratorAnnotation->allocationSize = (int) ($sequenceGeneratorElement['allocation-size'] ?? 1);
862
863 3
        return $sequenceGeneratorAnnotation;
864
    }
865
866 2
    private function convertCustomIdGeneratorElementToCustomIdGeneratorAnnotation(
867
        SimpleXMLElement $customIdGeneratorElement
868
    ) : Annotation\CustomIdGenerator {
869 2
        $customIdGeneratorAnnotation = new Annotation\CustomIdGenerator();
870
871 2
        $customIdGeneratorAnnotation->class     = (string) $customIdGeneratorElement['class'];
872 2
        $customIdGeneratorAnnotation->arguments = [];
873
874 2
        return $customIdGeneratorAnnotation;
875
    }
876
877
    /**
878
     * Constructs a JoinTable annotation based on the information
879
     * found in the given SimpleXMLElement.
880
     *
881
     * @param SimpleXMLElement $joinTableElement The XML element.
882
     */
883 8
    private function convertJoinTableElementToJoinTableAnnotation(
884
        SimpleXMLElement $joinTableElement
885
    ) : Annotation\JoinTable {
886 8
        $joinTableAnnotation = new Annotation\JoinTable();
887
888 8
        if (isset($joinTableElement['name'])) {
889 8
            $joinTableAnnotation->name = (string) $joinTableElement['name'];
890
        }
891
892 8
        if (isset($joinTableElement['schema'])) {
893
            $joinTableAnnotation->schema = (string) $joinTableElement['schema'];
894
        }
895
896 8
        if (isset($joinTableElement->{'join-columns'})) {
897 8
            $joinColumns = [];
898
899 8
            foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
900 8
                $joinColumns[] = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
901
            }
902
903 8
            $joinTableAnnotation->joinColumns = $joinColumns;
904
        }
905
906 8
        if (isset($joinTableElement->{'inverse-join-columns'})) {
907 8
            $joinColumns = [];
908
909 8
            foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
910 8
                $joinColumns[] = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
911
            }
912
913 8
            $joinTableAnnotation->inverseJoinColumns = $joinColumns;
914
        }
915
916 8
        return $joinTableAnnotation;
917
    }
918
919 1
    private function convertJoinColumnsElementToJoinColumnsAnnotation(
920
        SimpleXMLElement $joinColumnsElement
921
    ) : Annotation\JoinColumns {
922 1
        $joinColumnsAnnotation = new Annotation\JoinColumns();
923 1
        $joinColumns           = [];
924
925 1
        foreach ($joinColumnsElement->{'join-column'} as $joinColumnElement) {
926 1
            $joinColumns[] = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
927
        }
928
929 1
        $joinColumnsAnnotation->value = $joinColumns;
930
931 1
        return $joinColumnsAnnotation;
932
    }
933
934
    /**
935
     * Constructs a JoinColumn annotation based on the information
936
     * found in the given SimpleXMLElement.
937
     *
938
     * @param SimpleXMLElement $joinColumnElement The XML element.
939
     */
940 13
    private function convertJoinColumnElementToJoinColumnAnnotation(
941
        SimpleXMLElement $joinColumnElement
942
    ) : Annotation\JoinColumn {
943 13
        $joinColumnAnnotation = new Annotation\JoinColumn();
944
945 13
        $joinColumnAnnotation->name                 = (string) $joinColumnElement['name'];
946 13
        $joinColumnAnnotation->referencedColumnName = (string) $joinColumnElement['referenced-column-name'];
947
948 13
        if (isset($joinColumnElement['column-definition'])) {
949 3
            $joinColumnAnnotation->columnDefinition = (string) $joinColumnElement['column-definition'];
950
        }
951
952 13
        if (isset($joinColumnElement['field-name'])) {
953
            $joinColumnAnnotation->fieldName = (string) $joinColumnElement['field-name'];
954
        }
955
956 13
        if (isset($joinColumnElement['nullable'])) {
957 4
            $joinColumnAnnotation->nullable = $this->evaluateBoolean($joinColumnElement['nullable']);
958
        }
959
960 13
        if (isset($joinColumnElement['unique'])) {
961 3
            $joinColumnAnnotation->unique = $this->evaluateBoolean($joinColumnElement['unique']);
962
        }
963
964 13
        if (isset($joinColumnElement['on-delete'])) {
965 3
            $joinColumnAnnotation->onDelete = strtoupper((string) $joinColumnElement['on-delete']);
966
        }
967
968 13
        return $joinColumnAnnotation;
969
    }
970
971
    /**
972
     * Parse the given Cache as CacheMetadata
973
     */
974 14
    private function convertCacheElementToCacheAnnotation(SimpleXMLElement $cacheMapping) : Annotation\Cache
975
    {
976 14
        $cacheAnnotation = new Annotation\Cache();
977
978 14
        if (isset($cacheMapping['region'])) {
979
            $cacheAnnotation->region = (string) $cacheMapping['region'];
980
        }
981
982 14
        if (isset($cacheMapping['usage'])) {
983 2
            $cacheAnnotation->usage = strtoupper((string) $cacheMapping['usage']);
984
        }
985
986 14
        return $cacheAnnotation;
987
    }
988
989 8
    private function convertDiscrimininatorColumnElementToDiscriminatorColumnAnnotation(
990
        SimpleXMLElement $discriminatorColumnElement
991
    ) : Annotation\DiscriminatorColumn {
992 8
        $discriminatorColumnAnnotation = new Annotation\DiscriminatorColumn();
993
994 8
        $discriminatorColumnAnnotation->type = (string) ($discriminatorColumnElement['type'] ?? 'string');
995 8
        $discriminatorColumnAnnotation->name = (string) $discriminatorColumnElement['name'];
996
997 8
        if (isset($discriminatorColumnElement['column-definition'])) {
998 1
            $discriminatorColumnAnnotation->columnDefinition = (string) $discriminatorColumnElement['column-definition'];
999
        }
1000
1001 8
        if (isset($discriminatorColumnElement['length'])) {
1002 3
            $discriminatorColumnAnnotation->length = (int) $discriminatorColumnElement['length'];
1003
        }
1004
1005 8
        return $discriminatorColumnAnnotation;
1006
    }
1007
1008 5
    private function convertOrderByElementToOrderByAnnotation(
1009
        SimpleXMLElement $orderByElement
1010
    ) : Annotation\OrderBy {
1011 5
        $orderByAnnotation = new Annotation\OrderBy();
1012 5
        $orderBy           = [];
1013
1014 5
        foreach ($orderByElement->{'order-by-field'} as $orderByField) {
1015 5
            $orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
1016 4
                ? (string) $orderByField['direction']
1017 1
                : Criteria::ASC;
1018
        }
1019
1020 5
        $orderByAnnotation->value = $orderBy;
1021
1022 5
        return $orderByAnnotation;
1023
    }
1024
1025
    /**
1026
     * Gathers a list of cascade options found in the given cascade element.
1027
     *
1028
     * @param SimpleXMLElement $cascadeElement The cascade element.
1029
     *
1030
     * @return string[] The list of cascade options.
1031
     */
1032 10
    private function getCascadeMappings(SimpleXMLElement $cascadeElement) : array
1033
    {
1034 10
        $cascades = [];
1035
1036
        /** @var SimpleXMLElement $action */
1037 10
        foreach ($cascadeElement->children() as $action) {
1038
            // According to the JPA specifications, XML uses "cascade-persist"
1039
            // instead of "persist". Here, both variations are supported
1040
            // because Annotation use "persist" and we want to make sure that
1041
            // this driver doesn't need to know anything about the supported
1042
            // cascading actions
1043 10
            $cascades[] = str_replace('cascade-', '', $action->getName());
1044
        }
1045
1046 10
        return $cascades;
1047
    }
1048
1049
    /**
1050
     * {@inheritDoc}
1051
     */
1052 36
    protected function loadMappingFile($file)
1053
    {
1054 36
        $result = [];
1055
        // Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577
1056 36
        $xmlElement = simplexml_load_string(file_get_contents($file));
1057
1058 36
        if (isset($xmlElement->entity)) {
1059 35
            foreach ($xmlElement->entity as $entityElement) {
1060 35
                $entityName          = (string) $entityElement['name'];
1061 35
                $result[$entityName] = $entityElement;
1062
            }
1063 6
        } elseif (isset($xmlElement->{'mapped-superclass'})) {
1064 5
            foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) {
1065 5
                $className          = (string) $mappedSuperClass['name'];
1066 5
                $result[$className] = $mappedSuperClass;
1067
            }
1068 1
        } elseif (isset($xmlElement->embeddable)) {
1069
            foreach ($xmlElement->embeddable as $embeddableElement) {
1070
                $embeddableName          = (string) $embeddableElement['name'];
1071
                $result[$embeddableName] = $embeddableElement;
1072
            }
1073
        }
1074
1075 36
        return $result;
1076
    }
1077
1078
    /**
1079
     * @param mixed $element
1080
     *
1081
     * @return bool
1082
     */
1083 9
    protected function evaluateBoolean($element)
1084
    {
1085 9
        $flag = (string) $element;
1086
1087 9
        return $flag === 'true' || $flag === '1';
1088
    }
1089
}
1090