Completed
Push — master ( c51bd4...0a1432 )
by Asmir
8s
created

SchemaReader::loadImport()   C

Complexity

Conditions 11
Paths 5

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 11

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 19
cts 19
cp 1
rs 5.2653
c 0
b 0
f 0
cc 11
eloc 20
nc 5
nop 2
crap 11

How to fix   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
declare(strict_types=1);
4
5
namespace GoetasWebservices\XML\XSDReader;
6
7
use Closure;
8
use DOMDocument;
9
use DOMElement;
10
use DOMNode;
11
use GoetasWebservices\XML\XSDReader\Documentation\DocumentationReader;
12
use GoetasWebservices\XML\XSDReader\Documentation\StandardDocumentationReader;
13
use GoetasWebservices\XML\XSDReader\Exception\IOException;
14
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
15
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
16
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer;
17
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
18
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
19
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
20
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
21
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
22
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
23
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
24
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
25
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
26
use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax;
27
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
28
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base;
29
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
30
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
31
use GoetasWebservices\XML\XSDReader\Schema\Item;
32
use GoetasWebservices\XML\XSDReader\Schema\Schema;
33
use GoetasWebservices\XML\XSDReader\Schema\SchemaItem;
34
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
35
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
36
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
37
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
38
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
39
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
40
41
class SchemaReader
42
{
43
    public const XSD_NS = 'http://www.w3.org/2001/XMLSchema';
44
45
    public const XML_NS = 'http://www.w3.org/XML/1998/namespace';
46
47
    /**
48
     * @var DocumentationReader
49
     */
50
    private $documentationReader;
51
52
    /**
53
     * @var Schema[]
54
     */
55
    private $loadedFiles = array();
56
57
    /**
58
     * @var Schema[][]
59
     */
60
    private $loadedSchemas = array();
61
62
    /**
63
     * @var string[]
64
     */
65
    protected $knownLocationSchemas = [
66
        'http://www.w3.org/2001/xml.xsd' => (
67
            __DIR__.'/Resources/xml.xsd'
68
        ),
69
        'http://www.w3.org/2001/XMLSchema.xsd' => (
70
            __DIR__.'/Resources/XMLSchema.xsd'
71
        ),
72
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' => (
73
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-secext-1.0.xsd'
74
        ),
75
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' => (
76
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-utility-1.0.xsd'
77
        ),
78
        'https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
79
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
80
        ),
81
        'http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
82
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
83
        ),
84
    ];
85
86
    /**
87
     * @var string[]
88
     */
89
    protected static $globalSchemaInfo = array(
90
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
91
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd',
92
    );
93
94 2
    private function extractErrorMessage(): \Exception
95
    {
96 2
        $errors = array();
97
98 2
        foreach (libxml_get_errors() as $error) {
99 1
            $errors[] = sprintf("Error[%s] code %s: %s in '%s' at position %s:%s", $error->level, $error->code, trim($error->message), $error->file, $error->line, $error->column);
100
        }
101 2
        $e = new \Exception(implode('; ', $errors));
102 2
        libxml_use_internal_errors(false);
103
104 2
        return $e;
105
    }
106
107 69
    public function __construct(DocumentationReader $documentationReader = null)
108
    {
109 69
        if (null === $documentationReader) {
110 69
            $documentationReader = new StandardDocumentationReader();
111
        }
112 69
        $this->documentationReader = $documentationReader;
113 69
    }
114
115 1
    public function addKnownSchemaLocation(string $remote, string $local): void
116
    {
117 1
        $this->knownLocationSchemas[$remote] = $local;
118 1
    }
119
120 58
    private function loadAttributeGroup(
121
        Schema $schema,
122
        DOMElement $node
123
    ): Closure {
124 58
        $attGroup = new AttributeGroup($schema, $node->getAttribute('name'));
125 58
        $attGroup->setDoc($this->getDocumentation($node));
126 58
        $schema->addAttributeGroup($attGroup);
127
128 58
        return function () use ($schema, $node, $attGroup) {
129 58
            SchemaReader::againstDOMNodeList(
130 58
                $node,
131 58
                function (
132
                    DOMElement $node,
133
                    DOMElement $childNode
134
                ) use (
135 58
                    $schema,
136 58
                    $attGroup
137
                ) {
138 58
                    switch ($childNode->localName) {
139 58
                        case 'attribute':
140 58
                            $attribute = $this->getAttributeFromAttributeOrRef(
141 58
                                $childNode,
142 58
                                $schema,
143 58
                                $node
144
                            );
145 58
                            $attGroup->addAttribute($attribute);
146 58
                            break;
147 58
                        case 'attributeGroup':
148 1
                            $this->findSomethingLikeAttributeGroup(
149 1
                                $schema,
150 1
                                $node,
151 1
                                $childNode,
152 1
                                $attGroup
153
                            );
154 1
                            break;
155
                    }
156 58
                }
157
            );
158 58
        };
159
    }
160
161 58
    private function getAttributeFromAttributeOrRef(
162
        DOMElement $childNode,
163
        Schema $schema,
164
        DOMElement $node
165
    ): AttributeItem {
166 58
        if ($childNode->hasAttribute('ref')) {
167 58
            $attribute = $this->findAttributeItem($schema, $node, $childNode->getAttribute('ref'));
168
        } else {
169
            /**
170
             * @var Attribute
171
             */
172 58
            $attribute = $this->loadAttribute($schema, $childNode);
173
        }
174
175 58
        return $attribute;
176
    }
177
178 58
    private function loadAttribute(
179
        Schema $schema,
180
        DOMElement $node
181
    ): Attribute {
182 58
        $attribute = new Attribute($schema, $node->getAttribute('name'));
183 58
        $attribute->setDoc($this->getDocumentation($node));
184 58
        $this->fillItem($attribute, $node);
185
186 58
        if ($node->hasAttribute('nillable')) {
187 1
            $attribute->setNil($node->getAttribute('nillable') == 'true');
188
        }
189 58
        if ($node->hasAttribute('form')) {
190 1
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
191
        }
192 58
        if ($node->hasAttribute('use')) {
193 58
            $attribute->setUse($node->getAttribute('use'));
194
        }
195
196 58
        return $attribute;
197
    }
198
199 58
    private function loadAttributeOrElementDef(
200
        Schema $schema,
201
        DOMElement $node,
202
        bool $attributeDef
203
    ): Closure {
204 58
        $name = $node->getAttribute('name');
205 58
        if ($attributeDef) {
206 58
            $attribute = new AttributeDef($schema, $name);
207 58
            $schema->addAttribute($attribute);
208
        } else {
209 58
            $attribute = new ElementDef($schema, $name);
210 58
            $schema->addElement($attribute);
211
        }
212
213 58
        return function () use ($attribute, $node) {
214 58
            $this->fillItem($attribute, $node);
215 58
        };
216
    }
217
218 58
    private function loadAttributeDef(Schema $schema, DOMElement $node): Closure
219
    {
220 58
        return $this->loadAttributeOrElementDef($schema, $node, true);
221
    }
222
223 58
    private function getDocumentation(DOMElement $node): string
224
    {
225 58
        return $this->documentationReader->get($node);
226
    }
227
228
    /**
229
     * @return Closure[]
230
     */
231 58
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null): array
232
    {
233 58
        $this->setSchemaThingsFromNode($schema, $node, $parent);
234 58
        $functions = array();
235
236 58
        static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
237 58
            $node,
238 58
            function (
239
                DOMElement $node,
240
                DOMElement $childNode
241
            ) use (
242 58
                $schema,
243 58
                &$functions
244
            ) {
245 58
                $callback = null;
246
247 58
                switch ($childNode->localName) {
248 58
                    case 'attributeGroup':
249 58
                        $callback = $this->loadAttributeGroup($schema, $childNode);
250 58
                        break;
251 58
                    case 'include':
252 58
                    case 'import':
253 58
                        $callback = $this->loadImport($schema, $childNode);
254 58
                        break;
255 58
                    case 'element':
256 58
                        $callback = $this->loadElementDef($schema, $childNode);
257 58
                        break;
258 58
                    case 'attribute':
259 58
                        $callback = $this->loadAttributeDef($schema, $childNode);
260 58
                        break;
261 58
                    case 'group':
262 58
                        $callback = $this->loadGroup($schema, $childNode);
263 58
                        break;
264 58
                    case 'complexType':
265 58
                        $callback = $this->loadComplexType($schema, $childNode);
266 58
                        break;
267 58
                    case 'simpleType':
268 58
                        $callback = $this->loadSimpleType($schema, $childNode);
269 58
                        break;
270
                }
271
272 58
                if ($callback instanceof Closure) {
273 58
                    $functions[] = $callback;
274
                }
275 58
            }
276
        );
277
278 58
        return $functions;
279
    }
280
281 58
    private function loadGroupRef(Group $referenced, DOMElement $node): GroupRef
282
    {
283 58
        $ref = new GroupRef($referenced);
284 58
        $ref->setDoc($this->getDocumentation($node));
285
286 58
        self::maybeSetMax($ref, $node);
287 58
        self::maybeSetMin($ref, $node);
288
289 58
        return $ref;
290
    }
291
292 58
    private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): void
293
    {
294 58
        if ($node->hasAttribute('maxOccurs')) {
295 58
            $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
296
        }
297 58
    }
298
299 58
    private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): void
300
    {
301 58
        if ($node->hasAttribute('minOccurs')) {
302 58
            $ref->setMin((int) $node->getAttribute('minOccurs'));
303 58
            if ($ref->getMin() > $ref->getMax()) {
304 58
                $ref->setMax($ref->getMin());
305
            }
306
        }
307 58
    }
308
309 58
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void
310
    {
311
        $max =
312
            (
313 58
                (is_int($max) && (bool) $max) ||
314 58
                $node->getAttribute('maxOccurs') == 'unbounded' ||
315 58
                $node->getAttribute('maxOccurs') > 1
316
            )
317 58
                ? 2
318 58
                : null;
319
320 58
        static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
321 58
            $node,
322 58
            function (
323
                DOMElement $node,
324
                DOMElement $childNode
325
            ) use (
326 58
                $elementContainer,
327 58
                $max
328
            ) {
329 58
                $this->loadSequenceChildNode(
330 58
                    $elementContainer,
331 58
                    $node,
332 58
                    $childNode,
333 58
                    $max
334
                );
335 58
            }
336
        );
337 58
    }
338
339
    /**
340
     * @param int|null $max
341
     */
342 58
    private function loadSequenceChildNode(
343
        ElementContainer $elementContainer,
344
        DOMElement $node,
345
        DOMElement $childNode,
346
        $max
347
    ): void {
348 58
        switch ($childNode->localName) {
349 58
            case 'sequence':
350 58
            case 'choice':
351 58
            case 'all':
352 58
                $this->loadSequence(
353 58
                    $elementContainer,
354 58
                    $childNode,
355 58
                    $max
356
                );
357 58
                break;
358 58
            case 'element':
359 58
                $this->loadSequenceChildNodeLoadElement(
360 58
                    $elementContainer,
361 58
                    $node,
362 58
                    $childNode,
363 58
                    $max
364
                );
365 58
                break;
366 58
            case 'group':
367 58
                $this->addGroupAsElement(
368 58
                    $elementContainer->getSchema(),
369 58
                    $node,
370 58
                    $childNode,
371 58
                    $elementContainer
372
                );
373 58
                break;
374
        }
375 58
    }
376
377
    /**
378
     * @param int|null $max
379
     */
380 58
    private function loadSequenceChildNodeLoadElement(
381
        ElementContainer $elementContainer,
382
        DOMElement $node,
383
        DOMElement $childNode,
384
        $max
385
    ): void {
386 58
        if ($childNode->hasAttribute('ref')) {
387 58
            $element = new ElementRef(
388 58
                $this->findElement($elementContainer->getSchema(), $node, $childNode->getAttribute('ref'))
389
            );
390 58
            $element->setDoc($this->getDocumentation($childNode));
391
392 58
            self::maybeSetMax($element, $childNode);
393 58
            self::maybeSetMin($element, $childNode);
394 58
            if ($childNode->hasAttribute('nillable')) {
395
                $element->setNil($childNode->getAttribute('nillable') == 'true');
396
            }
397 58
            if ($childNode->hasAttribute('form')) {
398 58
                $element->setQualified($childNode->getAttribute('form') == 'qualified');
399
            }
400
        } else {
401 58
            $element = $this->loadElement(
402 58
                $elementContainer->getSchema(),
403 58
                $childNode
404
            );
405
        }
406 58
        if ($max > 1) {
407
            /*
408
            * although one might think the typecast is not needed with $max being `? int $max` after passing > 1,
409
            * phpstan@a4f89fa still thinks it's possibly null.
410
            * see https://github.com/phpstan/phpstan/issues/577 for related issue
411
            */
412 58
            $element->setMax((int) $max);
413
        }
414 58
        $elementContainer->addElement($element);
415 58
    }
416
417 58
    private function addGroupAsElement(
418
        Schema $schema,
419
        DOMElement $node,
420
        DOMElement $childNode,
421
        ElementContainer $elementContainer
422
    ): void {
423 58
        $referencedGroup = $this->findGroup(
424 58
            $schema,
425 58
            $node,
426 58
            $childNode->getAttribute('ref')
427
        );
428
429 58
        $group = $this->loadGroupRef($referencedGroup, $childNode);
430 58
        $elementContainer->addElement($group);
431 58
    }
432
433 58
    private function loadGroup(Schema $schema, DOMElement $node): Closure
434
    {
435 58
        $group = new Group($schema, $node->getAttribute('name'));
436 58
        $group->setDoc($this->getDocumentation($node));
437 58
        $groupOriginal = $group;
438
439 58
        if ($node->hasAttribute('maxOccurs') || $node->hasAttribute('maxOccurs')) {
440 1
            $group = new GroupRef($group);
441
442 1
            if ($node->hasAttribute('maxOccurs')) {
443 1
                self::maybeSetMax($group, $node);
444
            }
445 1
            if ($node->hasAttribute('minOccurs')) {
446 1
                self::maybeSetMin($group, $node);
447
            }
448
        }
449
450 58
        $schema->addGroup($group);
451
452 58
        return function () use ($groupOriginal, $node) {
453 58
            static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
454 58
                $node,
455 58
                function (DOMelement $node, DOMElement $childNode) use ($groupOriginal) {
456 58
                    switch ($childNode->localName) {
457 58
                        case 'sequence':
458 58
                        case 'choice':
459 58
                        case 'all':
460 58
                            $this->loadSequence($groupOriginal, $childNode);
461 58
                            break;
462
                    }
463 58
                }
464
            );
465 58
        };
466
    }
467
468 58
    private function loadComplexType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
469
    {
470
        /**
471
         * @var bool
472
         */
473 58
        $isSimple = false;
474
475 58
        static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
476 58
            $node,
477 58
            function (
478
                DOMElement $node,
479
                DOMElement $childNode
480
            ) use (
481 58
                &$isSimple
482
            ) {
483 58
                if ($isSimple) {
484 1
                    return;
485
                }
486 58
                if ($childNode->localName === 'simpleContent') {
487 2
                    $isSimple = true;
488
                }
489 58
            }
490
        );
491
492 58
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name'));
493
494 58
        $type->setDoc($this->getDocumentation($node));
495 58
        if ($node->getAttribute('name')) {
496 58
            $schema->addType($type);
497
        }
498
499 58
        return function () use ($type, $node, $schema, $callback) {
500 58
            $this->fillTypeNode($type, $node, true);
501
502 58
            static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
503 58
                $node,
504 58
                function (
505
                    DOMElement $node,
506
                    DOMElement $childNode
507
                ) use (
508 58
                    $schema,
509 58
                    $type
510
                ) {
511 58
                    $this->loadComplexTypeFromChildNode(
512 58
                        $type,
513 58
                        $node,
514 58
                        $childNode,
515 58
                        $schema
516
                    );
517 58
                }
518
            );
519
520 58
            if ($callback instanceof Closure) {
521 58
                call_user_func($callback, $type);
522
            }
523 58
        };
524
    }
525
526 58
    private function loadComplexTypeFromChildNode(
527
        BaseComplexType $type,
528
        DOMElement $node,
529
        DOMElement $childNode,
530
        Schema $schema
531
    ): void {
532 58
        switch ($childNode->localName) {
533 58
            case 'sequence':
534 58
            case 'choice':
535 58
            case 'all':
536 58
                if ($type instanceof ElementContainer) {
537 58
                    $this->loadSequence(
538 58
                        $type,
539 58
                        $childNode
540
                    );
541
                }
542 58
                break;
543 58
            case 'attribute':
544 58
                $this->addAttributeFromAttributeOrRef(
545 58
                    $type,
546 58
                    $childNode,
547 58
                    $schema,
548 58
                    $node
549
                );
550 58
                break;
551 58
            case 'attributeGroup':
552 2
                $this->findSomethingLikeAttributeGroup(
553 2
                    $schema,
554 2
                    $node,
555 2
                    $childNode,
556 2
                    $type
557
                );
558 2
                break;
559 58
            case 'group':
560
                if (
561 1
                    $type instanceof ComplexType
562
                ) {
563 1
                    $this->addGroupAsElement(
564 1
                        $schema,
565 1
                        $node,
566 1
                        $childNode,
567 1
                        $type
568
                    );
569
                }
570 1
                break;
571
        }
572 58
    }
573
574 58
    private function loadSimpleType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
575
    {
576 58
        $type = new SimpleType($schema, $node->getAttribute('name'));
577 58
        $type->setDoc($this->getDocumentation($node));
578 58
        if ($node->getAttribute('name')) {
579 58
            $schema->addType($type);
580
        }
581
582 58
        return function () use ($type, $node, $callback) {
583 58
            $this->fillTypeNode($type, $node, true);
584
585 58
            static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
586 58
                $node,
587 58
                function (DOMElement $node, DOMElement $childNode) use ($type) {
588 58
                    switch ($childNode->localName) {
589 58
                        case 'union':
590 58
                            $this->loadUnion($type, $childNode);
591 58
                            break;
592 58
                        case 'list':
593 58
                            $this->loadList($type, $childNode);
594 58
                            break;
595
                    }
596 58
                }
597
            );
598
599 58
            if ($callback instanceof Closure) {
600 58
                call_user_func($callback, $type);
601
            }
602 58
        };
603
    }
604
605 58
    private function loadList(SimpleType $type, DOMElement $node): void
606
    {
607 58
        if ($node->hasAttribute('itemType')) {
608
            /**
609
             * @var SimpleType
610
             */
611 58
            $listType = $this->findSomeType($type, $node, 'itemType');
612 58
            $type->setList($listType);
0 ignored issues
show
Documentation introduced by
$listType is of type object<GoetasWebservices...ader\Schema\SchemaItem>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
613
        } else {
614 58
            self::againstDOMNodeList(
615 58
                $node,
616 58
                function (
617
                    DOMElement $node,
618
                    DOMElement $childNode
619
                ) use (
620 58
                    $type
621
                ) {
622 58
                    $this->loadTypeWithCallback(
623 58
                        $type->getSchema(),
624 58
                        $childNode,
625 58
                        function (SimpleType $list) use ($type) {
626 58
                            $type->setList($list);
0 ignored issues
show
Documentation introduced by
$list is of type object<GoetasWebservices...Schema\Type\SimpleType>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
627 58
                        }
628
                    );
629 58
                }
630
            );
631
        }
632 58
    }
633
634 58
    private function findSomeType(
635
        SchemaItem $fromThis,
636
        DOMElement $node,
637
        string $attributeName
638
    ): SchemaItem {
639 58
        return $this->findSomeTypeFromAttribute(
640 58
            $fromThis,
641 58
            $node,
642 58
            $node->getAttribute($attributeName)
643
        );
644
    }
645
646 58
    private function findSomeTypeFromAttribute(
647
        SchemaItem $fromThis,
648
        DOMElement $node,
649
        string $attributeName
650
    ): SchemaItem {
651 58
        $out = $this->findType(
652 58
            $fromThis->getSchema(),
653 58
            $node,
654 58
            $attributeName
655
        );
656
657 58
        return $out;
658
    }
659
660 58
    private function loadUnion(SimpleType $type, DOMElement $node): void
661
    {
662 58
        if ($node->hasAttribute('memberTypes')) {
663 58
            $types = preg_split('/\s+/', $node->getAttribute('memberTypes'));
664 58
            foreach ($types as $typeName) {
665
                /**
666
                 * @var SimpleType
667
                 */
668 58
                $unionType = $this->findSomeTypeFromAttribute(
669 58
                    $type,
670 58
                    $node,
671 58
                    $typeName
672
                );
673 58
                $type->addUnion($unionType);
0 ignored issues
show
Documentation introduced by
$unionType is of type object<GoetasWebservices...ader\Schema\SchemaItem>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
674
            }
675
        }
676 58
        self::againstDOMNodeList(
677 58
            $node,
678 58
            function (
679
                DOMElement $node,
680
                DOMElement $childNode
681
            ) use (
682 58
                $type
683
            ) {
684 58
                $this->loadTypeWithCallback(
685 58
                    $type->getSchema(),
686 58
                    $childNode,
687 58
                    function (SimpleType $unType) use ($type) {
688 58
                        $type->addUnion($unType);
0 ignored issues
show
Documentation introduced by
$unType is of type object<GoetasWebservices...Schema\Type\SimpleType>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
689 58
                    }
690
                );
691 58
            }
692
        );
693 58
    }
694
695 58
    private function fillTypeNode(Type $type, DOMElement $node, bool $checkAbstract = false): void
696
    {
697 58
        if ($checkAbstract) {
698 58
            $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1');
699
        }
700
701 58
        static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
702 58
            $node,
703 58
            function (DOMElement $node, DOMElement $childNode) use ($type) {
704 58
                switch ($childNode->localName) {
705 58
                    case 'restriction':
706 58
                        $this->loadRestriction($type, $childNode);
707 58
                        break;
708 58
                    case 'extension':
709 58
                        if ($type instanceof BaseComplexType) {
710 58
                            $this->loadExtension($type, $childNode);
711
                        }
712 58
                        break;
713 58
                    case 'simpleContent':
714 58
                    case 'complexContent':
715 58
                        $this->fillTypeNode($type, $childNode);
716 58
                        break;
717
                }
718 58
            }
719
        );
720 58
    }
721
722 58
    private function loadExtension(BaseComplexType $type, DOMElement $node): void
723
    {
724 58
        $extension = new Extension();
725 58
        $type->setExtension($extension);
726
727 58
        if ($node->hasAttribute('base')) {
728 58
            $this->findAndSetSomeBase(
729 58
                $type,
730 58
                $extension,
731 58
                $node
732
            );
733
        }
734 58
        $this->loadExtensionChildNodes($type, $node);
735 58
    }
736
737 58
    private function findAndSetSomeBase(
738
        Type $type,
739
        Base $setBaseOnThis,
740
        DOMElement $node
741
    ): void {
742
        /**
743
         * @var Type
744
         */
745 58
        $parent = $this->findSomeType($type, $node, 'base');
746 58
        $setBaseOnThis->setBase($parent);
0 ignored issues
show
Compatibility introduced by
$parent of type object<GoetasWebservices...ader\Schema\SchemaItem> is not a sub-type of object<GoetasWebservices...eader\Schema\Type\Type>. It seems like you assume a concrete implementation of the interface GoetasWebservices\XML\XSDReader\Schema\SchemaItem to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
747 58
    }
748
749 58
    private function loadExtensionChildNodes(
750
        BaseComplexType $type,
751
        DOMElement $node
752
    ) {
753 58
        static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
754 58
            $node,
755 58
            function (
756
                DOMElement $node,
757
                DOMElement $childNode
758
            ) use (
759 58
                $type
760
            ) {
761 58
                switch ($childNode->localName) {
762 58
                    case 'sequence':
763 58
                    case 'choice':
764 58
                    case 'all':
765 58
                        if ($type instanceof ElementContainer) {
766 58
                            $this->loadSequence(
767 58
                                $type,
768 58
                                $childNode
769
                            );
770
                        }
771 58
                        break;
772 58
                    case 'attribute':
773 58
                        $this->addAttributeFromAttributeOrRef(
774 58
                            $type,
775 58
                            $childNode,
776 58
                            $type->getSchema(),
777 58
                            $node
778
                        );
779 58
                        break;
780 58
                    case 'attributeGroup':
781 58
                        $this->findSomethingLikeAttributeGroup(
782 58
                            $type->getSchema(),
783 58
                            $node,
784 58
                            $childNode,
785 58
                            $type
786
                        );
787 58
                        break;
788
                }
789 58
            }
790
        );
791 58
    }
792
793 58
    private function loadRestriction(Type $type, DOMElement $node): void
794
    {
795 58
        $restriction = new Restriction();
796 58
        $type->setRestriction($restriction);
797 58
        if ($node->hasAttribute('base')) {
798 58
            $this->findAndSetSomeBase($type, $restriction, $node);
799
        } else {
800 58
            self::againstDOMNodeList(
801 58
                $node,
802 58
                function (
803
                    DOMElement $node,
804
                    DOMElement $childNode
805
                ) use (
806 58
                    $type,
807 58
                    $restriction
808
                ) {
809 58
                    $this->loadTypeWithCallback(
810 58
                        $type->getSchema(),
811 58
                        $childNode,
812 58
                        function (Type $restType) use ($restriction) {
813 58
                            $restriction->setBase($restType);
814 58
                        }
815
                    );
816 58
                }
817
            );
818
        }
819 58
        self::againstDOMNodeList(
820 58
            $node,
821 58
            function (
822
                DOMElement $node,
823
                DOMElement $childNode
824
            ) use (
825 58
                $restriction
826
            ) {
827
                if (
828 58
                in_array(
829 58
                    $childNode->localName,
830
                    [
831 58
                        'enumeration',
832
                        'pattern',
833
                        'length',
834
                        'minLength',
835
                        'maxLength',
836
                        'minInclusive',
837
                        'maxInclusive',
838
                        'minExclusive',
839
                        'maxExclusive',
840
                        'fractionDigits',
841
                        'totalDigits',
842
                        'whiteSpace',
843
                    ],
844 58
                    true
845
                )
846
                ) {
847 58
                    $restriction->addCheck(
848 58
                        $childNode->localName,
849
                        [
850 58
                            'value' => $childNode->getAttribute('value'),
851 58
                            'doc' => $this->getDocumentation($childNode),
852
                        ]
853
                    );
854
                }
855 58
            }
856
        );
857 58
    }
858
859
    /**
860
     * @return mixed[]
861
     */
862 58
    private static function splitParts(DOMElement $node, string $typeName): array
863
    {
864 58
        $prefix = null;
865 58
        $name = $typeName;
866 58
        if (strpos($typeName, ':') !== false) {
867 58
            list($prefix, $name) = explode(':', $typeName);
868
        }
869
870 58
        $namespace = $node->lookupNamespaceUri($prefix ?: '');
871
872
        return array(
873 58
            $name,
874 58
            $namespace,
875 58
            $prefix,
876
        );
877
    }
878
879 58
    private function findAttributeItem(Schema $schema, DOMElement $node, string $typeName): AttributeItem
880
    {
881 58
        list($name, $namespace) = static::splitParts($node, $typeName);
0 ignored issues
show
Bug introduced by
Since splitParts() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of splitParts() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
882
883 58
        $namespace = $namespace ?: $schema->getTargetNamespace();
884
885
        try {
886 58
            return $schema->findAttribute($name, $namespace);
887
        } catch (TypeNotFoundException $e) {
888
            throw new TypeException(
889
                sprintf(
890
                    "Can't find %s named {%s}#%s, at line %d in %s ",
891
                    'attribute',
892
                    $namespace,
893
                    $name,
894
                    $node->getLineNo(),
895
                    $node->ownerDocument->documentURI
896
                ),
897
                0,
898
                $e
899
            );
900
        }
901
    }
902
903 58
    private function findAttributeGroup(Schema $schema, DOMElement $node, string $typeName): AttributeGroup
904
    {
905 58
        list($name, $namespace) = static::splitParts($node, $typeName);
0 ignored issues
show
Bug introduced by
Since splitParts() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of splitParts() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
906
907 58
        $namespace = $namespace ?: $schema->getTargetNamespace();
908
909
        try {
910 58
            return $schema->findAttributeGroup($name, $namespace);
911
        } catch (TypeNotFoundException $e) {
912
            throw new TypeException(
913
                sprintf(
914
                    "Can't find %s named {%s}#%s, at line %d in %s ",
915
                    'attributegroup',
916
                    $namespace,
917
                    $name,
918
                    $node->getLineNo(),
919
                    $node->ownerDocument->documentURI
920
                ),
921
                0,
922
                $e
923
            );
924
        }
925
    }
926
927 58
    private function findElement(Schema $schema, DOMElement $node, string $typeName): ElementDef
928
    {
929 58
        list($name, $namespace) = static::splitParts($node, $typeName);
0 ignored issues
show
Bug introduced by
Since splitParts() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of splitParts() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
930
931 58
        $namespace = $namespace ?: $schema->getTargetNamespace();
932
933
        try {
934 58
            return $schema->findElement($name, $namespace);
935
        } catch (TypeNotFoundException $e) {
936
            throw new TypeException(
937
                sprintf(
938
                    "Can't find %s named {%s}#%s, at line %d in %s ",
939
                    'element',
940
                    $namespace,
941
                    $name,
942
                    $node->getLineNo(),
943
                    $node->ownerDocument->documentURI
944
                ),
945
                0,
946
                $e
947
            );
948
        }
949
    }
950
951 58
    private function findGroup(Schema $schema, DOMElement $node, string $typeName): Group
952
    {
953 58
        list($name, $namespace) = static::splitParts($node, $typeName);
0 ignored issues
show
Bug introduced by
Since splitParts() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of splitParts() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
954
955 58
        $namespace = $namespace ?: $schema->getTargetNamespace();
956
957
        try {
958 58
            return $schema->findGroup($name, $namespace);
959
        } catch (TypeNotFoundException $e) {
960
            throw new TypeException(
961
                sprintf(
962
                    "Can't find %s named {%s}#%s, at line %d in %s ",
963
                    'group',
964
                    $namespace,
965
                    $name,
966
                    $node->getLineNo(),
967
                    $node->ownerDocument->documentURI
968
                ),
969
                0,
970
                $e
971
            );
972
        }
973
    }
974
975 58
    private function findType(Schema $schema, DOMElement $node, string $typeName): SchemaItem
976
    {
977 58
        list($name, $namespace) = static::splitParts($node, $typeName);
0 ignored issues
show
Bug introduced by
Since splitParts() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of splitParts() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
978
979 58
        $namespace = $namespace ?: $schema->getTargetNamespace();
980
981
        try {
982 58
            return $schema->findType($name, $namespace);
983
        } catch (TypeNotFoundException $e) {
984
            throw new TypeException(
985
                sprintf(
986
                    "Can't find %s named {%s}#%s, at line %d in %s ",
987
                    'type',
988
                    $namespace,
989
                    $name,
990
                    $node->getLineNo(),
991
                    $node->ownerDocument->documentURI
992
                ),
993
                0,
994
                $e
995
            );
996
        }
997
    }
998
999
    /**
1000
     * @return Closure
1001
     */
1002 58
    private function loadElementDef(Schema $schema, DOMElement $node): Closure
1003
    {
1004 58
        return $this->loadAttributeOrElementDef($schema, $node, false);
1005
    }
1006
1007 58
    private function fillItem(Item $element, DOMElement $node)
1008
    {
1009
        /**
1010
         * @var bool
1011
         */
1012 58
        $skip = false;
1013 58
        static::againstDOMNodeList(
0 ignored issues
show
Bug introduced by
Since againstDOMNodeList() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of againstDOMNodeList() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
1014 58
            $node,
1015 58
            function (
1016
                DOMElement $node,
1017
                DOMElement $childNode
1018
            ) use (
1019 58
                $element,
1020 58
                &$skip
1021
            ) {
1022
                if (
1023 58
                    !$skip &&
1024 58
                    in_array(
1025 58
                        $childNode->localName,
1026
                        [
1027 58
                            'complexType',
1028
                            'simpleType',
1029
                        ],
1030 58
                        true
1031
                    )
1032
                ) {
1033 58
                    $this->loadTypeWithCallback(
1034 58
                        $element->getSchema(),
1035 58
                        $childNode,
1036 58
                        function (Type $type) use ($element) {
1037 58
                            $element->setType($type);
1038 58
                        }
1039
                    );
1040 58
                    $skip = true;
1041
                }
1042 58
            }
1043
        );
1044 58
        if ($skip) {
1045 58
            return;
1046
        }
1047 58
        $this->fillItemNonLocalType($element, $node);
1048 58
    }
1049
1050 58
    private function fillItemNonLocalType(Item $element, DOMElement $node): void
1051
    {
1052 58
        if ($node->getAttribute('type')) {
1053
            /**
1054
             * @var Type
1055
             */
1056 58
            $type = $this->findSomeType($element, $node, 'type');
1057
        } else {
1058
            /**
1059
             * @var Type
1060
             */
1061 58
            $type = $this->findSomeTypeFromAttribute(
1062 58
                $element,
1063 58
                $node,
1064 58
                ($node->lookupPrefix(self::XSD_NS).':anyType')
1065
            );
1066
        }
1067
1068 58
        $element->setType($type);
0 ignored issues
show
Compatibility introduced by
$type of type object<GoetasWebservices...ader\Schema\SchemaItem> is not a sub-type of object<GoetasWebservices...eader\Schema\Type\Type>. It seems like you assume a concrete implementation of the interface GoetasWebservices\XML\XSDReader\Schema\SchemaItem to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1069 58
    }
1070
1071 58
    private function loadImport(
1072
        Schema $schema,
1073
        DOMElement $node
1074
    ): Closure {
1075 58
        $namespace = $node->getAttribute('namespace');
1076 58
        $schemaLocation = $node->getAttribute('schemaLocation');
1077
1078
        // postpone schema loading
1079 58
        if ($namespace && !$schemaLocation && !isset(self::$globalSchemaInfo[$namespace])) {
1080 2
            return function () use ($schema, $namespace) {
1081 2
                if (!empty($this->loadedSchemas[$namespace])) {
1082 2
                    foreach ($this->loadedSchemas[$namespace] as $s) {
1083 2
                        $schema->addSchema($s, $namespace);
0 ignored issues
show
Documentation introduced by
$s is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1084
                    }
1085
                }
1086 2
            };
1087 58
        } elseif ($namespace && !$schemaLocation && !empty($this->loadedSchemas[$namespace])) {
1088 1
            foreach ($this->loadedSchemas[$namespace] as $s) {
1089 1
                $schema->addSchema($s, $namespace);
0 ignored issues
show
Documentation introduced by
$s is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1090
            }
1091
        }
1092
1093 58
        $base = urldecode($node->ownerDocument->documentURI);
1094 58
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));
1095
1096 58
        if (isset($this->loadedFiles[$file])) {
1097 58
            $schema->addSchema($this->loadedFiles[$file]);
0 ignored issues
show
Documentation introduced by
$this->loadedFiles[$file] is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1098
1099 58
            return function () {
1100 58
            };
1101
        }
1102
1103 2
        return $this->loadImportFresh($namespace, $schema, $file);
1104
    }
1105
1106 2
    private function createOrUseSchemaForNs(
1107
        Schema $schema,
1108
        string $namespace
1109
    ): Schema {
1110 2
        if (('' !== trim($namespace))) {
1111 1
            $newSchema = new Schema();
1112 1
            $newSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
Documentation introduced by
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1113 1
            $schema->addSchema($newSchema);
0 ignored issues
show
Documentation introduced by
$newSchema is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1114
        } else {
1115 1
            $newSchema = $schema;
1116
        }
1117
1118 2
        return $newSchema;
1119
    }
1120
1121
    private function loadImportFresh(
1122
        string $namespace,
1123
        Schema $schema,
1124
        string $file
1125
    ): Closure {
1126 2
        return function () use ($namespace, $schema, $file) {
1127 2
            $dom = $this->getDOM(
1128 2
                isset($this->knownLocationSchemas[$file])
1129 1
                    ? $this->knownLocationSchemas[$file]
1130 2
                    : $file
1131
            );
1132
1133 2
            $schemaNew = $this->createOrUseSchemaForNs($schema, $namespace);
1134
1135 2
            $this->setLoadedFile($file, $schemaNew);
1136
1137 2
            $callbacks = $this->schemaNode($schemaNew, $dom->documentElement, $schema);
1138
1139 2
            foreach ($callbacks as $callback) {
1140 2
                $callback();
1141
            }
1142 2
        };
1143
    }
1144
1145
    /**
1146
     * @var Schema|null
1147
     */
1148
    protected $globalSchema;
1149
1150
    /**
1151
     * @return Schema
1152
     */
1153 58
    public function getGlobalSchema(): Schema
1154
    {
1155 58
        if (!($this->globalSchema instanceof Schema)) {
1156 58
            $callbacks = array();
1157 58
            $globalSchemas = array();
1158
            /**
1159
             * @var string $namespace
1160
             */
1161 58
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
1162 58
                $this->setLoadedFile(
1163 58
                    $uri,
1164 58
                    $globalSchemas[$namespace] = $schema = new Schema()
1165
                );
1166 58
                $this->setLoadedSchema($namespace, $schema);
1167 58
                if ($namespace === self::XSD_NS) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $namespace (integer) and self::XSD_NS (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1168 58
                    $this->globalSchema = $schema;
1169
                }
1170 58
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
1171 58
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
1172
            }
1173
1174 58
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType'));
1175 58
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType'));
1176
1177 58
            $globalSchemas[(string) static::XML_NS]->addSchema(
1178 58
                $globalSchemas[(string) static::XSD_NS],
1179 58
                (string) static::XSD_NS
1180
            );
1181 58
            $globalSchemas[(string) static::XSD_NS]->addSchema(
1182 58
                $globalSchemas[(string) static::XML_NS],
1183 58
                (string) static::XML_NS
1184
            );
1185
1186
            /**
1187
             * @var Closure
1188
             */
1189 58
            foreach ($callbacks as $callback) {
1190 58
                $callback();
1191
            }
1192
        }
1193
1194
        /**
1195
         * @var Schema
1196
         */
1197 58
        $out = $this->globalSchema;
1198
1199 58
        if (!($out instanceof Schema)) {
1200
            throw new TypeException('Globa schema not discoverd');
1201
        }
1202
1203 58
        return $out;
1204
    }
1205
1206 1
    public function readNodes(array $nodes, string $file = null)
1207
    {
1208 1
        $rootSchema = new Schema();
1209 1
        $rootSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
Documentation introduced by
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1210
1211 1
        if ($file !== null) {
1212 1
            $this->setLoadedFile($file, $rootSchema);
1213
        }
1214
1215 1
        $all = array();
1216 1
        foreach ($nodes as $k => $node) {
1217 1
            if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') {
1218 1
                $holderSchema = new Schema();
1219 1
                $holderSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
Documentation introduced by
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1220
1221 1
                $this->setLoadedSchemaFromElement($node, $holderSchema);
1222
1223 1
                $rootSchema->addSchema($holderSchema);
0 ignored issues
show
Documentation introduced by
$holderSchema is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1224
1225 1
                $callbacks = $this->schemaNode($holderSchema, $node);
1226 1
                $all = array_merge($callbacks, $all);
1227
            }
1228
        }
1229
1230 1
        foreach ($all as $callback) {
1231 1
            call_user_func($callback);
1232
        }
1233
1234 1
        return $rootSchema;
1235
    }
1236
1237 57
    public function readNode(DOMElement $node, string $file = null): Schema
1238
    {
1239 57
        $rootSchema = new Schema();
1240 57
        $rootSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
Documentation introduced by
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1241
1242 57
        if ($file !== null) {
1243 56
            $this->setLoadedFile($file, $rootSchema);
1244
        }
1245
1246 57
        $this->setLoadedSchemaFromElement($node, $rootSchema);
1247
1248 57
        $callbacks = $this->schemaNode($rootSchema, $node);
1249
1250 57
        foreach ($callbacks as $callback) {
1251 51
            call_user_func($callback);
1252
        }
1253
1254 57
        return $rootSchema;
1255
    }
1256
1257
    /**
1258
     * @throws IOException
1259
     */
1260 56
    public function readString(string $content, string $file = 'schema.xsd'): Schema
1261
    {
1262 56
        $xml = new DOMDocument('1.0', 'UTF-8');
1263 56
        libxml_use_internal_errors(true);
1264 56
        if (!@$xml->loadXML($content)) {
1265 1
            throw new IOException("Can't load the schema", 0, $this->extractErrorMessage());
1266
        }
1267 55
        libxml_use_internal_errors(false);
1268 55
        $xml->documentURI = $file;
1269
1270 55
        return $this->readNode($xml->documentElement, $file);
1271
    }
1272
1273
    /**
1274
     * @throws IOException
1275
     */
1276 2
    public function readFile(string $file): Schema
1277
    {
1278 2
        $xml = $this->getDOM($file);
1279
1280 1
        return $this->readNode($xml->documentElement, $file);
1281
    }
1282
1283
    /**
1284
     * @throws IOException
1285
     */
1286 59
    private function getDOM(string $file): DOMDocument
1287
    {
1288 59
        $xml = new DOMDocument('1.0', 'UTF-8');
1289 59
        libxml_use_internal_errors(true);
1290 59
        if (!@$xml->load($file)) {
1291 1
            libxml_use_internal_errors(false);
1292 1
            throw new IOException("Can't load the file '$file'", 0, $this->extractErrorMessage());
1293
        }
1294 58
        libxml_use_internal_errors(false);
1295
1296 58
        return $xml;
1297
    }
1298
1299 58
    private static function againstDOMNodeList(
1300
        DOMElement $node,
1301
        Closure $againstNodeList
1302
    ) {
1303 58
        $limit = $node->childNodes->length;
1304 58
        for ($i = 0; $i < $limit; $i += 1) {
1305
            /**
1306
             * @var DOMNode
1307
             */
1308 58
            $childNode = $node->childNodes->item($i);
1309
1310 58
            if ($childNode instanceof DOMElement) {
1311 58
                $againstNodeList(
1312 58
                    $node,
1313 58
                    $childNode
1314
                );
1315
            }
1316
        }
1317 58
    }
1318
1319 58
    private function loadTypeWithCallback(
1320
        Schema $schema,
1321
        DOMElement $childNode,
1322
        Closure $callback
1323
    ) {
1324
        /**
1325
         * @var Closure|null $func
1326
         */
1327 58
        $func = null;
1328
1329 58
        switch ($childNode->localName) {
1330 58
            case 'complexType':
1331 58
                $func = $this->loadComplexType($schema, $childNode, $callback);
1332 58
                break;
1333 58
            case 'simpleType':
1334 58
                $func = $this->loadSimpleType($schema, $childNode, $callback);
1335 58
                break;
1336
        }
1337
1338 58
        if ($func instanceof Closure) {
1339 58
            call_user_func($func);
1340
        }
1341 58
    }
1342
1343 58
    private function loadElement(
1344
        Schema $schema,
1345
        DOMElement $node
1346
    ): Element {
1347 58
        $element = new Element($schema, $node->getAttribute('name'));
1348 58
        $element->setDoc($this->getDocumentation($node));
1349
1350 58
        $this->fillItem($element, $node);
1351
1352 58
        self::maybeSetMax($element, $node);
1353 58
        self::maybeSetMin($element, $node);
1354
1355 58
        $xp = new \DOMXPath($node->ownerDocument);
1356 58
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
1357
1358 58
        if ($xp->query('ancestor::xs:choice', $node)->length) {
1359 58
            $element->setMin(0);
1360
        }
1361
1362 58
        if ($node->hasAttribute('nillable')) {
1363 3
            $element->setNil($node->getAttribute('nillable') == 'true');
1364
        }
1365 58
        if ($node->hasAttribute('form')) {
1366 3
            $element->setQualified($node->getAttribute('form') == 'qualified');
1367
        }
1368
1369 58
        return $element;
1370
    }
1371
1372 58
    private function addAttributeFromAttributeOrRef(
1373
        BaseComplexType $type,
1374
        DOMElement $childNode,
1375
        Schema $schema,
1376
        DOMElement $node
1377
    ): void {
1378 58
        $attribute = $this->getAttributeFromAttributeOrRef(
1379 58
            $childNode,
1380 58
            $schema,
1381 58
            $node
1382
        );
1383
1384 58
        $type->addAttribute($attribute);
1385 58
    }
1386
1387 58
    private function findSomethingLikeAttributeGroup(
1388
        Schema $schema,
1389
        DOMElement $node,
1390
        DOMElement $childNode,
1391
        AttributeContainer $addToThis
1392
    ): void {
1393 58
        $attribute = $this->findAttributeGroup($schema, $node, $childNode->getAttribute('ref'));
1394 58
        $addToThis->addAttribute($attribute);
1395 58
    }
1396
1397 58
    private function setLoadedFile(string $key, Schema $schema): void
1398
    {
1399 58
        $this->loadedFiles[$key] = $schema;
1400 58
    }
1401
1402 58
    private function setLoadedSchemaFromElement(DOMElement $node, Schema $schema): void
1403
    {
1404 58
        if ($node->hasAttribute('targetNamespace')) {
1405 58
            $this->setLoadedSchema($node->getAttribute('targetNamespace'), $schema);
1406
        }
1407 58
    }
1408
1409 58
    private function setLoadedSchema(string $namespace, Schema $schema): void
1410
    {
1411 58
        if (!isset($this->loadedSchemas[$namespace])) {
1412 58
            $this->loadedSchemas[$namespace] = array();
1413
        }
1414 58
        if (!in_array($schema, $this->loadedSchemas[$namespace], true)) {
1415 58
            $this->loadedSchemas[$namespace][] = $schema;
1416
        }
1417 58
    }
1418
1419 58
    private function setSchemaThingsFromNode(
1420
        Schema $schema,
1421
        DOMElement $node,
1422
        Schema $parent = null
1423
    ): void {
1424 58
        $schema->setDoc($this->getDocumentation($node));
1425
1426 58
        if ($node->hasAttribute('targetNamespace')) {
1427 58
            $schema->setTargetNamespace($node->getAttribute('targetNamespace'));
1428
        } elseif ($parent instanceof Schema) {
1429
            $schema->setTargetNamespace($parent->getTargetNamespace());
1430
        }
1431 58
        $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
1432 58
        $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
1433 58
        $schema->setDoc($this->getDocumentation($node));
1434 58
    }
1435
}
1436