Passed
Push — static-analysis ( d8a1cf...2cdeb5 )
by SignpostMarv
07:38 queued 04:26
created

SchemaReader   F

Complexity

Total Complexity 161

Size/Duplication

Total Lines 1428
Duplicated Lines 4.83 %

Test Coverage

Coverage 96.4%

Importance

Changes 0
Metric Value
wmc 161
dl 69
loc 1428
ccs 697
cts 723
cp 0.964
rs 0.5217
c 0
b 0
f 0

53 Methods

Rating   Name   Duplication   Size   Complexity  
A maybeSetMin() 0 7 2
A loadElementDef() 0 3 1
A readFile() 0 5 1
A addAttributeFromAttributeOrRef() 0 13 1
A addGroupAsElement() 0 18 1
B getGlobalSchema() 0 46 5
C loadGroup() 0 33 7
A loadAttributeDef() 0 3 1
A addKnownSchemaLocation() 0 3 1
B loadElement() 0 27 4
B loadUnion() 0 29 3
A __construct() 0 6 2
A getDocumentation() 0 3 1
A findSomethingLikeAttributeGroup() 0 11 1
B loadSequenceChildNodeLoadElement() 0 37 5
A loadImport() 0 21 3
A loadTypeWithCallback() 0 21 4
C loadExtensionChildNodes() 33 39 7
B loadComplexType() 0 54 6
C fillTypeNode() 0 22 8
A loadImportFresh() 0 14 2
A findSomeType() 0 9 1
B loadSimpleType() 0 27 5
A loadRestriction() 0 59 3
A loadAttribute() 0 19 4
D loadComplexTypeFromChildNode() 0 45 9
B loadSequenceChildNode() 32 32 6
A readNode() 0 13 3
A loadImportFreshKeys() 0 20 2
A getNamespaceSpecificFileIndex() 0 3 1
A setLoadedFile() 0 5 1
A loadImportFreshCallbacks() 0 22 2
A loadGroupRef() 0 9 1
A findAndSetSomeBase() 0 10 1
B fillItem() 0 40 4
A maybeSetMax() 0 9 3
A getAttributeFromAttributeOrRef() 0 18 2
B loadSequence() 0 25 5
A splitParts() 0 14 3
A loadList() 0 22 2
A findSomeTypeFromAttribute() 0 16 1
A readString() 0 9 2
A findSomething() 0 18 3
A fillItemNonLocalType() 0 19 2
B loadAttributeGroup() 0 35 3
A setSchemaThingsFromNode() 0 15 3
A loadExtension() 0 13 2
A againstDOMNodeList() 0 15 3
A loadAttributeOrElementDef() 0 16 2
A loadImportFreshCallbacksNewSchema() 0 19 3
C schemaNode() 0 48 10
A getDOM() 0 8 2
A getGlobalSchemaInfo() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
3
namespace GoetasWebservices\XML\XSDReader;
4
5
use Closure;
6
use DOMDocument;
7
use DOMElement;
8
use DOMNode;
9
use GoetasWebservices\XML\XSDReader\Documentation\DocumentationReader;
10
use GoetasWebservices\XML\XSDReader\Documentation\StandardDocumentationReader;
11
use GoetasWebservices\XML\XSDReader\Exception\IOException;
12
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
13
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
14
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer;
15
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
16
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
17
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
18
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
19
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
20
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
21
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
22
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
23
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
24
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
25
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
26
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
27
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base;
28
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
29
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
30
use GoetasWebservices\XML\XSDReader\Schema\Item;
31
use GoetasWebservices\XML\XSDReader\Schema\Schema;
32
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
33
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
34
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
35
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
36
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
37
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
38
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
39
40
class SchemaReader
41
{
42
    const XSD_NS = 'http://www.w3.org/2001/XMLSchema';
43
44
    const XML_NS = 'http://www.w3.org/XML/1998/namespace';
45
46
    /**
47
     * @var DocumentationReader
48
     */
49
    private $documentationReader;
50
51
    /**
52
     * @var Schema[]
53
     */
54
    private $loadedFiles = array();
55
56
    /**
57
     * @var string[]
58
     */
59
    protected $knownLocationSchemas = [
60
        'http://www.w3.org/2001/xml.xsd' => (
61
            __DIR__.'/Resources/xml.xsd'
62
        ),
63
        'http://www.w3.org/2001/XMLSchema.xsd' => (
64
            __DIR__.'/Resources/XMLSchema.xsd'
65
        ),
66
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' => (
67
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-secext-1.0.xsd'
68
        ),
69
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' => (
70
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-utility-1.0.xsd'
71
        ),
72
        'https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
73
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
74
        ),
75
        'http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
76
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
77
        ),
78
    ];
79
80
    /**
81
     * @var string[]
82
     */
83
    protected static $globalSchemaInfo = array(
84
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
85
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd',
86
    );
87
88 56
    public function __construct(DocumentationReader $documentationReader = null)
89
    {
90 56
        if (null === $documentationReader) {
91 56
            $documentationReader = new StandardDocumentationReader();
92 56
        }
93 56
        $this->documentationReader = $documentationReader;
94 56
    }
95
96
    /**
97
     * @param string $remote
98
     * @param string $local
99
     */
100
    public function addKnownSchemaLocation($remote, $local)
101
    {
102
        $this->knownLocationSchemas[$remote] = $local;
103
    }
104
105
    /**
106
     * @return \Closure
107
     */
108 47
    private function loadAttributeGroup(
109
        Schema $schema,
110
        DOMElement $node
111
    ) {
112 47
        $attGroup = new AttributeGroup($schema, $node->getAttribute('name'));
113 47
        $attGroup->setDoc($this->getDocumentation($node));
114 47
        $schema->addAttributeGroup($attGroup);
115
116
        return function () use ($schema, $node, $attGroup) {
117 47
            SchemaReader::againstDOMNodeList(
118 47
                $node,
119
                function (
120
                    DOMElement $node,
121
                    DOMElement $childNode
122
                ) use (
123 47
                    $schema,
124 47
                    $attGroup
125
                ) {
126 47
                    switch ($childNode->localName) {
127 47
                        case 'attribute':
128 47
                            $attribute = $this->getAttributeFromAttributeOrRef(
129 47
                                $childNode,
130 47
                                $schema,
131
                                $node
132 47
                            );
133 47
                            $attGroup->addAttribute($attribute);
134 47
                            break;
135 47
                        case 'attributeGroup':
136 1
                            $this->findSomethingLikeAttributeGroup(
137 1
                                $schema,
138 1
                                $node,
139 1
                                $childNode,
140
                                $attGroup
141 1
                            );
142 1
                            break;
143 47
                    }
144 47
                }
145 47
            );
146 47
        };
147
    }
148
149
    /**
150
     * @return AttributeItem
151
     */
152 47
    private function getAttributeFromAttributeOrRef(
153
        DOMElement $childNode,
154
        Schema $schema,
155
        DOMElement $node
156
    ) {
157 47
        if ($childNode->hasAttribute('ref')) {
158
            /**
159
             * @var AttributeItem
160
             */
161 47
            $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute('ref'));
162 47
        } else {
163
            /**
164
             * @var Attribute
165
             */
166 47
            $attribute = $this->loadAttribute($schema, $childNode);
167
        }
168
169 47
        return $attribute;
170
    }
171
172
    /**
173
     * @return Attribute
174
     */
175 47
    private function loadAttribute(
176
        Schema $schema,
177
        DOMElement $node
178
    ) {
179 47
        $attribute = new Attribute($schema, $node->getAttribute('name'));
180 47
        $attribute->setDoc($this->getDocumentation($node));
181 47
        $this->fillItem($attribute, $node);
182
183 47
        if ($node->hasAttribute('nillable')) {
184 1
            $attribute->setNil($node->getAttribute('nillable') == 'true');
185 1
        }
186 47
        if ($node->hasAttribute('form')) {
187 1
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
188 1
        }
189 47
        if ($node->hasAttribute('use')) {
190 47
            $attribute->setUse($node->getAttribute('use'));
191 47
        }
192
193 47
        return $attribute;
194
    }
195
196
    /**
197
     * @param bool $attributeDef
198
     *
199
     * @return Closure
200
     */
201 47
    private function loadAttributeOrElementDef(
202
        Schema $schema,
203
        DOMElement $node,
204
        $attributeDef
205
    ) {
206 47
        $name = $node->getAttribute('name');
207 47
        if ($attributeDef) {
208 47
            $attribute = new AttributeDef($schema, $name);
209 47
            $schema->addAttribute($attribute);
210 47
        } else {
211 47
            $attribute = new ElementDef($schema, $name);
212 47
            $schema->addElement($attribute);
213
        }
214
215
        return function () use ($attribute, $node) {
216 47
            $this->fillItem($attribute, $node);
217 47
        };
218
    }
219
220
    /**
221
     * @return Closure
222
     */
223 47
    private function loadAttributeDef(Schema $schema, DOMElement $node)
224
    {
225 47
        return $this->loadAttributeOrElementDef($schema, $node, true);
226
    }
227
228
    /**
229
     * @param DOMElement $node
230
     *
231
     * @return string
232
     */
233 47
    private function getDocumentation(DOMElement $node)
234
    {
235 47
        return $this->documentationReader->get($node);
236
    }
237
238
    /**
239
     * @param Schema     $schema
240
     * @param DOMElement $node
241
     * @param Schema     $parent
242
     *
243
     * @return Closure[]
244
     */
245 47
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null)
246
    {
247 47
        $this->setSchemaThingsFromNode($schema, $node, $parent);
248 47
        $functions = array();
249
250 47
        static::againstDOMNodeList(
251 47
            $node,
252
            function (
253
                DOMElement $node,
254
                DOMElement $childNode
255
            ) use (
256 47
                $schema,
257
                &$functions
258
            ) {
259 47
                $callback = null;
260
261 47
                switch ($childNode->localName) {
262 47
                    case 'attributeGroup':
263 47
                        $callback = $this->loadAttributeGroup($schema, $childNode);
264 47
                        break;
265 47
                    case 'include':
266 47
                    case 'import':
267 47
                        $callback = $this->loadImport($schema, $childNode);
268 47
                        break;
269 47
                    case 'element':
270 47
                        $callback = $this->loadElementDef($schema, $childNode);
271 47
                        break;
272 47
                    case 'attribute':
273 47
                        $callback = $this->loadAttributeDef($schema, $childNode);
274 47
                        break;
275 47
                    case 'group':
276 47
                        $callback = $this->loadGroup($schema, $childNode);
277 47
                        break;
278 47
                    case 'complexType':
279 47
                        $callback = $this->loadComplexType($schema, $childNode);
280 47
                        break;
281 47
                    case 'simpleType':
282 47
                        $callback = $this->loadSimpleType($schema, $childNode);
283 47
                        break;
284 47
                }
285
286 47
                if ($callback instanceof Closure) {
287 47
                    $functions[] = $callback;
288 47
                }
289 47
            }
290 47
        );
291
292 47
        return $functions;
293
    }
294
295
    /**
296
     * @return GroupRef
297
     */
298 47
    private function loadGroupRef(Group $referenced, DOMElement $node)
299
    {
300 47
        $ref = new GroupRef($referenced);
301 47
        $ref->setDoc($this->getDocumentation($node));
302
303 47
        self::maybeSetMax($ref, $node);
304 47
        self::maybeSetMin($ref, $node);
305
306 47
        return $ref;
307
    }
308
309
    /**
310
     * @return InterfaceSetMinMax
311
     */
312 47
    private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node)
313
    {
314
        if (
315 47
            $node->hasAttribute('maxOccurs')
316 47
        ) {
317 47
            $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
318 47
        }
319
320 47
        return $ref;
321
    }
322
323
    /**
324
     * @return InterfaceSetMinMax
325
     */
326 47
    private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node)
327
    {
328 47
        if ($node->hasAttribute('minOccurs')) {
329 47
            $ref->setMin((int) $node->getAttribute('minOccurs'));
330 47
        }
331
332 47
        return $ref;
333
    }
334
335
    /**
336
     * @param int|null $max
337
     */
338 47
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null)
339
    {
340
        $max =
341
        (
342 47
            (is_int($max) && (bool) $max) ||
343 47
            $node->getAttribute('maxOccurs') == 'unbounded' ||
344 47
            $node->getAttribute('maxOccurs') > 1
345 47
        )
346 47
            ? 2
347 47
            : null;
348
349 47
        static::againstDOMNodeList(
350 47
            $node,
351
            function (
352
                DOMElement $node,
353
                DOMElement $childNode
354
            ) use (
355 47
                $elementContainer,
356 47
                $max
357
            ) {
358 47
                $this->loadSequenceChildNode(
359 47
                    $elementContainer,
360 47
                    $node,
361 47
                    $childNode,
362
                    $max
363 47
                );
364 47
            }
365 47
        );
366 47
    }
367
368
    /**
369
     * @param int|null $max
370
     */
371 47 View Code Duplication
    private function loadSequenceChildNode(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
372
        ElementContainer $elementContainer,
373
        DOMElement $node,
374
        DOMElement $childNode,
375
        $max
376
    ) {
377 47
        switch ($childNode->localName) {
378 47
            case 'sequence':
379 47
            case 'choice':
380 47
            case 'all':
381 47
                $this->loadSequence(
382 47
                    $elementContainer,
383 47
                    $childNode,
384
                    $max
385 47
                );
386 47
                break;
387 47
            case 'element':
388 47
                $this->loadSequenceChildNodeLoadElement(
389 47
                    $elementContainer,
390 47
                    $node,
391 47
                    $childNode,
392
                    $max
393 47
                );
394 47
                break;
395 47
            case 'group':
396 47
                $this->addGroupAsElement(
397 47
                    $elementContainer->getSchema(),
398 47
                    $node,
399 47
                    $childNode,
400
                    $elementContainer
401 47
                );
402 47
                break;
403 47
        }
404 47
    }
405
406
    /**
407
     * @param int|null $max
408
     */
409 47
    private function loadSequenceChildNodeLoadElement(
410
        ElementContainer $elementContainer,
411
        DOMElement $node,
412
        DOMElement $childNode,
413
        $max
414
    ) {
415 47
        if ($childNode->hasAttribute('ref')) {
416
            /**
417
             * @var ElementDef $referencedElement
418
             */
419 47
            $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute('ref'));
420 47
            $element = new ElementRef($referencedElement);
421 47
            $element->setDoc($this->getDocumentation($childNode));
422
423 47
            self::maybeSetMax($element, $childNode);
424 47
            self::maybeSetMin($element, $childNode);
425 47
            if ($childNode->hasAttribute('nillable')) {
426
                $element->setNil($childNode->getAttribute('nillable') == 'true');
427
            }
428 47
            if ($childNode->hasAttribute('form')) {
429
                $element->setQualified($childNode->getAttribute('form') == 'qualified');
430
            }
431 47
        } else {
432 47
            $element = $this->loadElement(
433 47
                $elementContainer->getSchema(),
434
                $childNode
435 47
            );
436
        }
437 47
        if ($max > 1) {
438
            /*
439
            * although one might think the typecast is not needed with $max being `? int $max` after passing > 1,
440
            * phpstan@a4f89fa still thinks it's possibly null.
441
            * see https://github.com/phpstan/phpstan/issues/577 for related issue
442
            */
443 47
            $element->setMax((int) $max);
444 47
        }
445 47
        $elementContainer->addElement($element);
446 47
    }
447
448 47
    private function addGroupAsElement(
449
        Schema $schema,
450
        DOMElement $node,
451
        DOMElement $childNode,
452
        ElementContainer $elementContainer
453
    ) {
454
        /**
455
         * @var Group
456
         */
457 47
        $referencedGroup = $this->findSomething(
458 47
            'findGroup',
459 47
            $schema,
460 47
            $node,
461 47
            $childNode->getAttribute('ref')
462 47
        );
463
464 47
        $group = $this->loadGroupRef($referencedGroup, $childNode);
465 47
        $elementContainer->addElement($group);
466 47
    }
467
468
    /**
469
     * @return Closure
470
     */
471 47
    private function loadGroup(Schema $schema, DOMElement $node)
472
    {
473 47
        $group = new Group($schema, $node->getAttribute('name'));
474 47
        $group->setDoc($this->getDocumentation($node));
475
476 47
        if ($node->hasAttribute('maxOccurs')) {
477
            /**
478
             * @var GroupRef
479
             */
480
            $group = self::maybeSetMax(new GroupRef($group), $node);
481
        }
482 47
        if ($node->hasAttribute('minOccurs')) {
483
            /**
484
             * @var GroupRef
485
             */
486
            $group = self::maybeSetMin(
487
                $group instanceof GroupRef ? $group : new GroupRef($group),
488
                $node
489
            );
490
        }
491
492 47
        $schema->addGroup($group);
493
494
        return function () use ($group, $node) {
495 47
            static::againstDOMNodeList(
496 47
                $node,
497
                function (DOMelement $node, DOMElement $childNode) use ($group) {
498 47
                    switch ($childNode->localName) {
499 47
                        case 'sequence':
500 47
                        case 'choice':
501 47
                        case 'all':
502 47
                            $this->loadSequence($group, $childNode);
503 47
                            break;
504 47
                    }
505 47
                }
506 47
            );
507 47
        };
508
    }
509
510
    /**
511
     * @param Closure|null $callback
512
     *
513
     * @return Closure
514
     */
515 47
    private function loadComplexType(Schema $schema, DOMElement $node, $callback = null)
516
    {
517
        /**
518
         * @var bool
519
         */
520 47
        $isSimple = false;
521
522 47
        static::againstDOMNodeList(
523 47
            $node,
524
            function (
525
                DOMElement $node,
526
                DOMElement $childNode
527
            ) use (
528
                &$isSimple
529
            ) {
530 47
                if ($isSimple) {
531 1
                    return;
532
                }
533 47
                if ($childNode->localName === 'simpleContent') {
534 2
                    $isSimple = true;
535 2
                }
536 47
            }
537 47
        );
538
539 47
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name'));
540
541 47
        $type->setDoc($this->getDocumentation($node));
542 47
        if ($node->getAttribute('name')) {
543 47
            $schema->addType($type);
544 47
        }
545
546
        return function () use ($type, $node, $schema, $callback) {
547 47
            $this->fillTypeNode($type, $node, true);
548
549 47
            static::againstDOMNodeList(
550 47
                $node,
551
                function (
552
                    DOMElement $node,
553
                    DOMElement $childNode
554
                ) use (
555 47
                    $schema,
556 47
                    $type
557
                ) {
558 47
                    $this->loadComplexTypeFromChildNode(
559 47
                        $type,
560 47
                        $node,
561 47
                        $childNode,
562
                        $schema
563 47
                    );
564 47
                }
565 47
            );
566
567 47
            if ($callback) {
568 47
                call_user_func($callback, $type);
569 47
            }
570 47
        };
571
    }
572
573 47
    private function loadComplexTypeFromChildNode(
574
        BaseComplexType $type,
575
        DOMElement $node,
576
        DOMElement $childNode,
577
        Schema $schema
578
    ) {
579 47
        switch ($childNode->localName) {
580 47
            case 'sequence':
581 47
            case 'choice':
582 47
            case 'all':
583 47
                if ($type instanceof ElementContainer) {
584 47
                    $this->loadSequence(
585 47
                        $type,
586
                        $childNode
587 47
                    );
588 47
                }
589 47
                break;
590 47
            case 'attribute':
591 47
                $this->addAttributeFromAttributeOrRef(
592 47
                    $type,
593 47
                    $childNode,
594 47
                    $schema,
595
                    $node
596 47
                );
597 47
                break;
598 47
            case 'attributeGroup':
599 2
                $this->findSomethingLikeAttributeGroup(
600 2
                    $schema,
601 2
                    $node,
602 2
                    $childNode,
603
                    $type
604 2
                );
605 2
                break;
606 47
            case 'group':
607
                if (
608
                    $type instanceof ComplexType
609 1
                ) {
610 1
                    $this->addGroupAsElement(
611 1
                        $schema,
612 1
                        $node,
613 1
                        $childNode,
614
                        $type
615 1
                    );
616 1
                }
617 1
                break;
618 47
        }
619 47
    }
620
621
    /**
622
     * @param Closure|null $callback
623
     *
624
     * @return Closure
625
     */
626 47
    private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null)
627
    {
628 47
        $type = new SimpleType($schema, $node->getAttribute('name'));
629 47
        $type->setDoc($this->getDocumentation($node));
630 47
        if ($node->getAttribute('name')) {
631 47
            $schema->addType($type);
632 47
        }
633
634
        return function () use ($type, $node, $callback) {
635 47
            $this->fillTypeNode($type, $node, true);
636
637 47
            static::againstDOMNodeList(
638 47
                $node,
639
                function (DOMElement $node, DOMElement $childNode) use ($type) {
640 47
                    switch ($childNode->localName) {
641 47
                        case 'union':
642 47
                            $this->loadUnion($type, $childNode);
643 47
                            break;
644 47
                        case 'list':
645 47
                            $this->loadList($type, $childNode);
646 47
                            break;
647 47
                    }
648 47
                }
649 47
            );
650
651 47
            if ($callback) {
652 47
                call_user_func($callback, $type);
653 47
            }
654 47
        };
655
    }
656
657 47
    private function loadList(SimpleType $type, DOMElement $node)
658
    {
659 47
        if ($node->hasAttribute('itemType')) {
660
            /**
661
             * @var SimpleType
662
             */
663 47
            $listType = $this->findSomeType($type, $node, 'itemType');
664 47
            $type->setList($listType);
665 47
        } else {
666 47
            self::againstDOMNodeList(
667 47
                $node,
668
                function (
669
                    DOMElement $node,
670
                    DOMElement $childNode
671
                ) use (
672 47
                    $type
673
                ) {
674 47
                    $this->loadTypeWithCallback(
675 47
                        $type->getSchema(),
676 47
                        $childNode,
677
                        function (SimpleType $list) use ($type) {
678 47
                            $type->setList($list);
679 47
                        }
680 47
                    );
681 47
                }
682 47
            );
683
        }
684 47
    }
685
686
    /**
687
     * @param string $attributeName
688
     *
689
     * @return SchemaItem
690
     */
691 47
    private function findSomeType(
692
        SchemaItem $fromThis,
693
        DOMElement $node,
694
        $attributeName
695
    ) {
696 47
        return $this->findSomeTypeFromAttribute(
697 47
            $fromThis,
698 47
            $node,
699 47
            $node->getAttribute($attributeName)
700 47
        );
701
    }
702
703
    /**
704
     * @param string $attributeName
705
     *
706
     * @return SchemaItem
707
     */
708 47
    private function findSomeTypeFromAttribute(
709
        SchemaItem $fromThis,
710
        DOMElement $node,
711
        $attributeName
712
    ) {
713
        /**
714
         * @var SchemaItem
715
         */
716 47
        $out = $this->findSomething(
717 47
            'findType',
718 47
            $fromThis->getSchema(),
719 47
            $node,
720
            $attributeName
721 47
        );
722
723 47
        return $out;
724
    }
725
726 47
    private function loadUnion(SimpleType $type, DOMElement $node)
727
    {
728 47
        if ($node->hasAttribute('memberTypes')) {
729 47
            $types = preg_split('/\s+/', $node->getAttribute('memberTypes'));
730 47
            foreach ($types as $typeName) {
731
                /**
732
                 * @var SimpleType
733
                 */
734 47
                $unionType = $this->findSomeTypeFromAttribute(
735 47
                    $type,
736 47
                    $node,
737
                    $typeName
738 47
                );
739 47
                $type->addUnion($unionType);
740 47
            }
741 47
        }
742 47
        self::againstDOMNodeList(
743 47
            $node,
744
            function (
745
                DOMElement $node,
746
                DOMElement $childNode
747
            ) use (
748 47
                $type
749
            ) {
750 47
                $this->loadTypeWithCallback(
751 47
                    $type->getSchema(),
752 47
                    $childNode,
753
                    function (SimpleType $unType) use ($type) {
754 47
                        $type->addUnion($unType);
755 47
                    }
756 47
                );
757 47
            }
758 47
        );
759 47
    }
760
761
    /**
762
     * @param bool $checkAbstract
763
     */
764 47
    private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = false)
765
    {
766 47
        if ($checkAbstract) {
767 47
            $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1');
768 47
        }
769
770 47
        static::againstDOMNodeList(
771 47
            $node,
772
            function (DOMElement $node, DOMElement $childNode) use ($type) {
773 47
                switch ($childNode->localName) {
774 47
                    case 'restriction':
775 47
                        $this->loadRestriction($type, $childNode);
776 47
                        break;
777 47
                    case 'extension':
778 47
                        if ($type instanceof BaseComplexType) {
779 47
                            $this->loadExtension($type, $childNode);
780 47
                        }
781 47
                        break;
782 47
                    case 'simpleContent':
783 47
                    case 'complexContent':
784 47
                        $this->fillTypeNode($type, $childNode);
785 47
                        break;
786 47
                }
787 47
            }
788 47
        );
789 47
    }
790
791 47
    private function loadExtension(BaseComplexType $type, DOMElement $node)
792
    {
793 47
        $extension = new Extension();
794 47
        $type->setExtension($extension);
795
796 47
        if ($node->hasAttribute('base')) {
797 47
            $this->findAndSetSomeBase(
798 47
                $type,
799 47
                $extension,
800
                $node
801 47
            );
802 47
        }
803 47
        $this->loadExtensionChildNodes($type, $node);
804 47
    }
805
806 47
    private function findAndSetSomeBase(
807
        Type $type,
808
        Base $setBaseOnThis,
809
        DOMElement $node
810
    ) {
811
        /**
812
         * @var Type
813
         */
814 47
        $parent = $this->findSomeType($type, $node, 'base');
815 47
        $setBaseOnThis->setBase($parent);
816 47
    }
817
818 47
    private function loadExtensionChildNodes(
819
        BaseComplexType $type,
820
        DOMElement $node
821
    ) {
822 47
        static::againstDOMNodeList(
823 47
            $node,
824 View Code Duplication
            function (
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
825
                DOMElement $node,
826
                DOMElement $childNode
827
            ) use (
828 47
                $type
829
            ) {
830 47
                switch ($childNode->localName) {
831 47
                    case 'sequence':
832 47
                    case 'choice':
833 47
                    case 'all':
834 47
                        if ($type instanceof ElementContainer) {
835 47
                            $this->loadSequence(
836 47
                                $type,
837
                                $childNode
838 47
                            );
839 47
                        }
840 47
                        break;
841 47
                    case 'attribute':
842 47
                        $this->addAttributeFromAttributeOrRef(
843 47
                            $type,
844 47
                            $childNode,
845 47
                            $type->getSchema(),
846
                            $node
847 47
                        );
848 47
                        break;
849 47
                    case 'attributeGroup':
850 47
                        $this->findSomethingLikeAttributeGroup(
851 47
                            $type->getSchema(),
852 47
                            $node,
853 47
                            $childNode,
854
                            $type
855 47
                        );
856 47
                        break;
857 47
                }
858 47
            }
859 47
        );
860 47
    }
861
862 47
    private function loadRestriction(Type $type, DOMElement $node)
863
    {
864 47
        $restriction = new Restriction();
865 47
        $type->setRestriction($restriction);
866 47
        if ($node->hasAttribute('base')) {
867 47
            $this->findAndSetSomeBase($type, $restriction, $node);
868 47
        } else {
869 47
            self::againstDOMNodeList(
870 47
                $node,
871
                function (
872
                    DOMElement $node,
873
                    DOMElement $childNode
874
                ) use (
875 47
                    $type,
876 47
                    $restriction
877
                ) {
878 47
                    $this->loadTypeWithCallback(
879 47
                        $type->getSchema(),
880 47
                        $childNode,
881
                        function (Type $restType) use ($restriction) {
882 47
                            $restriction->setBase($restType);
883 47
                        }
884 47
                    );
885 47
                }
886 47
            );
887
        }
888 47
        self::againstDOMNodeList(
889 47
            $node,
890
            function (
891
                DOMElement $node,
892
                DOMElement $childNode
893
            ) use (
894 47
                $restriction
895
            ) {
896
                if (
897 47
                    in_array(
898 47
                        $childNode->localName,
899
                        [
900 47
                            'enumeration',
901 47
                            'pattern',
902 47
                            'length',
903 47
                            'minLength',
904 47
                            'maxLength',
905 47
                            'minInclusive',
906 47
                            'maxInclusive',
907 47
                            'minExclusive',
908 47
                            'maxExclusive',
909 47
                            'fractionDigits',
910 47
                            'totalDigits',
911 47
                            'whiteSpace',
912 47
                        ],
913
                        true
914 47
                    )
915 47
                ) {
916 47
                    $restriction->addCheck(
917 47
                        $childNode->localName,
918
                        [
919 47
                            'value' => $childNode->getAttribute('value'),
920 47
                            'doc' => $this->getDocumentation($childNode),
921
                        ]
922 47
                    );
923 47
                }
924 47
            }
925 47
        );
926 47
    }
927
928
    /**
929
     * @param string $typeName
930
     *
931
     * @return mixed[]
932
     */
933 47
    private static function splitParts(DOMElement $node, $typeName)
934
    {
935 47
        $prefix = null;
936 47
        $name = $typeName;
937 47
        if (strpos($typeName, ':') !== false) {
938 47
            list($prefix, $name) = explode(':', $typeName);
939 47
        }
940
941 47
        $namespace = $node->lookupNamespaceUri($prefix ?: '');
942
943
        return array(
944 47
            $name,
945 47
            $namespace,
946 47
            $prefix,
947 47
        );
948
    }
949
950
    /**
951
     * @param string     $finder
952
     * @param Schema     $schema
953
     * @param DOMElement $node
954
     * @param string     $typeName
955
     *
956
     * @throws TypeException
957
     *
958
     * @return ElementItem|Group|AttributeItem|AttributeGroup|Type
959
     */
960 47
    private function findSomething($finder, Schema $schema, DOMElement $node, $typeName)
961
    {
962 47
        list($name, $namespace) = static::splitParts($node, $typeName);
963
964
        /**
965
         * @var string|null
966
         */
967 47
        $namespace = $namespace ?: $schema->getTargetNamespace();
968
969
        try {
970
            /**
971
             * @var ElementItem|Group|AttributeItem|AttributeGroup|Type
972
             */
973 47
            $out = $schema->$finder($name, $namespace);
974
975 47
            return $out;
976
        } catch (TypeNotFoundException $e) {
977
            throw new TypeException(sprintf("Can't find %s named {%s}#%s, at line %d in %s ", strtolower(substr($finder, 4)), $namespace, $name, $node->getLineNo(), $node->ownerDocument->documentURI), 0, $e);
978
        }
979
    }
980
981
    /**
982
     * @return Closure
983
     */
984 47
    private function loadElementDef(Schema $schema, DOMElement $node)
985
    {
986 47
        return $this->loadAttributeOrElementDef($schema, $node, false);
987
    }
988
989 47
    private function fillItem(Item $element, DOMElement $node)
990
    {
991
        /**
992
         * @var bool
993
         */
994 47
        $skip = false;
995 47
        static::againstDOMNodeList(
996 47
            $node,
997
            function (
998
                DOMElement $node,
999
                DOMElement $childNode
1000
            ) use (
1001 47
                $element,
1002
                &$skip
1003
            ) {
1004
                if (
1005 47
                    !$skip &&
1006 47
                    in_array(
1007 47
                        $childNode->localName,
1008
                        [
1009 47
                            'complexType',
1010 47
                            'simpleType',
1011
                        ]
1012 47
                    )
1013 47
                ) {
1014 47
                    $this->loadTypeWithCallback(
1015 47
                        $element->getSchema(),
1016 47
                        $childNode,
1017
                        function (Type $type) use ($element) {
1018 47
                            $element->setType($type);
1019 47
                        }
1020 47
                    );
1021 47
                    $skip = true;
1022 47
                }
1023 47
            }
1024 47
        );
1025 47
        if ($skip) {
1026 47
            return;
1027
        }
1028 47
        $this->fillItemNonLocalType($element, $node);
1029 47
    }
1030
1031 47
    private function fillItemNonLocalType(Item $element, DOMElement $node)
1032
    {
1033 47
        if ($node->getAttribute('type')) {
1034
            /**
1035
             * @var Type
1036
             */
1037 47
            $type = $this->findSomeType($element, $node, 'type');
1038 47
        } else {
1039
            /**
1040
             * @var Type
1041
             */
1042 47
            $type = $this->findSomeTypeFromAttribute(
1043 47
                $element,
1044 47
                $node,
1045 47
                ($node->lookupPrefix(self::XSD_NS).':anyType')
1046 47
            );
1047
        }
1048
1049 47
        $element->setType($type);
1050 47
    }
1051
1052
    /**
1053
     * @return Closure
1054
     */
1055 47
    private function loadImport(
1056
        Schema $schema,
1057
        DOMElement $node
1058
    ) {
1059 47
        $base = urldecode($node->ownerDocument->documentURI);
1060 47
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));
1061
1062 47
        $namespace = $node->getAttribute('namespace');
1063
1064 47
        $keys = $this->loadImportFreshKeys($namespace, $file);
1065
1066 47
        foreach ($keys as $key) {
1067 47
            if (isset($this->loadedFiles[$key])) {
1068 47
                $schema->addSchema($this->loadedFiles[$key]);
1069
1070
                return function () {
1071 47
                };
1072
            }
1073 1
        }
1074
1075 1
        return $this->loadImportFresh($namespace, $schema, $file);
1076
    }
1077
1078
    /**
1079
     * @param string $namespace
1080
     * @param string $file
1081
     *
1082
     * @return string[]
1083
     */
1084 47
    private function loadImportFreshKeys(
1085
        $namespace,
1086
        $file
1087
    ) {
1088 47
        $globalSchemaInfo = $this->getGlobalSchemaInfo();
1089
1090 47
        $keys = [];
1091
1092 47
        if (isset($globalSchemaInfo[$namespace])) {
1093 47
            $keys[] = $globalSchemaInfo[$namespace];
1094 47
        }
1095
1096 47
        $keys[] = $this->getNamespaceSpecificFileIndex(
1097 47
            $file,
1098
            $namespace
1099 47
        );
1100
1101 47
        $keys[] = $file;
1102
1103 47
        return $keys;
1104
    }
1105
1106
    /**
1107
     * @param string $namespace
1108
     * @param string $file
1109
     *
1110
     * @return Schema
1111
     */
1112 1
    private function loadImportFreshCallbacksNewSchema(
1113
        $namespace,
1114
        Schema $schema,
1115
        $file
1116
    ) {
1117
        /**
1118
         * @var Schema $newSchema
1119
         */
1120 1
        $newSchema = $this->setLoadedFile(
1121 1
            $file,
1122 1
            ($namespace ? new Schema() : $schema)
1123 1
        );
1124
1125 1
        if ($namespace) {
1126
            $newSchema->addSchema($this->getGlobalSchema());
1127
            $schema->addSchema($newSchema);
1128
        }
1129
1130 1
        return $newSchema;
1131
    }
1132
1133
    /**
1134
     * @param string $namespace
1135
     * @param string $file
1136
     *
1137
     * @return Closure[]
1138
     */
1139 1
    private function loadImportFreshCallbacks(
1140
        $namespace,
1141
        Schema $schema,
1142
        $file
1143
    ) {
1144
        /**
1145
         * @var string
1146
         */
1147 1
        $file = $file;
1148
1149 1
        return $this->schemaNode(
1150 1
            $this->loadImportFreshCallbacksNewSchema(
1151 1
                $namespace,
1152 1
                $schema,
1153
                $file
1154 1
            ),
1155 1
            $this->getDOM(
1156 1
                isset($this->knownLocationSchemas[$file])
1157 1
                    ? $this->knownLocationSchemas[$file]
1158
                    : $file
1159 1
            )->documentElement,
1160
            $schema
1161 1
        );
1162
    }
1163
1164
    /**
1165
     * @param string $namespace
1166
     * @param string $file
1167
     *
1168
     * @return Closure
1169
     */
1170
    private function loadImportFresh(
1171
        $namespace,
1172
        Schema $schema,
1173
        $file
1174
    ) {
1175 1
        return function () use ($namespace, $schema, $file) {
1176
            foreach (
1177 1
                $this->loadImportFreshCallbacks(
1178 1
                    $namespace,
1179 1
                    $schema,
1180
                    $file
1181 1
                ) as $callback
1182 1
            ) {
1183 1
                $callback();
1184 1
            }
1185 1
        };
1186
    }
1187
1188
    /**
1189
     * @var Schema|null
1190
     */
1191
    protected $globalSchema;
1192
1193
    /**
1194
     * @return string[]
1195
     */
1196 47
    public function getGlobalSchemaInfo()
1197
    {
1198 47
        return self::$globalSchemaInfo;
1199
    }
1200
1201
    /**
1202
     * @return Schema
1203
     */
1204 47
    public function getGlobalSchema()
1205
    {
1206 47
        if (!$this->globalSchema) {
1207 47
            $callbacks = array();
1208 47
            $globalSchemas = array();
1209
            /**
1210
             * @var string $namespace
1211
             */
1212 47
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
1213 47
                $this->setLoadedFile(
1214 47
                    $uri,
1215 47
                    $globalSchemas[$namespace] = $schema = new Schema()
1216 47
                );
1217 47
                if ($namespace === self::XSD_NS) {
1218 47
                    $this->globalSchema = $schema;
1219 47
                }
1220 47
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
1221 47
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
1222 47
            }
1223
1224 47
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType'));
1225 47
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType'));
1226
1227 47
            $globalSchemas[(string) static::XML_NS]->addSchema(
1228 47
                $globalSchemas[(string) static::XSD_NS],
1229
                (string) static::XSD_NS
1230 47
            );
1231 47
            $globalSchemas[(string) static::XSD_NS]->addSchema(
1232 47
                $globalSchemas[(string) static::XML_NS],
1233
                (string) static::XML_NS
1234 47
            );
1235
1236
            /**
1237
             * @var Closure
1238
             */
1239 47
            foreach ($callbacks as $callback) {
1240 47
                $callback();
1241 47
            }
1242 47
        }
1243
1244
        /**
1245
         * @var Schema
1246
         */
1247 47
        $out = $this->globalSchema;
1248
1249 47
        return $out;
1250
    }
1251
1252
    /**
1253
     * @param DOMElement $node
1254
     * @param string     $file
1255
     *
1256
     * @return Schema
1257
     */
1258 47
    private function readNode(DOMElement $node, $file = 'schema.xsd')
1259
    {
1260 47
        $fileKey = $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file;
1261 47
        $this->setLoadedFile($fileKey, $rootSchema = new Schema());
1262
1263 47
        $rootSchema->addSchema($this->getGlobalSchema());
1264 47
        $callbacks = $this->schemaNode($rootSchema, $node);
1265
1266 47
        foreach ($callbacks as $callback) {
1267 41
            call_user_func($callback);
1268 47
        }
1269
1270 47
        return $rootSchema;
1271
    }
1272
1273
    /**
1274
     * It is possible that a single file contains multiple <xsd:schema/> nodes, for instance in a WSDL file.
1275
     *
1276
     * Each of these  <xsd:schema/> nodes typically target a specific namespace. Append the target namespace to the
1277
     * file to distinguish between multiple schemas in a single file.
1278
     *
1279
     * @param string $file
1280
     * @param string $targetNamespace
1281
     *
1282
     * @return string
1283
     */
1284 47
    private function getNamespaceSpecificFileIndex($file, $targetNamespace)
1285
    {
1286 47
        return $file.'#'.$targetNamespace;
1287
    }
1288
1289
    /**
1290
     * @param string $content
1291
     * @param string $file
1292
     *
1293
     * @return Schema
1294
     *
1295
     * @throws IOException
1296
     */
1297 46
    public function readString($content, $file = 'schema.xsd')
1298
    {
1299 46
        $xml = new DOMDocument('1.0', 'UTF-8');
1300 46
        if (!$xml->loadXML($content)) {
1301
            throw new IOException("Can't load the schema");
1302
        }
1303 46
        $xml->documentURI = $file;
1304
1305 46
        return $this->readNode($xml->documentElement, $file);
1306
    }
1307
1308
    /**
1309
     * @param string $file
1310
     *
1311
     * @return Schema
1312
     */
1313 1
    public function readFile($file)
1314
    {
1315 1
        $xml = $this->getDOM($file);
1316
1317 1
        return $this->readNode($xml->documentElement, $file);
1318
    }
1319
1320
    /**
1321
     * @param string $file
1322
     *
1323
     * @return DOMDocument
1324
     *
1325
     * @throws IOException
1326
     */
1327 47
    private function getDOM($file)
1328
    {
1329 47
        $xml = new DOMDocument('1.0', 'UTF-8');
1330 47
        if (!$xml->load($file)) {
1331
            throw new IOException("Can't load the file $file");
1332
        }
1333
1334 47
        return $xml;
1335
    }
1336
1337 47
    private static function againstDOMNodeList(
1338
        DOMElement $node,
1339
        Closure $againstNodeList
1340
    ) {
1341 47
        $limit = $node->childNodes->length;
1342 47
        for ($i = 0; $i < $limit; $i += 1) {
1343
            /**
1344
             * @var DOMNode
1345
             */
1346 47
            $childNode = $node->childNodes->item($i);
1347
1348 47
            if ($childNode instanceof DOMElement) {
1349 47
                $againstNodeList(
1350 47
                    $node,
1351
                    $childNode
1352 47
                );
1353 47
            }
1354 47
        }
1355 47
    }
1356
1357 47
    private function loadTypeWithCallback(
1358
        Schema $schema,
1359
        DOMElement $childNode,
1360
        Closure $callback
1361
    ) {
1362
        /**
1363
         * @var Closure|null $func
1364
         */
1365 47
        $func = null;
1366
1367 47
        switch ($childNode->localName) {
1368 47
            case 'complexType':
1369 47
                $func = $this->loadComplexType($schema, $childNode, $callback);
1370 47
                break;
1371 47
            case 'simpleType':
1372 47
                $func = $this->loadSimpleType($schema, $childNode, $callback);
1373 47
                break;
1374 47
        }
1375
1376 47
        if ($func instanceof Closure) {
1377 47
            call_user_func($func);
1378 47
        }
1379 47
    }
1380
1381
    /**
1382
     * @return Element
1383
     */
1384 47
    private function loadElement(
1385
        Schema $schema,
1386
        DOMElement $node
1387
    ) {
1388 47
        $element = new Element($schema, $node->getAttribute('name'));
1389 47
        $element->setDoc($this->getDocumentation($node));
1390
1391 47
        $this->fillItem($element, $node);
1392
1393 47
        self::maybeSetMax($element, $node);
1394 47
        self::maybeSetMin($element, $node);
1395
1396 47
        $xp = new \DOMXPath($node->ownerDocument);
1397 47
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
1398
1399 47
        if ($xp->query('ancestor::xs:choice', $node)->length) {
1400 47
            $element->setMin(0);
1401 47
        }
1402
1403 47
        if ($node->hasAttribute('nillable')) {
1404 3
            $element->setNil($node->getAttribute('nillable') == 'true');
1405 3
        }
1406 47
        if ($node->hasAttribute('form')) {
1407 3
            $element->setQualified($node->getAttribute('form') == 'qualified');
1408 3
        }
1409
1410 47
        return $element;
1411
    }
1412
1413 47
    private function addAttributeFromAttributeOrRef(
1414
        BaseComplexType $type,
1415
        DOMElement $childNode,
1416
        Schema $schema,
1417
        DOMElement $node
1418
    ) {
1419 47
        $attribute = $this->getAttributeFromAttributeOrRef(
1420 47
            $childNode,
1421 47
            $schema,
1422
            $node
1423 47
        );
1424
1425 47
        $type->addAttribute($attribute);
1426 47
    }
1427
1428 47
    private function findSomethingLikeAttributeGroup(
1429
        Schema $schema,
1430
        DOMElement $node,
1431
        DOMElement $childNode,
1432
        AttributeContainer $addToThis
1433
    ) {
1434
        /**
1435
         * @var AttributeItem
1436
         */
1437 47
        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute('ref'));
1438 47
        $addToThis->addAttribute($attribute);
1439 47
    }
1440
1441
    /**
1442
     * @param string $key
1443
     *
1444
     * @return Schema
1445
     */
1446 47
    private function setLoadedFile($key, Schema $schema)
1447
    {
1448 47
        $this->loadedFiles[$key] = $schema;
1449
1450 47
        return $schema;
1451
    }
1452
1453 47
    private function setSchemaThingsFromNode(
1454
        Schema $schema,
1455
        DOMElement $node,
1456
        Schema $parent = null
1457
    ) {
1458 47
        $schema->setDoc($this->getDocumentation($node));
1459
1460 47
        if ($node->hasAttribute('targetNamespace')) {
1461 47
            $schema->setTargetNamespace($node->getAttribute('targetNamespace'));
1462 47
        } elseif ($parent) {
1463
            $schema->setTargetNamespace($parent->getTargetNamespace());
1464
        }
1465 47
        $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
1466 47
        $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
1467 47
        $schema->setDoc($this->getDocumentation($node));
1468 47
    }
1469
}
1470