Completed
Push — master ( e91634...cfc9d7 )
by Gerrit
11:16
created

MappingXmlDriver::readObject()   F

Complexity

Conditions 13
Paths 545

Size

Total Lines 129

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 57
CRAP Score 13.1458

Importance

Changes 0
Metric Value
dl 0
loc 129
ccs 57
cts 63
cp 0.9048
rs 2.4655
c 0
b 0
f 0
cc 13
nc 545
nop 2
crap 13.1458

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright (C) 2018 Gerrit Addiks.
4
 * This package (including this file) was released under the terms of the GPL-3.0.
5
 * You should have received a copy of the GNU General Public License along with this program.
6
 * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy.
7
 * @license GPL-3.0
8
 * @author Gerrit Addiks <[email protected]>
9
 */
10
11
namespace Addiks\RDMBundle\Mapping\Drivers;
12
13
use DOMDocument;
14
use DOMXPath;
15
use DOMNode;
16
use DOMAttr;
17
use DOMNamedNodeMap;
18
use Doctrine\DBAL\Schema\Column;
19
use Doctrine\DBAL\Types\Type;
20
use Doctrine\Common\Persistence\Mapping\Driver\FileLocator;
21
use Addiks\RDMBundle\Mapping\Drivers\MappingDriverInterface;
22
use Addiks\RDMBundle\Mapping\EntityMappingInterface;
23
use Addiks\RDMBundle\Mapping\EntityMapping;
24
use Addiks\RDMBundle\Mapping\ServiceMapping;
25
use Addiks\RDMBundle\Mapping\MappingInterface;
26
use Addiks\RDMBundle\Mapping\ChoiceMapping;
27
use Addiks\RDMBundle\Mapping\ObjectMapping;
28
use Addiks\RDMBundle\Mapping\CallDefinitionInterface;
29
use Addiks\RDMBundle\Mapping\CallDefinition;
30
use Addiks\RDMBundle\Mapping\FieldMapping;
31
use Addiks\RDMBundle\Mapping\ArrayMapping;
32
use Addiks\RDMBundle\Mapping\ListMapping;
33
use Addiks\RDMBundle\Mapping\NullMapping;
34
use Addiks\RDMBundle\Mapping\NullableMapping;
35
use Addiks\RDMBundle\Mapping\MappingProxy;
36
use Addiks\RDMBundle\Exception\InvalidMappingException;
37
use Symfony\Component\HttpKernel\KernelInterface;
38
39
final class MappingXmlDriver implements MappingDriverInterface
40
{
41
42
    const RDM_SCHEMA_URI = "http://github.com/addiks/symfony_rdm/tree/master/Resources/mapping-schema.v1.xsd";
43
    const DOCTRINE_SCHEMA_URI = "http://doctrine-project.org/schemas/orm/doctrine-mapping";
44
45
    /**
46
     * @var FileLocator
47
     */
48
    private $doctrineFileLocator;
49
50
    /**
51
     * @var KernelInterface
52
     */
53
    private $kernel;
54
55
    /**
56
     * @var string
57
     */
58
    private $schemaFilePath;
59
60 3
    public function __construct(
61
        FileLocator $doctrineFileLocator,
62
        KernelInterface $kernel,
63
        string $schemaFilePath
64
    ) {
65 3
        $this->doctrineFileLocator = $doctrineFileLocator;
66 3
        $this->kernel = $kernel;
67 3
        $this->schemaFilePath = $schemaFilePath;
68 3
    }
69
70 2
    public function loadRDMMetadataForClass(string $className): ?EntityMappingInterface
71
    {
72
        /** @var ?EntityMappingInterface $mapping */
0 ignored issues
show
Documentation introduced by
The doc-type ?EntityMappingInterface could not be parsed: Unknown type name "?EntityMappingInterface" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
73 2
        $mapping = null;
74
75
        /** @var array<MappingInterface> $fieldMappings */
76 2
        $fieldMappings = array();
77
78 2
        if ($this->doctrineFileLocator->fileExists($className)) {
79
            /** @var string $mappingFile */
80 2
            $mappingFile = $this->doctrineFileLocator->findMappingFile($className);
81
82 2
            $fieldMappings = $this->readFieldMappingsFromFile($mappingFile);
83
        }
84
85 1
        if (!empty($fieldMappings)) {
86 1
            $mapping = new EntityMapping($className, $fieldMappings);
87
        }
88
89 1
        return $mapping;
90
    }
91
92
    /**
93
     * @return array<MappingInterface>
94
     */
95 2
    private function readFieldMappingsFromFile(string $mappingFile, string $parentMappingFile = null): array
96
    {
97 2
        if ($mappingFile[0] === '@') {
98
            /** @var string $mappingFile */
99 1
            $mappingFile = $this->kernel->locateResource($mappingFile);
100
        }
101
102 2
        if ($mappingFile[0] !== DIRECTORY_SEPARATOR && !empty($parentMappingFile)) {
103 1
            $mappingFile = dirname($parentMappingFile) . DIRECTORY_SEPARATOR . $mappingFile;
104
        }
105
106 2
        if (!file_exists($mappingFile)) {
107 1
            throw new InvalidMappingException(sprintf(
108 1
                "Missing referenced orm file '%s', referenced in file '%s'!",
109 1
                $mappingFile,
110 1
                $parentMappingFile
111
            ));
112
        }
113
114 2
        $dom = new DOMDocument();
115 2
        $dom->loadXML(file_get_contents($mappingFile));
116
117
        /** @var DOMXPath $xpath */
118 2
        $xpath = $this->createXPath($dom->documentElement);
119
120
        /** @var array<MappingInterface> $fieldMappings */
121 2
        $fieldMappings = $this->readFieldMappings(
122 2
            $dom,
123 2
            $mappingFile,
124 2
            null,
125 2
            false
126
        );
127
128 2
        foreach ($xpath->query("//orm:entity", $dom) as $entityNode) {
129
            /** @var DOMNode $entityNode */
130
131 2
            $fieldMappings = array_merge($fieldMappings, $this->readFieldMappings(
132 2
                $entityNode,
133 2
                $mappingFile,
134 2
                null,
135 2
                false
136
            ));
137
        }
138
139 1
        return $fieldMappings;
140
    }
141
142 2
    private function createXPath(DOMNode $node): DOMXPath
143
    {
144
        /** @var DOMNode $ownerDocument */
145 2
        $ownerDocument = $node;
146
147 2
        if (!$ownerDocument instanceof DOMDocument) {
148 2
            $ownerDocument = $node->ownerDocument;
149
        }
150
151 2
        $xpath = new DOMXPath($ownerDocument);
152 2
        $xpath->registerNamespace('rdm', self::RDM_SCHEMA_URI);
153 2
        $xpath->registerNamespace('orm', self::DOCTRINE_SCHEMA_URI);
154
155 2
        return $xpath;
156
    }
157
158 1
    private function readObject(DOMNode $objectNode, string $mappingFile): ObjectMapping
159
    {
160
        /** @var DOMNamedNodeMap $attributes */
161 1
        $objectNodeAttributes = $objectNode->attributes;
162
163 1
        if (is_null($objectNodeAttributes->getNamedItem("class"))) {
164
            throw new InvalidMappingException(sprintf(
165
                "Missing 'class' attribute on 'object' mapping in %s",
166
                $mappingFile
167
            ));
168
        }
169
170 1
        $className = (string)$objectNodeAttributes->getNamedItem("class")->nodeValue;
171
172
        /** @var CallDefinitionInterface|null $factory */
173 1
        $factory = null;
174
175
        /** @var CallDefinitionInterface|null $factory */
176 1
        $serializer = null;
177
178
        /** @var DOMXPath $xpath */
179 1
        $xpath = $this->createXPath($objectNode);
180
181 1
        foreach ($xpath->query('./rdm:factory', $objectNode) as $factoryNode) {
182
            /** @var DOMNode $factoryNode */
183
184
            /** @var array<MappingInterface> $argumentMappings */
185 1
            $argumentMappings = $this->readFieldMappings($factoryNode, $mappingFile);
186
187
            /** @var string $routineName */
188 1
            $routineName = (string)$factoryNode->attributes->getNamedItem('method')->nodeValue;
189
190
            /** @var string $objectReference */
191 1
            $objectReference = (string)$factoryNode->attributes->getNamedItem('object')->nodeValue;
192
193 1
            $factory = new CallDefinition(
194 1
                $this->kernel->getContainer(),
0 ignored issues
show
Bug introduced by
It seems like $this->kernel->getContainer() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
195 1
                $routineName,
196 1
                $objectReference,
197 1
                $argumentMappings
198
            );
199
        }
200
201 1
        if ($objectNodeAttributes->getNamedItem("factory") !== null && is_null($factory)) {
202 1
            $factory = $this->readCallDefinition(
203 1
                (string)$objectNodeAttributes->getNamedItem("factory")->nodeValue
204
            );
205
        }
206
207 1
        if ($objectNodeAttributes->getNamedItem("serialize") !== null) {
208 1
            $serializer = $this->readCallDefinition(
209 1
                (string)$objectNodeAttributes->getNamedItem("serialize")->nodeValue
210
            );
211
        }
212
213
        /** @var array<MappingInterface> $fieldMappings */
214 1
        $fieldMappings = $this->readFieldMappings($objectNode, $mappingFile);
215
216
        /** @var Column|null $dbalColumn */
217 1
        $dbalColumn = null;
218
219 1
        if ($objectNodeAttributes->getNamedItem("column") !== null) {
220
            /** @var bool $notnull */
221 1
            $notnull = true;
222
223
            /** @var string $type */
224 1
            $type = "string";
225
226
            /** @var int $length */
227 1
            $length = 255;
228
229
            /** @var string|null $default */
230 1
            $default = null;
231
232 1
            if ($objectNodeAttributes->getNamedItem("nullable")) {
233 1
                $notnull = (strtolower($objectNodeAttributes->getNamedItem("nullable")->nodeValue) !== 'true');
234
            }
235
236 1
            if ($objectNodeAttributes->getNamedItem("column-type")) {
237 1
                $type = (string)$objectNodeAttributes->getNamedItem("column-type")->nodeValue;
238
            }
239
240 1
            if ($objectNodeAttributes->getNamedItem("column-length")) {
241
                $length = (int)$objectNodeAttributes->getNamedItem("column-length")->nodeValue;
242
            }
243
244 1
            if ($objectNodeAttributes->getNamedItem("column-default")) {
245 1
                $default = (string)$objectNodeAttributes->getNamedItem("column-default")->nodeValue;
246
            }
247
248 1
            $dbalColumn = new Column(
249 1
                (string)$objectNodeAttributes->getNamedItem("column")->nodeValue,
250 1
                Type::getType($type),
251
                [
252 1
                    'notnull' => $notnull,
253 1
                    'length' => $length,
254 1
                    'default' => $default
255
                ]
256
            );
257
        }
258
259
        /** @var string|null $id */
260 1
        $id = null;
261
262
        /** @var string|null $referencedId */
263 1
        $referencedId = null;
264
265 1
        if ($objectNodeAttributes->getNamedItem("id") !== null) {
266
            $id = (string)$objectNodeAttributes->getNamedItem("id")->nodeValue;
267
        }
268
269 1
        if ($objectNodeAttributes->getNamedItem("references-id") !== null) {
270
            $referencedId = (string)$objectNodeAttributes->getNamedItem("references-id")->nodeValue;
271
        }
272
273 1
        return new ObjectMapping(
274 1
            $className,
275 1
            $fieldMappings,
276 1
            $dbalColumn,
277 1
            sprintf(
278 1
                "in file '%s'",
279 1
                $mappingFile
280
            ),
281 1
            $factory,
282 1
            $serializer,
283 1
            $id,
284 1
            $referencedId
285
        );
286
    }
287
288 1
    private function readCallDefinition(string $callDefinition): CallDefinitionInterface
289
    {
290
        /** @var string $routineName */
291 1
        $routineName = $callDefinition;
292
293
        /** @var string|null $objectReference */
294 1
        $objectReference = null;
295
296
        /** @var bool $isStaticCall */
297 1
        $isStaticCall = false;
298
299 1
        if (strpos($callDefinition, '::') !== false) {
300 1
            [$objectReference, $routineName] = explode('::', $callDefinition);
301 1
            $isStaticCall = true;
302
        }
303
304 1
        if (strpos($callDefinition, '->') !== false) {
305
            [$objectReference, $routineName] = explode('->', $callDefinition);
306
        }
307
308 1
        return new CallDefinition(
309 1
            $this->kernel->getContainer(),
0 ignored issues
show
Bug introduced by
It seems like $this->kernel->getContainer() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
310 1
            $routineName,
311 1
            $objectReference,
312 1
            [],
313 1
            $isStaticCall
314
        );
315
    }
316
317 1
    private function readChoice(
318
        DOMNode $choiceNode,
319
        string $mappingFile,
320
        string $defaultColumnName
321
    ): ChoiceMapping {
322
        /** @var string|Column $columnName */
323 1
        $column = $defaultColumnName;
324
325 1
        if (!is_null($choiceNode->attributes->getNamedItem("column"))) {
326 1
            $column = (string)$choiceNode->attributes->getNamedItem("column")->nodeValue;
327
        }
328
329
        /** @var array<MappingInterface> $choiceMappings */
330 1
        $choiceMappings = array();
331
332
        /** @var DOMXPath $xpath */
333 1
        $xpath = $this->createXPath($choiceNode);
334
335 1
        foreach ($xpath->query('./rdm:option', $choiceNode) as $optionNode) {
336
            /** @var DOMNode $optionNode */
337
338
            /** @var string $determinator */
339 1
            $determinator = (string)$optionNode->attributes->getNamedItem("name")->nodeValue;
340
341
            /** @var string $optionDefaultColumnName */
342 1
            $optionDefaultColumnName = sprintf("%s_%s", $defaultColumnName, $determinator);
343
344 1
            foreach ($this->readFieldMappings($optionNode, $mappingFile, $optionDefaultColumnName) as $mapping) {
345
                /** @var MappingInterface $mapping */
346
347 1
                $choiceMappings[$determinator] = $mapping;
348
            }
349
        }
350
351 1
        foreach ($xpath->query('./orm:field', $choiceNode) as $fieldNode) {
352
            /** @var DOMNode $fieldNode */
353
354 1
            $column = $this->readDoctrineField($fieldNode);
355
        }
356
357 1
        return new ChoiceMapping($column, $choiceMappings, sprintf(
358 1
            "in file '%s'",
359 1
            $mappingFile
360
        ));
361
    }
362
363
    /**
364
     * @return array<MappingInterface>
365
     */
366 2
    private function readFieldMappings(
367
        DOMNode $parentNode,
368
        string $mappingFile,
369
        string $choiceDefaultColumnName = null,
370
        bool $readFields = true
371
    ): array {
372
        /** @var DOMXPath $xpath */
373 2
        $xpath = $this->createXPath($parentNode);
374
375
        /** @var array<MappingInterface> $fieldMappings */
376 2
        $fieldMappings = array();
377
378 2
        foreach ($xpath->query('./rdm:service', $parentNode) as $serviceNode) {
379
            /** @var DOMNode $serviceNode */
380
381 1
            $serviceMapping = $this->readService($serviceNode, $mappingFile);
382
383 1
            if (!is_null($serviceNode->attributes->getNamedItem("field"))) {
384
                /** @var string $fieldName */
385 1
                $fieldName = (string)$serviceNode->attributes->getNamedItem("field")->nodeValue;
386
387 1
                $fieldMappings[$fieldName] = $serviceMapping;
388
389
            } else {
390 1
                $fieldMappings[] = $serviceMapping;
391
            }
392
        }
393
394 2
        foreach ($xpath->query('./rdm:choice', $parentNode) as $choiceNode) {
395
            /** @var DOMNode $choiceNode */
396
397
            /** @var string $defaultColumnName */
398 1
            $defaultColumnName = "";
399
400 1
            if (!is_null($choiceDefaultColumnName)) {
401
                $defaultColumnName = $choiceDefaultColumnName;
402
403 1
            } elseif (!is_null($choiceNode->attributes->getNamedItem("field"))) {
404 1
                $defaultColumnName = (string)$choiceNode->attributes->getNamedItem("field")->nodeValue;
405
            }
406
407 1
            $choiceMapping = $this->readChoice($choiceNode, $mappingFile, $defaultColumnName);
408
409 1
            if (!is_null($choiceNode->attributes->getNamedItem("field"))) {
410
                /** @var string $fieldName */
411 1
                $fieldName = (string)$choiceNode->attributes->getNamedItem("field")->nodeValue;
412
413 1
                $fieldMappings[$fieldName] = $choiceMapping;
414
415
            } else {
416 1
                $fieldMappings[] = $choiceMapping;
417
            }
418
        }
419
420 2
        foreach ($xpath->query('./rdm:object', $parentNode) as $objectNode) {
421
            /** @var DOMNode $objectNode */
422
423
            /** @var ObjectMapping $objectMapping */
424 1
            $objectMapping = $this->readObject($objectNode, $mappingFile);
425
426 1
            if (!is_null($objectNode->attributes->getNamedItem("field"))) {
427
                /** @var string $fieldName */
428 1
                $fieldName = (string)$objectNode->attributes->getNamedItem("field")->nodeValue;
429
430 1
                $fieldMappings[$fieldName] = $objectMapping;
431
432
            } else {
433 1
                $fieldMappings[] = $objectMapping;
434
            }
435
        }
436
437 2
        if ($readFields) {
438 1
            foreach ($xpath->query('./orm:field', $parentNode) as $fieldNode) {
439
                /** @var DOMNode $fieldNode */
440
441
                /** @var Column $column */
442 1
                $column = $this->readDoctrineField($fieldNode);
443
444 1
                $fieldName = (string)$fieldNode->attributes->getNamedItem('name')->nodeValue;
445
446 1
                $fieldMappings[$fieldName] = new FieldMapping(
447 1
                    $column,
448 1
                    sprintf("in file '%s'", $mappingFile)
449
                );
450
            }
451
        }
452
453 2
        foreach ($xpath->query('./rdm:array', $parentNode) as $arrayNode) {
454
            /** @var DOMNode $arrayNode */
455
456
            /** @var ArrayMapping $arrayMapping */
457 1
            $arrayMapping = $this->readArray($arrayNode, $mappingFile);
458
459 1
            if (!is_null($arrayNode->attributes->getNamedItem("field"))) {
460
                /** @var string $fieldName */
461 1
                $fieldName = (string)$arrayNode->attributes->getNamedItem("field")->nodeValue;
462
463 1
                $fieldMappings[$fieldName] = $arrayMapping;
464
465
            } else {
466 1
                $fieldMappings[] = $arrayMapping;
467
            }
468
        }
469
470 2
        foreach ($xpath->query('./rdm:list', $parentNode) as $listNode) {
471
            /** @var DOMNode $listNode */
472
473
            /** @var string $defaultColumnName */
474 1
            $defaultColumnName = "";
475
476 1
            if (!is_null($choiceDefaultColumnName)) {
477
                $defaultColumnName = $choiceDefaultColumnName;
478
479 1
            } elseif (!is_null($listNode->attributes->getNamedItem("field"))) {
480 1
                $defaultColumnName = (string)$listNode->attributes->getNamedItem("field")->nodeValue;
481
            }
482
483
            /** @var ListMapping $listMapping */
484 1
            $listMapping = $this->readList($listNode, $mappingFile, $defaultColumnName);
485
486 1
            if (!is_null($listNode->attributes->getNamedItem("field"))) {
487
                /** @var string $fieldName */
488 1
                $fieldName = (string)$listNode->attributes->getNamedItem("field")->nodeValue;
489
490 1
                $fieldMappings[$fieldName] = $listMapping;
491
492
            } else {
493 1
                $fieldMappings[] = $listMapping;
494
            }
495
        }
496
497 2
        foreach ($xpath->query('./rdm:null', $parentNode) as $nullNode) {
498
            /** @var DOMNode $nullNode */
499
500 1
            if (!is_null($nullNode->attributes->getNamedItem("field"))) {
501
                /** @var string $fieldName */
502
                $fieldName = (string)$nullNode->attributes->getNamedItem("field")->nodeValue;
503
504
                $fieldMappings[$fieldName] = new NullMapping("in file '{$mappingFile}'");
505
506
            } else {
507 1
                $fieldMappings[] = new NullMapping("in file '{$mappingFile}'");
508
            }
509
        }
510
511 2
        foreach ($xpath->query('./rdm:nullable', $parentNode) as $nullableNode) {
512
            /** @var DOMNode $nullableNode */
513
514
            /** @var NullableMapping $nullableMapping */
515 1
            $nullableMapping = $this->readNullable($nullableNode, $mappingFile);
516
517 1
            if (!is_null($nullableNode->attributes->getNamedItem("field"))) {
518
                /** @var string $fieldName */
519 1
                $fieldName = (string)$nullableNode->attributes->getNamedItem("field")->nodeValue;
520
521 1
                $fieldMappings[$fieldName] = $nullableMapping;
522
523
            } else {
524 1
                $fieldMappings[] = $nullableMapping;
525
            }
526
        }
527
528 2
        foreach ($xpath->query('./rdm:import', $parentNode) as $importNode) {
529
            /** @var DOMNode $importNode */
530
531
            /** @var string $path */
532 2
            $path = (string)$importNode->attributes->getNamedItem("path")->nodeValue;
533
534
            /** @var string $forcedFieldName */
535 2
            $forcedFieldName = null;
536
537 2
            if (!is_null($importNode->attributes->getNamedItem("field"))) {
538 1
                $forcedFieldName = (string)$importNode->attributes->getNamedItem("field")->nodeValue;
539
            }
540
541
            /** @var string $columnPrefix */
542 2
            $columnPrefix = "";
543
544 2
            if (!is_null($importNode->attributes->getNamedItem("column-prefix"))) {
545
                $columnPrefix = (string)$importNode->attributes->getNamedItem("column-prefix")->nodeValue;
546
            }
547
548 2
            foreach ($this->readFieldMappingsFromFile($path, $mappingFile) as $fieldName => $fieldMapping) {
549
                /** @var MappingInterface $fieldMapping */
550
551 1
                $fieldMappingProxy = new MappingProxy(
0 ignored issues
show
Unused Code introduced by
$fieldMappingProxy is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
552 1
                    $fieldMapping,
553 1
                    $columnPrefix
554
                );
555
556 1
                if (!empty($forcedFieldName)) {
557 1
                    $fieldMappings[$forcedFieldName] = $fieldMapping;
558
                } else {
559
560 1
                    $fieldMappings[$fieldName] = $fieldMapping;
561
                }
562
            }
563
        }
564
565 2
        return $fieldMappings;
566
    }
567
568 1
    private function readService(DOMNode $serviceNode, string $mappingFile): ServiceMapping
569
    {
570
        /** @var bool $lax */
571 1
        $lax = false;
572
573 1
        if ($serviceNode->attributes->getNamedItem("lax") instanceof DOMNode) {
574 1
            $lax = strtolower($serviceNode->attributes->getNamedItem("lax")->nodeValue) === 'true';
575
        }
576
577
        /** @var string $serviceId */
578 1
        $serviceId = (string)$serviceNode->attributes->getNamedItem("id")->nodeValue;
579
580 1
        return new ServiceMapping(
581 1
            $this->kernel->getContainer(),
0 ignored issues
show
Bug introduced by
It seems like $this->kernel->getContainer() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
582 1
            $serviceId,
583 1
            $lax,
584 1
            sprintf(
585 1
                "in file '%s'",
586 1
                $mappingFile
587
            )
588
        );
589
    }
590
591 1
    private function readArray(DOMNode $arrayNode, string $mappingFile): ArrayMapping
592
    {
593
        /** @var array<MappingInterface> $entryMappings */
594 1
        $entryMappings = $this->readFieldMappings($arrayNode, $mappingFile);
595
596
        /** @var DOMXPath $xpath */
597 1
        $xpath = $this->createXPath($arrayNode);
598
599 1
        foreach ($xpath->query('./rdm:entry', $arrayNode) as $entryNode) {
600
            /** @var DOMNode $entryNode */
601
602
            /** @var string|null $key */
603 1
            $key = null;
604
605 1
            if ($entryNode->attributes->getNamedItem("key") instanceof DOMNode) {
606 1
                $key = (string)$entryNode->attributes->getNamedItem("key")->nodeValue;
607
            }
608
609 1
            foreach ($this->readFieldMappings($entryNode, $mappingFile) as $entryMapping) {
610
                /** @var MappingInterface $entryMapping */
611
612 1
                if (is_null($key)) {
613
                    $entryMappings[] = $entryMapping;
614
615
                } else {
616 1
                    $entryMappings[$key] = $entryMapping;
617
                }
618
619 1
                break;
620
            }
621
        }
622
623 1
        return new ArrayMapping($entryMappings, sprintf(
624 1
            "in file '%s'",
625 1
            $mappingFile
626
        ));
627
    }
628
629 1
    private function readList(
630
        DOMNode $listNode,
631
        string $mappingFile,
632
        string $columnName
633
    ): ListMapping {
634 1
        if (!is_null($listNode->attributes->getNamedItem("column"))) {
635 1
            $columnName = (string)$listNode->attributes->getNamedItem("column")->nodeValue;
636
        }
637
638
        /** @var array<MappingInterface> $entryMappings */
639 1
        $entryMappings = $this->readFieldMappings($listNode, $mappingFile);
640
641
        /** @var array<string, mixed> $columnOptions */
642 1
        $columnOptions = array();
643
644 1
        if (!is_null($listNode->attributes->getNamedItem("column-length"))) {
645
            $columnOptions['length'] = (int)(string)$listNode->attributes->getNamedItem("column-length")->nodeValue;
646
        }
647
648 1
        $column = new Column(
649 1
            $columnName,
650 1
            Type::getType("string"),
651 1
            $columnOptions
652
        );
653
654 1
        return new ListMapping($column, array_values($entryMappings)[0], sprintf(
655 1
            "in file '%s'",
656 1
            $mappingFile
657
        ));
658
    }
659
660 1
    private function readNullable(
661
        DOMNode $nullableNode,
662
        string $mappingFile
663
    ): NullableMapping {
664
        /** @var array<MappingInterface> $innerMappings */
665 1
        $innerMappings = $this->readFieldMappings($nullableNode, $mappingFile);
666
667 1
        if (count($innerMappings) !== 1) {
668
            throw new InvalidMappingException(sprintf(
669
                "A nullable mapping can only contain one inner mapping in '%s'!",
670
                $mappingFile
671
            ));
672
        }
673
674
        /** @var MappingInterface $innerMapping */
675 1
        $innerMapping = array_values($innerMappings)[0];
676
677
        /** @var Column|null $column */
678 1
        $column = null;
679
680 1
        if (!is_null($nullableNode->attributes->getNamedItem("column"))) {
681
            /** @var string $columnName */
682 1
            $columnName = (string)$nullableNode->attributes->getNamedItem("column")->nodeValue;
683
684 1
            $column = new Column(
685 1
                $columnName,
686 1
                Type::getType("boolean"),
687
                [
688 1
                    'notnull' => false
689
                ]
690
            );
691
        }
692
693 1
        return new NullableMapping($innerMapping, $column, sprintf(
694 1
            "in file '%s'",
695 1
            $mappingFile
696
        ));
697
    }
698
699 1
    private function readDoctrineField(DOMNode $fieldNode): Column
700
    {
701
        /** @var array<string> $attributes */
702 1
        $attributes = array();
703
704
        /** @var array<string> $keyMap */
705
        $keyMap = array(
706 1
            'column'            => 'name',
707
            'type'              => 'type',
708
            'nullable'          => 'notnull',
709
            'length'            => 'length',
710
            'precision'         => 'precision',
711
            'scale'             => 'scale',
712
            'column-definition' => 'columnDefinition',
713
        );
714
715
        /** @var string $columnName */
716 1
        $columnName = null;
717
718
        /** @var Type $type */
719 1
        $type = Type::getType('string');
720
721 1
        foreach ($fieldNode->attributes as $key => $attribute) {
722
            /** @var DOMAttr $attribute */
723
724 1
            $attributeValue = (string)$attribute->nodeValue;
725
726 1
            if ($key === 'column') {
727
                $columnName = $attributeValue;
728
729 1
            } elseif ($key === 'name') {
730 1
                if (empty($columnName)) {
731 1
                    $columnName = $attributeValue;
732
                }
733
734 1
            } elseif ($key === 'type') {
735 1
                $type = Type::getType($attributeValue);
736
737 1
            } elseif (isset($keyMap[$key])) {
738 1
                if ($key === 'nullable') {
739
                    # target is 'notnull', so falue is reversed
740 1
                    $attributeValue = ($attributeValue === 'false');
741
                }
742
743 1
                $attributes[$keyMap[$key]] = $attributeValue;
744
            }
745
        }
746
747 1
        $column = new Column(
748 1
            $columnName,
749 1
            $type,
750 1
            $attributes
751
        );
752
753 1
        return $column;
754
    }
755
756
}
757