XmlDriver   F
last analyzed

Complexity

Total Complexity 177

Size/Duplication

Total Lines 1003
Duplicated Lines 0 %

Test Coverage

Coverage 90.3%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 490
dl 0
loc 1003
ccs 456
cts 505
cp 0.903
rs 2
c 4
b 0
f 0
wmc 177

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A evaluateBoolean() 0 5 2
A convertCacheElementToCacheAnnotation() 0 14 3
B convertTableElementToTableAnnotation() 0 42 8
A convertMappedSuperclassElementToMappedSuperclassAnnotation() 0 10 2
A convertEntityElementToEntityAnnotation() 0 14 3
A convertIndexElementToIndexAnnotation() 0 18 5
A convertSequenceGeneratorElementToSequenceGeneratorAnnotation() 0 9 1
F loadMetadataForClass() 0 394 70
A convertChangeTrackingPolicyElementToChangeTrackingPolicyAnnotation() 0 8 1
A convertCustomIdGeneratorElementToCustomIdGeneratorAnnotation() 0 9 1
B loadMappingFile() 0 24 7
A convertDiscrimininatorColumnElementToDiscriminatorColumnAnnotation() 0 17 3
B convertManyToManyElementToManyToManyAnnotation() 0 34 8
A parseOptions() 0 26 5
A getCascadeMappings() 0 15 2
B convertOneToManyElementToOneToManyAnnotation() 0 30 7
A convertDiscriminatorMapElementToDiscriminatorMapAnnotation() 0 13 2
A convertOrderByElementToOrderByAnnotation() 0 15 3
A convertUniqueConstraintElementToUniqueConstraintAnnotation() 0 14 4
B convertJoinTableElementToJoinTableAnnotation() 0 34 7
A convertOneToOneElementToOneToOneAnnotation() 0 28 6
A convertEmbeddedElementToEmbeddedAnnotation() 0 12 2
A convertInheritanceTypeElementToInheritanceTypeAnnotation() 0 8 1
A convertManyToOneElementToManyToOneAnnotation() 0 20 4
A convertJoinColumnElementToJoinColumnAnnotation() 0 29 6
D convertFieldElementToColumnAnnotation() 0 40 10
A convertGeneratorElementToGeneratedValueAnnotation() 0 8 1
A convertJoinColumnsElementToJoinColumnsAnnotation() 0 13 2

How to fix   Complexity   

Complex Class

Complex classes like XmlDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use XmlDriver, and based on these observations, apply Extract Interface, too.

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\ORM\Annotation;
9
use Doctrine\ORM\Events;
10
use Doctrine\ORM\Mapping;
11
use Doctrine\ORM\Mapping\Builder;
12
use InvalidArgumentException;
13
use SimpleXMLElement;
14
use function class_exists;
15
use function constant;
16
use function explode;
17
use function file_get_contents;
18
use function in_array;
19
use function simplexml_load_string;
20
use function str_replace;
21
use function strtoupper;
22
23
/**
24
 * XmlDriver is a metadata driver that enables mapping through XML files.
25
 */
26
class XmlDriver extends FileDriver
27
{
28
    public const DEFAULT_FILE_EXTENSION = '.dcm.xml';
29
30
    /**
31
     * {@inheritDoc}
32
     */
33 41
    public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
34
    {
35 41
        parent::__construct($locator, $fileExtension);
36 41
    }
37
38 36
    public function loadMetadataForClass(
39
        string $className,
40
        ?Mapping\ComponentMetadata $parent,
41
        Mapping\ClassMetadataBuildingContext $metadataBuildingContext
42
    ) : Mapping\ComponentMetadata {
43
        /** @var SimpleXMLElement $xmlRoot */
44 36
        $xmlRoot       = $this->getElement($className);
45 34
        $classBuilder  = new Builder\ClassMetadataBuilder($metadataBuildingContext);
46
        $classMetadata = $classBuilder
47 34
            ->withClassName($className)
48 34
            ->withParentMetadata($parent)
49 34
            ->withEntityAnnotation(
50 34
                $xmlRoot->getName() === 'entity'
51 34
                    ? $this->convertEntityElementToEntityAnnotation($xmlRoot)
52 34
                    : null
53
            )
54 34
            ->withMappedSuperclassAnnotation(
55 34
                $xmlRoot->getName() === 'mapped-superclass'
56 5
                    ? $this->convertMappedSuperclassElementToMappedSuperclassAnnotation($xmlRoot)
57 34
                    : null
58
            )
59 34
            ->withEmbeddableAnnotation(
60 34
                $xmlRoot->getName() === 'embeddable'
61
                    ? null
62 34
                    : null
63
            )
64 34
            ->withTableAnnotation(
65
                // @todo guilhermeblanco Is this the proper check to build Table annotation?
66 34
                $xmlRoot->getName() === 'entity'
67 34
                    ? $this->convertTableElementToTableAnnotation($xmlRoot)
68 34
                    : null
69
            )
70 34
            ->withInheritanceTypeAnnotation(
71 34
                isset($xmlRoot['inheritance-type'])
72 10
                    ? $this->convertInheritanceTypeElementToInheritanceTypeAnnotation($xmlRoot)
73 34
                    : null
74
            )
75 34
            ->withDiscriminatorColumnAnnotation(
76 34
                isset($xmlRoot->{'discriminator-column'})
77 8
                    ? $this->convertDiscrimininatorColumnElementToDiscriminatorColumnAnnotation($xmlRoot->{'discriminator-column'})
78 34
                    : null
79
            )
80 34
            ->withDiscriminatorMapAnnotation(
81 34
                isset($xmlRoot->{'discriminator-map'})
82 10
                    ? $this->convertDiscriminatorMapElementToDiscriminatorMapAnnotation($xmlRoot->{'discriminator-map'})
83 34
                    : null
84
            )
85 34
            ->withChangeTrackingPolicyAnnotation(
86 34
                isset($xmlRoot['change-tracking-policy'])
87
                    ? $this->convertChangeTrackingPolicyElementToChangeTrackingPolicyAnnotation($xmlRoot)
88 34
                    : null
89
            )
90 34
            ->withCacheAnnotation(
91 34
                isset($xmlRoot->cache)
92 2
                    ? $this->convertCacheElementToCacheAnnotation($xmlRoot->cache)
93 34
                    : null
94
            )
95 34
            ->build();
96
97 34
        $propertyBuilder = new Builder\PropertyMetadataBuilder($metadataBuildingContext);
98
99 34
        $propertyBuilder->withComponentMetadata($classMetadata);
100
101
        // Evaluate <field ...> mappings
102 34
        if (isset($xmlRoot->field)) {
103 20
            foreach ($xmlRoot->field as $fieldElement) {
104
                $propertyBuilder
105 20
                    ->withFieldName((string) $fieldElement['name'])
106 20
                    ->withColumnAnnotation($this->convertFieldElementToColumnAnnotation($fieldElement))
107 20
                    ->withIdAnnotation(null)
108 20
                    ->withVersionAnnotation(
109 20
                        isset($fieldElement['version']) && $this->evaluateBoolean($fieldElement['version'])
110 3
                            ? new Annotation\Version()
111 20
                            : null
112
                    );
113
114 20
                $classMetadata->addProperty($propertyBuilder->build());
115
            }
116
        }
117
118 34
        if (isset($xmlRoot->embedded)) {
119
            foreach ($xmlRoot->embedded as $embeddedElement) {
120
                $propertyBuilder
121
                    ->withFieldName((string) $embeddedElement['name'])
122
                    ->withEmbeddedAnnotation($this->convertEmbeddedElementToEmbeddedAnnotation($embeddedElement))
123
                    ->withIdAnnotation(null)
124
                    ->withVersionAnnotation(
125
                        isset($embeddedElement['version']) && $this->evaluateBoolean($embeddedElement['version'])
126
                            ? new Annotation\Version()
127
                            : null
128
                    );
129
130
                $classMetadata->addProperty($propertyBuilder->build());
131
            }
132
        }
133
134
        // Evaluate <id ...> mappings
135 34
        $associationIds = [];
136
137 34
        foreach ($xmlRoot->id as $idElement) {
138 29
            $fieldName = (string) $idElement['name'];
139
140 29
            if (isset($idElement['association-key']) && $this->evaluateBoolean($idElement['association-key'])) {
141 2
                $associationIds[$fieldName] = true;
142
143 2
                continue;
144
            }
145
146
            $propertyBuilder
147 28
                ->withFieldName($fieldName)
148 28
                ->withColumnAnnotation($this->convertFieldElementToColumnAnnotation($idElement))
149 28
                ->withIdAnnotation(new Annotation\Id())
150 28
                ->withVersionAnnotation(
151 28
                    isset($idElement['version']) && $this->evaluateBoolean($idElement['version'])
152
                        ? new Annotation\Version()
153 28
                        : null
154
                )
155 28
                ->withGeneratedValueAnnotation(
156 28
                    isset($idElement->generator)
157 27
                        ? $this->convertGeneratorElementToGeneratedValueAnnotation($idElement->generator)
158 28
                        : null
159
                )
160 28
                ->withSequenceGeneratorAnnotation(
161 28
                    isset($idElement->{'sequence-generator'})
162 3
                        ? $this->convertSequenceGeneratorElementToSequenceGeneratorAnnotation($idElement->{'sequence-generator'})
163 28
                        : null
164
                )
165 28
                ->withCustomIdGeneratorAnnotation(
166 28
                    isset($idElement->{'custom-id-generator'})
167 2
                        ? $this->convertCustomIdGeneratorElementToCustomIdGeneratorAnnotation($idElement->{'custom-id-generator'})
168 28
                        : null
169
                );
170
171 28
            $classMetadata->addProperty($propertyBuilder->build());
172
        }
173
174
        // Evaluate <one-to-one ...> mappings
175 34
        if (isset($xmlRoot->{'one-to-one'})) {
176 7
            foreach ($xmlRoot->{'one-to-one'} as $oneToOneElement) {
177 7
                $fieldName = (string) $oneToOneElement['field'];
178
179
                $propertyBuilder
180 7
                    ->withFieldName($fieldName)
181 7
                    ->withOneToOneAnnotation($this->convertOneToOneElementToOneToOneAnnotation($oneToOneElement))
182 7
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
183 7
                    ->withVersionAnnotation(null)
184 7
                    ->withCacheAnnotation(
185 7
                        isset($oneToOneElement->cache)
186
                            ? $this->convertCacheElementToCacheAnnotation($oneToOneElement->cache)
187 7
                            : null
188
                    )
189 7
                    ->withJoinColumnAnnotation(
190 7
                        isset($oneToOneElement->{'join-column'})
191 5
                            ? $this->convertJoinColumnElementToJoinColumnAnnotation($oneToOneElement->{'join-column'})
192 7
                            : null
193
                    )
194 7
                    ->withJoinColumnsAnnotation(
195 7
                        isset($oneToOneElement->{'join-columns'})
196
                            ? $this->convertJoinColumnsElementToJoinColumnsAnnotation($oneToOneElement->{'join-columns'})
197 7
                            : null
198
                    );
199
200 7
                $classMetadata->addProperty($propertyBuilder->build());
201
            }
202
        }
203
204
        // Evaluate <many-to-one ...> mappings
205 34
        if (isset($xmlRoot->{'many-to-one'})) {
206 8
            foreach ($xmlRoot->{'many-to-one'} as $manyToOneElement) {
207 8
                $fieldName = (string) $manyToOneElement['field'];
208
209
                $propertyBuilder
210 8
                    ->withFieldName($fieldName)
211 8
                    ->withManyToOneAnnotation($this->convertManyToOneElementToManyToOneAnnotation($manyToOneElement))
212 8
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
213 8
                    ->withVersionAnnotation(null)
214 8
                    ->withCacheAnnotation(
215 8
                        isset($manyToOneElement->cache)
216 1
                            ? $this->convertCacheElementToCacheAnnotation($manyToOneElement->cache)
217 8
                            : null
218
                    )
219 8
                    ->withJoinColumnAnnotation(
220 8
                        isset($manyToOneElement->{'join-column'})
221 7
                            ? $this->convertJoinColumnElementToJoinColumnAnnotation($manyToOneElement->{'join-column'})
222 8
                            : null
223
                    )
224 8
                    ->withJoinColumnsAnnotation(
225 8
                        isset($manyToOneElement->{'join-columns'})
226 1
                            ? $this->convertJoinColumnsElementToJoinColumnsAnnotation($manyToOneElement->{'join-columns'})
227 8
                            : null
228
                    );
229
230 8
                $classMetadata->addProperty($propertyBuilder->build());
231
            }
232
        }
233
234
        // Evaluate <one-to-many ...> mappings
235 33
        if (isset($xmlRoot->{'one-to-many'})) {
236 9
            foreach ($xmlRoot->{'one-to-many'} as $oneToManyElement) {
237 9
                $fieldName = (string) $oneToManyElement['field'];
238
239
                $propertyBuilder
240 9
                    ->withFieldName($fieldName)
241 9
                    ->withOneToManyAnnotation($this->convertOneToManyElementToOneToManyAnnotation($oneToManyElement))
242 9
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
243 9
                    ->withVersionAnnotation(null)
244 9
                    ->withCacheAnnotation(
245 9
                        isset($oneToManyElement->cache)
246 1
                            ? $this->convertCacheElementToCacheAnnotation($oneToManyElement->cache)
247 9
                            : null
248
                    )
249 9
                    ->withOrderByAnnotation(
250 9
                        isset($oneToManyElement->{'order-by'})
251 5
                            ? $this->convertOrderByElementToOrderByAnnotation($oneToManyElement->{'order-by'})
252 9
                            : null
253
                    );
254
255 9
                $classMetadata->addProperty($propertyBuilder->build());
256
            }
257
        }
258
259
        // Evaluate <many-to-many ...> mappings
260 33
        if (isset($xmlRoot->{'many-to-many'})) {
261 14
            foreach ($xmlRoot->{'many-to-many'} as $manyToManyElement) {
262 14
                $fieldName = (string) $manyToManyElement['field'];
263
264
                $propertyBuilder
265 14
                    ->withFieldName($fieldName)
266 14
                    ->withManyToManyAnnotation($this->convertManyToManyElementToManyToManyAnnotation($manyToManyElement))
267 14
                    ->withIdAnnotation(isset($associationIds[$fieldName]) ? new Annotation\Id() : null)
268 14
                    ->withVersionAnnotation(null)
269 14
                    ->withCacheAnnotation(
270 14
                        isset($manyToManyElement->cache)
271
                            ? $this->convertCacheElementToCacheAnnotation($manyToManyElement->cache)
272 14
                            : null
273
                    )
274 14
                    ->withJoinTableAnnotation(
275 14
                        isset($manyToManyElement->{'join-table'})
276 8
                            ? $this->convertJoinTableElementToJoinTableAnnotation($manyToManyElement->{'join-table'})
277 14
                            : null
278
                    )
279 14
                    ->withOrderByAnnotation(
280 14
                        isset($manyToManyElement->{'order-by'})
281 1
                            ? $this->convertOrderByElementToOrderByAnnotation($manyToManyElement->{'order-by'})
282 14
                            : null
283
                    );
284
285 14
                $classMetadata->addProperty($propertyBuilder->build());
286
            }
287
        }
288
289
        // Evaluate association-overrides
290 33
        if (isset($xmlRoot->{'attribute-overrides'})) {
291 2
            $fieldBuilder = new Builder\FieldMetadataBuilder($metadataBuildingContext);
292
293
            $fieldBuilder
294 2
                ->withComponentMetadata($classMetadata);
295
296 2
            foreach ($xmlRoot->{'attribute-overrides'}->{'attribute-override'} as $overrideElement) {
297 2
                $fieldName = (string) $overrideElement['name'];
298 2
                $property  = $classMetadata->getProperty($fieldName);
299
300 2
                if (! $property) {
301
                    throw Mapping\MappingException::invalidOverrideFieldName($classMetadata->getClassName(), $fieldName);
302
                }
303
304 2
                foreach ($overrideElement->field as $fieldElement) {
305 2
                    $versionAnnotation = isset($fieldElement['version']) && $this->evaluateBoolean($fieldElement['version'])
306
                        ? new Annotation\Version()
307 2
                        : null;
308
309
                    $fieldBuilder
310 2
                        ->withFieldName($fieldName)
311 2
                        ->withColumnAnnotation($this->convertFieldElementToColumnAnnotation($fieldElement))
312 2
                        ->withIdAnnotation(null)
313 2
                        ->withVersionAnnotation($versionAnnotation);
314
315 2
                    $fieldMetadata = $fieldBuilder->build();
316 2
                    $columnName    = $fieldMetadata->getColumnName();
317
318
                    // Prevent column duplication
319 2
                    if ($classMetadata->checkPropertyDuplication($columnName)) {
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

319
                    if ($classMetadata->checkPropertyDuplication(/** @scrutinizer ignore-type */ $columnName)) {
Loading history...
320
                        throw Mapping\MappingException::duplicateColumnName($classMetadata->getClassName(), $columnName);
321
                    }
322
323 2
                    $classMetadata->setPropertyOverride($fieldMetadata);
324
                }
325
            }
326
        }
327
328
        // Evaluate association-overrides
329 33
        if (isset($xmlRoot->{'association-overrides'})) {
330 4
            foreach ($xmlRoot->{'association-overrides'}->{'association-override'} as $overrideElement) {
331 4
                $fieldName = (string) $overrideElement['name'];
332 4
                $property  = $classMetadata->getProperty($fieldName);
333
334 4
                if (! $property) {
335
                    throw Mapping\MappingException::invalidOverrideFieldName($classMetadata->getClassName(), $fieldName);
336
                }
337
338 4
                $override = clone $property;
339
340
                // Check for join-columns
341 4
                if (isset($overrideElement->{'join-columns'})) {
342 2
                    $joinColumnBuilder = new Builder\JoinColumnMetadataBuilder($metadataBuildingContext);
343
344
                    $joinColumnBuilder
345 2
                        ->withComponentMetadata($classMetadata)
346 2
                        ->withFieldName($override->getName());
347
348 2
                    $joinColumns = [];
349
350 2
                    foreach ($overrideElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
351 2
                        $joinColumnBuilder->withJoinColumnAnnotation(
352 2
                            $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement)
353
                        );
354
355 2
                        $joinColumnMetadata = $joinColumnBuilder->build();
356 2
                        $columnName         = $joinColumnMetadata->getColumnName();
0 ignored issues
show
Unused Code introduced by
The assignment to $columnName is dead and can be removed.
Loading history...
357
358
                        // @todo guilhermeblanco Open an issue to discuss making this scenario impossible.
359
                        //if ($metadata->checkPropertyDuplication($columnName)) {
360
                        //    throw Mapping\MappingException::duplicateColumnName($metadata->getClassName(), $columnName);
361
                        //}
362
363 2
                        $joinColumns[] = $joinColumnMetadata;
364
                    }
365
366 2
                    $override->setJoinColumns($joinColumns);
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

366
                    $override->/** @scrutinizer ignore-call */ 
367
                               setJoinColumns($joinColumns);
Loading history...
367
                }
368
369
                // Check for join-table
370 4
                if ($overrideElement->{'join-table'}) {
371 2
                    $joinTableElement    = $overrideElement->{'join-table'};
372 2
                    $joinTableAnnotation = $this->convertJoinTableElementToJoinTableAnnotation($joinTableElement);
373 2
                    $joinTableBuilder    = new Builder\JoinTableMetadataBuilder($metadataBuildingContext);
374
375
                    $joinTableBuilder
376 2
                        ->withComponentMetadata($classMetadata)
377 2
                        ->withFieldName($property->getName())
378 2
                        ->withTargetEntity($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\EmbeddedMetadata or 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

378
                        ->withTargetEntity($property->/** @scrutinizer ignore-call */ getTargetEntity())
Loading history...
379 2
                        ->withJoinTableAnnotation($joinTableAnnotation);
380
381 2
                    $override->setJoinTable($joinTableBuilder->build());
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

381
                    $override->/** @scrutinizer ignore-call */ 
382
                               setJoinTable($joinTableBuilder->build());
Loading history...
382
                }
383
384
                // Check for inversed-by
385 4
                if (isset($overrideElement->{'inversed-by'})) {
386 1
                    $override->setInversedBy((string) $overrideElement->{'inversed-by'}['name']);
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

386
                    $override->/** @scrutinizer ignore-call */ 
387
                               setInversedBy((string) $overrideElement->{'inversed-by'}['name']);
Loading history...
387
                }
388
389
                // Check for fetch
390 4
                if (isset($overrideElement['fetch'])) {
391 1
                    $override->setFetchMode(
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

391
                    $override->/** @scrutinizer ignore-call */ 
392
                               setFetchMode(
Loading history...
392 1
                        constant('Doctrine\ORM\Mapping\FetchMode::' . (string) $overrideElement['fetch'])
393
                    );
394
                }
395
396 4
                $classMetadata->setPropertyOverride($override);
397
            }
398
        }
399
400
        // Evaluate <lifecycle-callbacks...>
401 33
        if (isset($xmlRoot->{'lifecycle-callbacks'})) {
402 3
            foreach ($xmlRoot->{'lifecycle-callbacks'}->{'lifecycle-callback'} as $lifecycleCallback) {
403 3
                $eventName  = constant(Events::class . '::' . (string) $lifecycleCallback['type']);
404 3
                $methodName = (string) $lifecycleCallback['method'];
405
406 3
                $classMetadata->addLifecycleCallback($eventName, $methodName);
407
            }
408
        }
409
410
        // Evaluate entity listener
411 33
        if (isset($xmlRoot->{'entity-listeners'})) {
412 2
            foreach ($xmlRoot->{'entity-listeners'}->{'entity-listener'} as $listenerElement) {
413 2
                $listenerClassName = (string) $listenerElement['class'];
414
415 2
                if (! class_exists($listenerClassName)) {
416
                    throw Mapping\MappingException::entityListenerClassNotFound(
417
                        $listenerClassName,
418
                        $classMetadata->getClassName()
419
                    );
420
                }
421
422 2
                foreach ($listenerElement as $callbackElement) {
423 2
                    $eventName  = (string) $callbackElement['type'];
424 2
                    $methodName = (string) $callbackElement['method'];
425
426 2
                    $classMetadata->addEntityListener($eventName, $listenerClassName, $methodName);
427
                }
428
            }
429
        }
430
431 33
        return $classMetadata;
432
    }
433
434
    /**
435
     * {@inheritDoc}
436
     */
437 36
    protected function loadMappingFile($file)
438
    {
439 36
        $result = [];
440
        // Note: we do not use `simplexml_load_file()` because of https://bugs.php.net/bug.php?id=62577
441 36
        $xmlElement = simplexml_load_string(file_get_contents($file));
442
443 36
        if (isset($xmlElement->entity)) {
444 35
            foreach ($xmlElement->entity as $entityElement) {
445 35
                $entityName          = (string) $entityElement['name'];
446 35
                $result[$entityName] = $entityElement;
447
            }
448 6
        } elseif (isset($xmlElement->{'mapped-superclass'})) {
449 5
            foreach ($xmlElement->{'mapped-superclass'} as $mappedSuperClass) {
450 5
                $className          = (string) $mappedSuperClass['name'];
451 5
                $result[$className] = $mappedSuperClass;
452
            }
453 1
        } elseif (isset($xmlElement->embeddable)) {
454
            foreach ($xmlElement->embeddable as $embeddableElement) {
455
                $embeddableName          = (string) $embeddableElement['name'];
456
                $result[$embeddableName] = $embeddableElement;
457
            }
458
        }
459
460 36
        return $result;
461
    }
462
463 34
    private function convertEntityElementToEntityAnnotation(
464
        SimpleXMLElement $entityElement
465
    ) : Annotation\Entity {
466 34
        $entityAnnotation = new Annotation\Entity();
467
468 34
        if (isset($entityElement['repository-class'])) {
469
            $entityAnnotation->repositoryClass = (string) $entityElement['repository-class'];
470
        }
471
472 34
        if (isset($entityElement['read-only'])) {
473
            $entityAnnotation->readOnly = $this->evaluateBoolean($entityElement['read-only']);
474
        }
475
476 34
        return $entityAnnotation;
477
    }
478
479 5
    private function convertMappedSuperclassElementToMappedSuperclassAnnotation(
480
        SimpleXMLElement $mappedSuperclassElement
481
    ) : Annotation\MappedSuperclass {
482 5
        $mappedSuperclassAnnotation = new Annotation\MappedSuperclass();
483
484 5
        if (isset($mappedSuperclassElement['repository-class'])) {
485 1
            $mappedSuperclassAnnotation->repositoryClass = (string) $mappedSuperclassElement['repository-class'];
486
        }
487
488 5
        return $mappedSuperclassAnnotation;
489
    }
490
491 34
    private function convertTableElementToTableAnnotation(
492
        SimpleXMLElement $tableElement
493
    ) : Annotation\Table {
494 34
        $tableAnnotation = new Annotation\Table();
495
496
        // Evaluate <entity...> attributes
497 34
        if (isset($tableElement['table'])) {
498 12
            $tableAnnotation->name = (string) $tableElement['table'];
499
        }
500
501 34
        if (isset($tableElement['schema'])) {
502 2
            $tableAnnotation->schema = (string) $tableElement['schema'];
503
        }
504
505
        // Evaluate <indexes...>
506 34
        if (isset($tableElement->indexes)) {
507 4
            $indexes = [];
508
509
            /** @var SimpleXMLElement $indexElement */
510 4
            foreach ($tableElement->indexes->children() as $indexElement) {
511 4
                $indexes[] = $this->convertIndexElementToIndexAnnotation($indexElement);
512
            }
513
514 4
            $tableAnnotation->indexes = $indexes;
515
        }
516
517
        // Evaluate <unique-constraints..>
518 34
        if (isset($tableElement->{'unique-constraints'})) {
519 3
            $uniqueConstraints = [];
520
521 3
            foreach ($tableElement->{'unique-constraints'}->children() as $uniqueConstraintElement) {
522 3
                $uniqueConstraints[] = $this->convertUniqueConstraintElementToUniqueConstraintAnnotation($uniqueConstraintElement);
523
            }
524
525 3
            $tableAnnotation->uniqueConstraints = $uniqueConstraints;
526
        }
527
528 34
        if (isset($tableElement->options)) {
529 3
            $tableAnnotation->options = $this->parseOptions($tableElement->options->children());
530
        }
531
532 34
        return $tableAnnotation;
533
    }
534
535 4
    private function convertIndexElementToIndexAnnotation(
536
        SimpleXMLElement $indexElement
537
    ) : Annotation\Index {
538 4
        $indexAnnotation = new Annotation\Index();
539
540 4
        $indexAnnotation->columns = explode(',', (string) $indexElement['columns']);
541 4
        $indexAnnotation->options = isset($indexElement->options) ? $this->parseOptions($indexElement->options->children()) : [];
542 4
        $indexAnnotation->flags   = isset($indexElement['flags']) ? explode(',', (string) $indexElement['flags']) : [];
543
544 4
        if (isset($indexElement['name'])) {
545 3
            $indexAnnotation->name = (string) $indexElement['name'];
546
        }
547
548 4
        if (isset($indexElement['unique'])) {
549
            $indexAnnotation->unique = $this->evaluateBoolean($indexElement['unique']);
550
        }
551
552 4
        return $indexAnnotation;
553
    }
554
555 3
    private function convertUniqueConstraintElementToUniqueConstraintAnnotation(
556
        SimpleXMLElement $uniqueConstraintElement
557
    ) : Annotation\UniqueConstraint {
558 3
        $uniqueConstraintAnnotation = new Annotation\UniqueConstraint();
559
560 3
        $uniqueConstraintAnnotation->columns = explode(',', (string) $uniqueConstraintElement['columns']);
561 3
        $uniqueConstraintAnnotation->options = isset($uniqueConstraintElement->options) ? $this->parseOptions($uniqueConstraintElement->options->children()) : [];
562 3
        $uniqueConstraintAnnotation->flags   = isset($uniqueConstraintElement['flags']) ? explode(',', (string) $uniqueConstraintElement['flags']) : [];
563
564 3
        if (isset($uniqueConstraintElement['name'])) {
565 3
            $uniqueConstraintAnnotation->name = (string) $uniqueConstraintElement['name'];
566
        }
567
568 3
        return $uniqueConstraintAnnotation;
569
    }
570
571 10
    private function convertInheritanceTypeElementToInheritanceTypeAnnotation(
572
        SimpleXMLElement $inheritanceTypeElement
573
    ) : Annotation\InheritanceType {
574 10
        $inheritanceTypeAnnotation = new Annotation\InheritanceType();
575
576 10
        $inheritanceTypeAnnotation->value = strtoupper((string) $inheritanceTypeElement['inheritance-type']);
577
578 10
        return $inheritanceTypeAnnotation;
579
    }
580
581
    private function convertChangeTrackingPolicyElementToChangeTrackingPolicyAnnotation(
582
        SimpleXMLElement $changeTrackingPolicyElement
583
    ) : Annotation\ChangeTrackingPolicy {
584
        $changeTrackingPolicyAnnotation = new Annotation\ChangeTrackingPolicy();
585
586
        $changeTrackingPolicyAnnotation->value = strtoupper((string) $changeTrackingPolicyElement['change-tracking-policy']);
587
588
        return $changeTrackingPolicyAnnotation;
589
    }
590
591 8
    private function convertDiscrimininatorColumnElementToDiscriminatorColumnAnnotation(
592
        SimpleXMLElement $discriminatorColumnElement
593
    ) : Annotation\DiscriminatorColumn {
594 8
        $discriminatorColumnAnnotation = new Annotation\DiscriminatorColumn();
595
596 8
        $discriminatorColumnAnnotation->type = (string) ($discriminatorColumnElement['type'] ?? 'string');
597 8
        $discriminatorColumnAnnotation->name = (string) $discriminatorColumnElement['name'];
598
599 8
        if (isset($discriminatorColumnElement['column-definition'])) {
600 1
            $discriminatorColumnAnnotation->columnDefinition = (string) $discriminatorColumnElement['column-definition'];
601
        }
602
603 8
        if (isset($discriminatorColumnElement['length'])) {
604 3
            $discriminatorColumnAnnotation->length = (int) $discriminatorColumnElement['length'];
605
        }
606
607 8
        return $discriminatorColumnAnnotation;
608
    }
609
610 10
    private function convertDiscriminatorMapElementToDiscriminatorMapAnnotation(
611
        SimpleXMLElement $discriminatorMapElement
612
    ) : Annotation\DiscriminatorMap {
613 10
        $discriminatorMapAnnotation = new Annotation\DiscriminatorMap();
614 10
        $discriminatorMap           = [];
615
616 10
        foreach ($discriminatorMapElement->{'discriminator-mapping'} as $discriminatorMapElement) {
617 10
            $discriminatorMap[(string) $discriminatorMapElement['value']] = (string) $discriminatorMapElement['class'];
618
        }
619
620 10
        $discriminatorMapAnnotation->value = $discriminatorMap;
621
622 10
        return $discriminatorMapAnnotation;
623
    }
624
625 2
    private function convertCacheElementToCacheAnnotation(
626
        SimpleXMLElement $cacheElement
627
    ) : Annotation\Cache {
628 2
        $cacheAnnotation = new Annotation\Cache();
629
630 2
        if (isset($cacheElement['region'])) {
631
            $cacheAnnotation->region = (string) $cacheElement['region'];
632
        }
633
634 2
        if (isset($cacheElement['usage'])) {
635 2
            $cacheAnnotation->usage = strtoupper((string) $cacheElement['usage']);
636
        }
637
638 2
        return $cacheAnnotation;
639
    }
640
641 30
    private function convertFieldElementToColumnAnnotation(
642
        SimpleXMLElement $fieldElement
643
    ) : Annotation\Column {
644 30
        $columnAnnotation = new Annotation\Column();
645
646 30
        $columnAnnotation->type = isset($fieldElement['type']) ? (string) $fieldElement['type'] : 'string';
647
648 30
        if (isset($fieldElement['column'])) {
649 20
            $columnAnnotation->name = (string) $fieldElement['column'];
650
        }
651
652 30
        if (isset($fieldElement['length'])) {
653 6
            $columnAnnotation->length = (int) $fieldElement['length'];
654
        }
655
656 30
        if (isset($fieldElement['precision'])) {
657 1
            $columnAnnotation->precision = (int) $fieldElement['precision'];
658
        }
659
660 30
        if (isset($fieldElement['scale'])) {
661 1
            $columnAnnotation->scale = (int) $fieldElement['scale'];
662
        }
663
664 30
        if (isset($fieldElement['unique'])) {
665 7
            $columnAnnotation->unique = $this->evaluateBoolean($fieldElement['unique']);
666
        }
667
668 30
        if (isset($fieldElement['nullable'])) {
669 7
            $columnAnnotation->nullable = $this->evaluateBoolean($fieldElement['nullable']);
670
        }
671
672 30
        if (isset($fieldElement['column-definition'])) {
673 4
            $columnAnnotation->columnDefinition = (string) $fieldElement['column-definition'];
674
        }
675
676 30
        if (isset($fieldElement->options)) {
677 3
            $columnAnnotation->options = $this->parseOptions($fieldElement->options->children());
678
        }
679
680 30
        return $columnAnnotation;
681
    }
682
683
    private function convertEmbeddedElementToEmbeddedAnnotation(
684
        SimpleXMLElement $embeddedElement
685
    ) : Annotation\Embedded {
686
        $embeddedAnnotation = new Annotation\Embedded();
687
688
        $embeddedAnnotation->class = (string) $embeddedElement['class'];
689
690
        if (isset($embeddedElement['column-prefix'])) {
691
            $embeddedAnnotation->columnPrefix = (string) $embeddedElement['column-prefix'];
692
        }
693
694
        return $embeddedAnnotation;
695
    }
696
697 7
    private function convertOneToOneElementToOneToOneAnnotation(
698
        SimpleXMLElement $oneToOneElement
699
    ) : Annotation\OneToOne {
700 7
        $oneToOneAnnotation = new Annotation\OneToOne();
701
702 7
        $oneToOneAnnotation->targetEntity = (string) $oneToOneElement['target-entity'];
703
704 7
        if (isset($oneToOneElement['mapped-by'])) {
705 3
            $oneToOneAnnotation->mappedBy = (string) $oneToOneElement['mapped-by'];
706
        }
707
708 7
        if (isset($oneToOneElement['inversed-by'])) {
709 4
            $oneToOneAnnotation->inversedBy = (string) $oneToOneElement['inversed-by'];
710
        }
711
712 7
        if (isset($oneToOneElement['orphan-removal'])) {
713
            $oneToOneAnnotation->orphanRemoval = $this->evaluateBoolean($oneToOneElement['orphan-removal']);
714
        }
715
716 7
        if (isset($oneToOneElement['fetch'])) {
717 3
            $oneToOneAnnotation->fetch = (string) $oneToOneElement['fetch'];
718
        }
719
720 7
        if (isset($oneToOneElement->cascade)) {
721 7
            $oneToOneAnnotation->cascade = $this->getCascadeMappings($oneToOneElement->cascade);
722
        }
723
724 7
        return $oneToOneAnnotation;
725
    }
726
727 8
    private function convertManyToOneElementToManyToOneAnnotation(
728
        SimpleXMLElement $manyToOneElement
729
    ) : Annotation\ManyToOne {
730 8
        $manyToOneAnnotation = new Annotation\ManyToOne();
731
732 8
        $manyToOneAnnotation->targetEntity = (string) $manyToOneElement['target-entity'];
733
734 8
        if (isset($manyToOneElement['inversed-by'])) {
735 2
            $manyToOneAnnotation->inversedBy = (string) $manyToOneElement['inversed-by'];
736
        }
737
738 8
        if (isset($manyToOneElement['fetch'])) {
739
            $manyToOneAnnotation->fetch = (string) $manyToOneElement['fetch'];
740
        }
741
742 8
        if (isset($manyToOneElement->cascade)) {
743 4
            $manyToOneAnnotation->cascade = $this->getCascadeMappings($manyToOneElement->cascade);
744
        }
745
746 8
        return $manyToOneAnnotation;
747
    }
748
749 9
    private function convertOneToManyElementToOneToManyAnnotation(
750
        SimpleXMLElement $oneToManyElement
751
    ) : Annotation\OneToMany {
752 9
        $oneToManyAnnotation = new Annotation\OneToMany();
753
754 9
        $oneToManyAnnotation->targetEntity = (string) $oneToManyElement['target-entity'];
755
756 9
        if (isset($oneToManyElement['mapped-by'])) {
757 9
            $oneToManyAnnotation->mappedBy = (string) $oneToManyElement['mapped-by'];
758
        }
759
760 9
        if (isset($oneToManyElement['fetch'])) {
761
            $oneToManyAnnotation->fetch = (string) $oneToManyElement['fetch'];
762
        }
763
764 9
        if (isset($oneToManyElement->cascade)) {
765 6
            $oneToManyAnnotation->cascade = $this->getCascadeMappings($oneToManyElement->cascade);
766
        }
767
768 9
        if (isset($oneToManyElement['orphan-removal'])) {
769 3
            $oneToManyAnnotation->orphanRemoval = $this->evaluateBoolean($oneToManyElement['orphan-removal']);
770
        }
771
772 9
        if (isset($oneToManyElement['index-by'])) {
773 3
            $oneToManyAnnotation->indexBy = (string) $oneToManyElement['index-by'];
774 6
        } elseif (isset($oneToManyElement->{'index-by'})) {
775
            throw new InvalidArgumentException('<index-by /> is not a valid tag');
776
        }
777
778 9
        return $oneToManyAnnotation;
779
    }
780
781 14
    private function convertManyToManyElementToManyToManyAnnotation(
782
        SimpleXMLElement $manyToManyElement
783
    ) : Annotation\ManyToMany {
784 14
        $manyToManyAnnotation = new Annotation\ManyToMany();
785
786 14
        $manyToManyAnnotation->targetEntity = (string) $manyToManyElement['target-entity'];
787
788 14
        if (isset($manyToManyElement['mapped-by'])) {
789 5
            $manyToManyAnnotation->mappedBy = (string) $manyToManyElement['mapped-by'];
790
        }
791
792 14
        if (isset($manyToManyElement['inversed-by'])) {
793 6
            $manyToManyAnnotation->inversedBy = (string) $manyToManyElement['inversed-by'];
794
        }
795
796 14
        if (isset($manyToManyElement['fetch'])) {
797 4
            $manyToManyAnnotation->fetch = (string) $manyToManyElement['fetch'];
798
        }
799
800 14
        if (isset($manyToManyElement->cascade)) {
801 8
            $manyToManyAnnotation->cascade = $this->getCascadeMappings($manyToManyElement->cascade);
802
        }
803
804 14
        if (isset($manyToManyElement['orphan-removal'])) {
805
            $manyToManyAnnotation->orphanRemoval = $this->evaluateBoolean($manyToManyElement['orphan-removal']);
806
        }
807
808 14
        if (isset($manyToManyElement['index-by'])) {
809
            $manyToManyAnnotation->indexBy = (string) $manyToManyElement['index-by'];
810 14
        } elseif (isset($manyToManyElement->{'index-by'})) {
811
            throw new InvalidArgumentException('<index-by /> is not a valid tag');
812
        }
813
814 14
        return $manyToManyAnnotation;
815
    }
816
817
    /**
818
     * Constructs a JoinTable annotation based on the information
819
     * found in the given SimpleXMLElement.
820
     *
821
     * @param SimpleXMLElement $joinTableElement The XML element.
822
     */
823 8
    private function convertJoinTableElementToJoinTableAnnotation(
824
        SimpleXMLElement $joinTableElement
825
    ) : Annotation\JoinTable {
826 8
        $joinTableAnnotation = new Annotation\JoinTable();
827
828 8
        if (isset($joinTableElement['name'])) {
829 8
            $joinTableAnnotation->name = (string) $joinTableElement['name'];
830
        }
831
832 8
        if (isset($joinTableElement['schema'])) {
833
            $joinTableAnnotation->schema = (string) $joinTableElement['schema'];
834
        }
835
836 8
        if (isset($joinTableElement->{'join-columns'})) {
837 8
            $joinColumns = [];
838
839 8
            foreach ($joinTableElement->{'join-columns'}->{'join-column'} as $joinColumnElement) {
840 8
                $joinColumns[] = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
841
            }
842
843 8
            $joinTableAnnotation->joinColumns = $joinColumns;
844
        }
845
846 8
        if (isset($joinTableElement->{'inverse-join-columns'})) {
847 8
            $joinColumns = [];
848
849 8
            foreach ($joinTableElement->{'inverse-join-columns'}->{'join-column'} as $joinColumnElement) {
850 8
                $joinColumns[] = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
851
            }
852
853 8
            $joinTableAnnotation->inverseJoinColumns = $joinColumns;
854
        }
855
856 8
        return $joinTableAnnotation;
857
    }
858
859 1
    private function convertJoinColumnsElementToJoinColumnsAnnotation(
860
        SimpleXMLElement $joinColumnsElement
861
    ) : Annotation\JoinColumns {
862 1
        $joinColumnsAnnotation = new Annotation\JoinColumns();
863 1
        $joinColumns           = [];
864
865 1
        foreach ($joinColumnsElement->{'join-column'} as $joinColumnElement) {
866 1
            $joinColumns[] = $this->convertJoinColumnElementToJoinColumnAnnotation($joinColumnElement);
867
        }
868
869 1
        $joinColumnsAnnotation->value = $joinColumns;
870
871 1
        return $joinColumnsAnnotation;
872
    }
873
874
    /**
875
     * Constructs a JoinColumn annotation based on the information
876
     * found in the given SimpleXMLElement.
877
     *
878
     * @param SimpleXMLElement $joinColumnElement The XML element.
879
     */
880 13
    private function convertJoinColumnElementToJoinColumnAnnotation(
881
        SimpleXMLElement $joinColumnElement
882
    ) : Annotation\JoinColumn {
883 13
        $joinColumnAnnotation = new Annotation\JoinColumn();
884
885 13
        $joinColumnAnnotation->name                 = (string) $joinColumnElement['name'];
886 13
        $joinColumnAnnotation->referencedColumnName = (string) $joinColumnElement['referenced-column-name'];
887
888 13
        if (isset($joinColumnElement['column-definition'])) {
889 3
            $joinColumnAnnotation->columnDefinition = (string) $joinColumnElement['column-definition'];
890
        }
891
892 13
        if (isset($joinColumnElement['field-name'])) {
893
            $joinColumnAnnotation->fieldName = (string) $joinColumnElement['field-name'];
894
        }
895
896 13
        if (isset($joinColumnElement['nullable'])) {
897 4
            $joinColumnAnnotation->nullable = $this->evaluateBoolean($joinColumnElement['nullable']);
898
        }
899
900 13
        if (isset($joinColumnElement['unique'])) {
901 3
            $joinColumnAnnotation->unique = $this->evaluateBoolean($joinColumnElement['unique']);
902
        }
903
904 13
        if (isset($joinColumnElement['on-delete'])) {
905 3
            $joinColumnAnnotation->onDelete = strtoupper((string) $joinColumnElement['on-delete']);
906
        }
907
908 13
        return $joinColumnAnnotation;
909
    }
910
911 6
    private function convertOrderByElementToOrderByAnnotation(
912
        SimpleXMLElement $orderByElement
913
    ) : Annotation\OrderBy {
914 6
        $orderByAnnotation = new Annotation\OrderBy();
915 6
        $orderBy           = [];
916
917 6
        foreach ($orderByElement->{'order-by-field'} as $orderByField) {
918 6
            $orderBy[(string) $orderByField['name']] = isset($orderByField['direction'])
919 4
                ? (string) $orderByField['direction']
920 2
                : Criteria::ASC;
921
        }
922
923 6
        $orderByAnnotation->value = $orderBy;
924
925 6
        return $orderByAnnotation;
926
    }
927
928 27
    private function convertGeneratorElementToGeneratedValueAnnotation(
929
        SimpleXMLElement $generatorElement
930
    ) : Annotation\GeneratedValue {
931 27
        $generatedValueAnnotation = new Annotation\GeneratedValue();
932
933 27
        $generatedValueAnnotation->strategy = (string) ($generatorElement['strategy'] ?? 'AUTO');
934
935 27
        return $generatedValueAnnotation;
936
    }
937
938 3
    private function convertSequenceGeneratorElementToSequenceGeneratorAnnotation(
939
        SimpleXMLElement $sequenceGeneratorElement
940
    ) : Annotation\SequenceGenerator {
941 3
        $sequenceGeneratorAnnotation = new Annotation\SequenceGenerator();
942
943 3
        $sequenceGeneratorAnnotation->sequenceName   = (string) ($sequenceGeneratorElement['sequence-name'] ?? null);
944 3
        $sequenceGeneratorAnnotation->allocationSize = (int) ($sequenceGeneratorElement['allocation-size'] ?? 1);
945
946 3
        return $sequenceGeneratorAnnotation;
947
    }
948
949 2
    private function convertCustomIdGeneratorElementToCustomIdGeneratorAnnotation(
950
        SimpleXMLElement $customIdGeneratorElement
951
    ) : Annotation\CustomIdGenerator {
952 2
        $customIdGeneratorAnnotation = new Annotation\CustomIdGenerator();
953
954 2
        $customIdGeneratorAnnotation->class     = (string) $customIdGeneratorElement['class'];
955 2
        $customIdGeneratorAnnotation->arguments = [];
956
957 2
        return $customIdGeneratorAnnotation;
958
    }
959
960
    /**
961
     * Gathers a list of cascade options found in the given cascade element.
962
     *
963
     * @param SimpleXMLElement $cascadeElement The cascade element.
964
     *
965
     * @return string[] The list of cascade options.
966
     */
967 10
    private function getCascadeMappings(SimpleXMLElement $cascadeElement) : array
968
    {
969 10
        $cascades = [];
970
971
        /** @var SimpleXMLElement $action */
972 10
        foreach ($cascadeElement->children() as $action) {
973
            // According to the JPA specifications, XML uses "cascade-persist"
974
            // instead of "persist". Here, both variations are supported
975
            // because Annotation use "persist" and we want to make sure that
976
            // this driver doesn't need to know anything about the supported
977
            // cascading actions
978 10
            $cascades[] = str_replace('cascade-', '', $action->getName());
979
        }
980
981 10
        return $cascades;
982
    }
983
984
    /**
985
     * @param mixed $element
986
     *
987
     * @return bool
988
     */
989 9
    private function evaluateBoolean($element)
990
    {
991 9
        $flag = (string) $element;
992
993 9
        return $flag === 'true' || $flag === '1';
994
    }
995
996
    /**
997
     * Parses (nested) option elements.
998
     *
999
     * @param SimpleXMLElement $options The XML element.
1000
     *
1001
     * @return mixed[] The options array.
1002
     */
1003 4
    private function parseOptions(SimpleXMLElement $options) : array
1004
    {
1005 4
        $array = [];
1006
1007
        /** @var SimpleXMLElement $option */
1008 4
        foreach ($options as $option) {
1009 4
            if ($option->count()) {
1010 3
                $value = $this->parseOptions($option->children());
1011
            } else {
1012 4
                $value = (string) $option;
1013
            }
1014
1015 4
            $attributes = $option->attributes();
1016
1017 4
            if (isset($attributes->name)) {
1018 4
                $nameAttribute = (string) $attributes->name;
1019
1020 4
                $array[$nameAttribute] = in_array($nameAttribute, ['unsigned', 'fixed'], true)
1021 3
                    ? $this->evaluateBoolean($value)
1022 4
                    : $value;
1023
            } else {
1024
                $array[] = $value;
1025
            }
1026
        }
1027
1028 4
        return $array;
1029
    }
1030
}
1031