Passed
Push — php-7.1 ( 280be0...7ba4a5 )
by SignpostMarv
02:07
created

SchemaReaderLoadAbstraction   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 460
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 460
ccs 225
cts 225
cp 1
rs 8.3396
c 1
b 0
f 0
wmc 44

22 Methods

Rating   Name   Duplication   Size   Complexity  
A loadExtensionChildNodes() 0 11 3
B loadComplexTypeBeforeCallbackCallback() 0 21 5
B loadUnion() 0 25 3
B loadSimpleType() 0 35 2
A loadRestriction() 0 3 1
A loadAttributeOrElementDef() 0 17 2
A loadComplexTypeFromChildNode() 0 52 2
A loadSequenceChildNodeLoadSequence() 0 6 1
B loadExtensionChildNode() 0 38 1
A loadGroup() 0 3 1
A loadExtension() 0 16 2
A loadSequence() 0 14 3
A loadElementDef() 0 5 1
A loadAttributeGroup() 0 5 1
B loadComplexType() 0 25 1
A addGroupAsElement() 0 18 1
A loadSequenceChildNodeLoadGroup() 0 10 1
A loadList() 0 18 2
A loadAttributeDef() 0 5 1
B loadSequenceChildNodeLoadElement() 0 26 4
B loadSequenceNormaliseMax() 0 12 5
B loadSequenceChildNode() 0 38 1

How to fix   Complexity   

Complex Class

Complex classes like SchemaReaderLoadAbstraction 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 SchemaReaderLoadAbstraction, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace GoetasWebservices\XML\XSDReader;
3
4
use Closure;
5
use DOMDocument;
6
use DOMElement;
7
use DOMNode;
8
use DOMNodeList;
9
use GoetasWebservices\XML\XSDReader\Exception\IOException;
10
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
11
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
12
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
13
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
14
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
15
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
16
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
17
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
18
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
19
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
20
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
21
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
22
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
23
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
24
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base;
25
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
26
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
27
use GoetasWebservices\XML\XSDReader\Schema\Item;
28
use GoetasWebservices\XML\XSDReader\Schema\Schema;
29
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
30
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
31
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
32
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
33
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
34
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
35
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
36
use RuntimeException;
37
38
abstract class SchemaReaderLoadAbstraction extends SchemaReaderFillAbstraction
39
{
40 45
    protected function loadAttributeGroup(
41
        Schema $schema,
42
        DOMElement $node
43
    ) : Closure {
44 45
        return AttributeGroup::loadAttributeGroup($this, $schema, $node);
45
    }
46
47 45
    protected function loadAttributeOrElementDef(
48
        Schema $schema,
49
        DOMElement $node,
50
        bool $attributeDef
51
    ) : Closure {
52 45
        $name = $node->getAttribute('name');
53 45
        if ($attributeDef) {
54 45
            $attribute = new AttributeDef($schema, $name);
55 45
            $schema->addAttribute($attribute);
56
        } else {
57 45
            $attribute = new ElementDef($schema, $name);
58 45
            $schema->addElement($attribute);
59
        }
60
61
62 45
        return function () use ($attribute, $node) : void {
63 45
            $this->fillItem($attribute, $node);
64 45
        };
65
    }
66
67 45
    protected function loadAttributeDef(
68
        Schema $schema,
69
        DOMElement $node
70
    ) : Closure {
71 45
        return $this->loadAttributeOrElementDef($schema, $node, true);
72
    }
73
74 45
    protected static function loadSequenceNormaliseMax(
75
        DOMElement $node,
76
        ? int $max
77
    ) : ? int {
78
        return
79
        (
80 45
            (is_int($max) && (bool) $max) ||
81 45
            $node->getAttribute("maxOccurs") == "unbounded" ||
82 45
            $node->getAttribute("maxOccurs") > 1
83
        )
84 45
            ? 2
85 45
            : null;
86
    }
87
88 45
    protected function loadSequence(
89
        ElementContainer $elementContainer,
90
        DOMElement $node,
91
        int $max = null
92
    ) : void {
93 45
        $max = static::loadSequenceNormaliseMax($node, $max);
94
95 45
        foreach ($node->childNodes as $childNode) {
96 45
            if ($childNode instanceof DOMElement) {
97 45
                $this->loadSequenceChildNode(
98 45
                    $elementContainer,
99 45
                    $node,
100 45
                    $childNode,
101 45
                    $max
102
                );
103
            }
104
        }
105 45
    }
106
107 45
    protected function loadSequenceChildNode(
108
        ElementContainer $elementContainer,
109
        DOMElement $node,
110
        DOMElement $childNode,
111
        ? int $max
112
    ) : void {
113
        $commonMethods = [
114
            [
115 45
                ['sequence', 'choice', 'all'],
116 45
                [$this, 'loadSequenceChildNodeLoadSequence'],
117
                [
118 45
                    $elementContainer,
119 45
                    $childNode,
120 45
                    $max,
121
                ],
122
            ],
123
        ];
124
        $methods = [
125
            'element' => [
126 45
                [$this, 'loadSequenceChildNodeLoadElement'],
127
                [
128 45
                    $elementContainer,
129 45
                    $node,
130 45
                    $childNode,
131 45
                    $max
132
                ]
133
            ],
134
            'group' => [
135 45
                [$this, 'loadSequenceChildNodeLoadGroup'],
136
                [
137 45
                    $elementContainer,
138 45
                    $node,
139 45
                    $childNode
140
                ]
141
            ],
142
        ];
143
144 45
        $this->maybeCallCallableWithArgs($childNode, $commonMethods, $methods);
145 45
    }
146
147 45
    protected function loadSequenceChildNodeLoadSequence(
148
        ElementContainer $elementContainer,
149
        DOMElement $childNode,
150
        ? int $max
151
    ) : void {
152 45
        $this->loadSequence($elementContainer, $childNode, $max);
153 45
    }
154
155 45
    protected function loadSequenceChildNodeLoadElement(
156
        ElementContainer $elementContainer,
157
        DOMElement $node,
158
        DOMElement $childNode,
159
        ? int $max
160
    ) : void {
161 45
        if ($childNode->hasAttribute("ref")) {
162
            /**
163
            * @var ElementDef $referencedElement
164
            */
165 45
            $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
166 45
            $element = ElementRef::loadElementRef(
167 45
                $referencedElement,
168 45
                $childNode
169
            );
170
        } else {
171 45
            $element = Element::loadElement(
172 45
                $this,
173 45
                $elementContainer->getSchema(),
174 45
                $childNode
175
            );
176
        }
177 45
        if (is_int($max) && (bool) $max) {
178 45
            $element->setMax($max);
179
        }
180 45
        $elementContainer->addElement($element);
181 45
    }
182
183 45
    protected function loadSequenceChildNodeLoadGroup(
184
        ElementContainer $elementContainer,
185
        DOMElement $node,
186
        DOMElement $childNode
187
    ) : void {
188 45
        $this->addGroupAsElement(
189 45
            $elementContainer->getSchema(),
190 45
            $node,
191 45
            $childNode,
192 45
            $elementContainer
193
        );
194 45
    }
195
196 45
    protected function addGroupAsElement(
197
        Schema $schema,
198
        DOMElement $node,
199
        DOMElement $childNode,
200
        ElementContainer $elementContainer
201
    ) : void {
202
        /**
203
        * @var Group $referencedGroup
204
        */
205 45
        $referencedGroup = $this->findSomething(
206 45
            'findGroup',
207 45
            $schema,
208 45
            $node,
209 45
            $childNode->getAttribute("ref")
210
        );
211
212 45
        $group = GroupRef::loadGroupRef($referencedGroup, $childNode);
213 45
        $elementContainer->addElement($group);
214 45
    }
215
216 45
    protected function loadGroup(Schema $schema, DOMElement $node) : Closure
217
    {
218 45
        return Group::loadGroup($this, $schema, $node);
219
    }
220
221 45
    protected function loadComplexTypeBeforeCallbackCallback(
222
        Schema $schema,
223
        DOMElement $node
224
    ) : BaseComplexType {
225 45
        $isSimple = false;
226
227 45
        foreach ($node->childNodes as $childNode) {
228 45
            if ($childNode->localName === "simpleContent") {
229 2
                $isSimple = true;
230 2
                break;
231
            }
232
        }
233
234 45
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute("name")) : new ComplexType($schema, $node->getAttribute("name"));
235
236 45
        $type->setDoc(static::getDocumentation($node));
237 45
        if ($node->getAttribute("name")) {
238 45
            $schema->addType($type);
239
        }
240
241 45
        return $type;
242
    }
243
244 45
    protected function loadComplexType(
245
        Schema $schema,
246
        DOMElement $node,
247
        Closure $callback = null
248
    ) : Closure {
249 45
        $type = $this->loadComplexTypeBeforeCallbackCallback($schema, $node);
250
251 45
        return $this->makeCallbackCallback(
252 45
            $type,
253 45
            $node,
254 45
            function (
255
                DOMElement $node,
256
                DOMElement $childNode
257
            ) use(
258 45
                $schema,
259 45
                $type
260
            ) : void {
261 45
                $this->loadComplexTypeFromChildNode(
262 45
                    $type,
263 45
                    $node,
264 45
                    $childNode,
265 45
                    $schema
266
                );
267 45
            },
268 45
            $callback
269
        );
270
    }
271
272 45
    protected function loadComplexTypeFromChildNode(
273
        BaseComplexType $type,
274
        DOMElement $node,
275
        DOMElement $childNode,
276
        Schema $schema
277
    ) : void {
278
        $commonMethods = [
279
            [
280 45
                ['sequence', 'choice', 'all'],
281 45
                [$this, 'maybeLoadSequenceFromElementContainer'],
282
                [
283 45
                    $type,
284 45
                    $childNode,
285
                ],
286
            ],
287
        ];
288
        $methods = [
289 45
            'attribute' => [
290 45
                [$type, 'addAttributeFromAttributeOrRef'],
291
                [
292 45
                    $this,
293 45
                    $childNode,
294 45
                    $schema,
295 45
                    $node
296
                ]
297
            ],
298
            'attributeGroup' => [
299
                (AttributeGroup::class . '::findSomethingLikeThis'),
300
                [
301 45
                    $this,
302 45
                    $schema,
303 45
                    $node,
304 45
                    $childNode,
305 45
                    $type
306
                ]
307
            ],
308
        ];
309
        if (
310 45
            $type instanceof ComplexType
311
        ) {
312 45
            $methods['group'] = [
313 45
                [$this, 'addGroupAsElement'],
314
                [
315 45
                    $schema,
316 45
                    $node,
317 45
                    $childNode,
318 45
                    $type
319
                ]
320
            ];
321
        }
322
323 45
        $this->maybeCallCallableWithArgs($childNode, $commonMethods, $methods);
324 45
    }
325
326 45
    protected function loadSimpleType(
327
        Schema $schema,
328
        DOMElement $node,
329
        Closure $callback = null
330
    ) : Closure {
331 45
        $type = new SimpleType($schema, $node->getAttribute("name"));
332 45
        $type->setDoc(static::getDocumentation($node));
333 45
        if ($node->getAttribute("name")) {
334 45
            $schema->addType($type);
335
        }
336
337 45
        static $methods = [
338
            'union' => 'loadUnion',
339
            'list' => 'loadList',
340
        ];
341
342 45
        return $this->makeCallbackCallback(
343 45
            $type,
344 45
            $node,
345 45
            function (
346
                DOMElement $node,
347
                DOMElement $childNode
348
            ) use (
349 45
                $methods,
350 45
                $type
351
            ) : void {
352 45
                $this->maybeCallMethod(
353 45
                    $methods,
354 45
                    $childNode->localName,
355 45
                    $childNode,
356 45
                    $type,
357 45
                    $childNode
358
                );
359 45
            },
360 45
            $callback
361
        );
362
    }
363
364 45
    protected function loadList(SimpleType $type, DOMElement $node) : void
365
    {
366 45
        if ($node->hasAttribute("itemType")) {
367
            /**
368
            * @var SimpleType $listType
369
            */
370 45
            $listType = $this->findSomeType($type, $node, 'itemType');
371 45
            $type->setList($listType);
372
        } else {
373 45
            $addCallback = function (SimpleType $list) use ($type) : void {
374 45
                $type->setList($list);
375 45
            };
376
377 45
            Type::loadTypeWithCallbackOnChildNodes(
378 45
                $this,
379 45
                $type->getSchema(),
380 45
                $node,
381 45
                $addCallback
382
            );
383
        }
384 45
    }
385
386 45
    protected function loadUnion(SimpleType $type, DOMElement $node) : void
387
    {
388 45
        if ($node->hasAttribute("memberTypes")) {
389 45
            $types = preg_split('/\s+/', $node->getAttribute("memberTypes"));
390 45
            foreach ($types as $typeName) {
391
                /**
392
                * @var SimpleType $unionType
393
                */
394 45
                $unionType = $this->findSomeTypeFromAttribute(
395 45
                    $type,
396 45
                    $node,
397 45
                    $typeName
398
                );
399 45
                $type->addUnion($unionType);
400
            }
401
        }
402 45
        $addCallback = function (SimpleType $unType) use ($type) : void {
403 45
            $type->addUnion($unType);
404 45
        };
405
406 45
        Type::loadTypeWithCallbackOnChildNodes(
407 45
            $this,
408 45
            $type->getSchema(),
409 45
            $node,
410 45
            $addCallback
411
        );
412 45
    }
413
414 45
    protected function loadExtensionChildNode(
415
        BaseComplexType $type,
416
        DOMElement $node,
417
        DOMElement $childNode
418
    ) : void {
419
        $commonMethods = [
420
            [
421 45
                ['sequence', 'choice', 'all'],
422 45
                [$this, 'maybeLoadSequenceFromElementContainer'],
423
                [
424 45
                    $type,
425 45
                    $childNode,
426
                ],
427
            ],
428
        ];
429
        $methods = [
430 45
            'attribute' => [
431 45
                [$type, 'addAttributeFromAttributeOrRef'],
432
                [
433 45
                    $this,
434 45
                    $childNode,
435 45
                    $type->getSchema(),
436 45
                    $node
437
                ]
438
            ],
439
            'attributeGroup' => [
440
                (AttributeGroup::class . '::findSomethingLikeThis'),
441
                [
442 45
                    $this,
443 45
                    $type->getSchema(),
444 45
                    $node,
445 45
                    $childNode,
446 45
                    $type
447
                ]
448
            ],
449
        ];
450
451 45
        $this->maybeCallCallableWithArgs($childNode, $commonMethods, $methods);
452 45
    }
453
454 45
    protected function loadExtension(
455
        BaseComplexType $type,
456
        DOMElement $node
457
    ) : void {
458 45
        $extension = new Extension();
459 45
        $type->setExtension($extension);
460
461 45
        if ($node->hasAttribute("base")) {
462 45
            $this->findAndSetSomeBase(
463 45
                $type,
464 45
                $extension,
465 45
                $node
466
            );
467
        }
468
469 45
        $this->loadExtensionChildNodes($type, $node->childNodes, $node);
470 45
    }
471
472 45
    protected function loadExtensionChildNodes(
473
        BaseComplexType $type,
474
        DOMNodeList $childNodes,
475
        DOMElement $node
476
    ) : void {
477 45
        foreach ($childNodes as $childNode) {
478 45
            if ($childNode instanceof DOMElement) {
479 45
                $this->loadExtensionChildNode(
480 45
                    $type,
481 45
                    $node,
482 45
                    $childNode
483
                );
484
            }
485
        }
486 45
    }
487
488 45
    protected function loadRestriction(Type $type, DOMElement $node) : void
489
    {
490 45
        Restriction::loadRestriction($this, $type, $node);
491 45
    }
492
493 45
    protected function loadElementDef(
494
        Schema $schema,
495
        DOMElement $node
496
    ) : Closure {
497 45
        return $this->loadAttributeOrElementDef($schema, $node, false);
498
    }
499
}
500