Completed
Push — master ( 26cc59...c51bd4 )
by Asmir
03:44
created

SchemaReader::loadImport()   D

Complexity

Conditions 10
Paths 5

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 10.017

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 17
cts 18
cp 0.9444
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 19
nc 5
nop 2
crap 10.017

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\InterfaceSetMinMax;
26
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
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 58
    public function __construct(DocumentationReader $documentationReader = null)
95
    {
96 58
        if (null === $documentationReader) {
97 58
            $documentationReader = new StandardDocumentationReader();
98
        }
99 58
        $this->documentationReader = $documentationReader;
100 58
    }
101
102
    public function addKnownSchemaLocation(string $remote, string $local): void
103
    {
104
        $this->knownLocationSchemas[$remote] = $local;
105
    }
106
107 49
    private function loadAttributeGroup(
108
        Schema $schema,
109
        DOMElement $node
110
    ): Closure {
111 49
        $attGroup = new AttributeGroup($schema, $node->getAttribute('name'));
112 49
        $attGroup->setDoc($this->getDocumentation($node));
113 49
        $schema->addAttributeGroup($attGroup);
114
115 49
        return function () use ($schema, $node, $attGroup) {
116 49
            SchemaReader::againstDOMNodeList(
117 49
                $node,
118 49
                function (
119
                    DOMElement $node,
120
                    DOMElement $childNode
121
                ) use (
122 49
                    $schema,
123 49
                    $attGroup
124
                ) {
125 49
                    switch ($childNode->localName) {
126 49
                        case 'attribute':
127 49
                            $attribute = $this->getAttributeFromAttributeOrRef(
128 49
                                $childNode,
129 49
                                $schema,
130 49
                                $node
131
                            );
132 49
                            $attGroup->addAttribute($attribute);
133 49
                            break;
134 49
                        case 'attributeGroup':
135 1
                            $this->findSomethingLikeAttributeGroup(
136 1
                                $schema,
137 1
                                $node,
138 1
                                $childNode,
139 1
                                $attGroup
140
                            );
141 1
                            break;
142
                    }
143 49
                }
144
            );
145 49
        };
146
    }
147
148 49
    private function getAttributeFromAttributeOrRef(
149
        DOMElement $childNode,
150
        Schema $schema,
151
        DOMElement $node
152
    ): AttributeItem {
153 49
        if ($childNode->hasAttribute('ref')) {
154 49
            $attribute = $this->findAttributeItem($schema, $node, $childNode->getAttribute('ref'));
155
        } else {
156
            /**
157
             * @var Attribute
158
             */
159 49
            $attribute = $this->loadAttribute($schema, $childNode);
160
        }
161
162 49
        return $attribute;
163
    }
164
165 49
    private function loadAttribute(
166
        Schema $schema,
167
        DOMElement $node
168
    ): Attribute {
169 49
        $attribute = new Attribute($schema, $node->getAttribute('name'));
170 49
        $attribute->setDoc($this->getDocumentation($node));
171 49
        $this->fillItem($attribute, $node);
172
173 49
        if ($node->hasAttribute('nillable')) {
174 1
            $attribute->setNil($node->getAttribute('nillable') == 'true');
175
        }
176 49
        if ($node->hasAttribute('form')) {
177 1
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
178
        }
179 49
        if ($node->hasAttribute('use')) {
180 49
            $attribute->setUse($node->getAttribute('use'));
181
        }
182
183 49
        return $attribute;
184
    }
185
186 49
    private function loadAttributeOrElementDef(
187
        Schema $schema,
188
        DOMElement $node,
189
        bool $attributeDef
190
    ): Closure {
191 49
        $name = $node->getAttribute('name');
192 49
        if ($attributeDef) {
193 49
            $attribute = new AttributeDef($schema, $name);
194 49
            $schema->addAttribute($attribute);
195
        } else {
196 49
            $attribute = new ElementDef($schema, $name);
197 49
            $schema->addElement($attribute);
198
        }
199
200 49
        return function () use ($attribute, $node) {
201 49
            $this->fillItem($attribute, $node);
202 49
        };
203
    }
204
205 49
    private function loadAttributeDef(Schema $schema, DOMElement $node): Closure
206
    {
207 49
        return $this->loadAttributeOrElementDef($schema, $node, true);
208
    }
209
210 49
    private function getDocumentation(DOMElement $node): string
211
    {
212 49
        return $this->documentationReader->get($node);
213
    }
214
215
    /**
216
     * @return Closure[]
217
     */
218 49
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null): array
219
    {
220 49
        $this->setSchemaThingsFromNode($schema, $node, $parent);
221 49
        $functions = array();
222
223 49
        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...
224 49
            $node,
225 49
            function (
226
                DOMElement $node,
227
                DOMElement $childNode
228
            ) use (
229 49
                $schema,
230 49
                &$functions
231
            ) {
232 49
                $callback = null;
233
234 49
                switch ($childNode->localName) {
235 49
                    case 'attributeGroup':
236 49
                        $callback = $this->loadAttributeGroup($schema, $childNode);
237 49
                        break;
238 49
                    case 'include':
239 49
                    case 'import':
240 49
                        $callback = $this->loadImport($schema, $childNode);
241 49
                        break;
242 49
                    case 'element':
243 49
                        $callback = $this->loadElementDef($schema, $childNode);
244 49
                        break;
245 49
                    case 'attribute':
246 49
                        $callback = $this->loadAttributeDef($schema, $childNode);
247 49
                        break;
248 49
                    case 'group':
249 49
                        $callback = $this->loadGroup($schema, $childNode);
250 49
                        break;
251 49
                    case 'complexType':
252 49
                        $callback = $this->loadComplexType($schema, $childNode);
253 49
                        break;
254 49
                    case 'simpleType':
255 49
                        $callback = $this->loadSimpleType($schema, $childNode);
256 49
                        break;
257
                }
258
259 49
                if ($callback instanceof Closure) {
260 49
                    $functions[] = $callback;
261
                }
262 49
            }
263
        );
264
265 49
        return $functions;
266
    }
267
268 49
    private function loadGroupRef(Group $referenced, DOMElement $node): GroupRef
269
    {
270 49
        $ref = new GroupRef($referenced);
271 49
        $ref->setDoc($this->getDocumentation($node));
272
273 49
        self::maybeSetMax($ref, $node);
274 49
        self::maybeSetMin($ref, $node);
275
276 49
        return $ref;
277
    }
278
279 49
    private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
280
    {
281
        if (
282 49
            $node->hasAttribute('maxOccurs')
283
        ) {
284 49
            $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
285
        }
286
287 49
        return $ref;
288
    }
289
290 49
    private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
291
    {
292 49
        if ($node->hasAttribute('minOccurs')) {
293 49
            $ref->setMin((int) $node->getAttribute('minOccurs'));
294
        }
295
296 49
        return $ref;
297
    }
298
299 49
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void
300
    {
301
        $max =
302
        (
303 49
            (is_int($max) && (bool) $max) ||
304 49
            $node->getAttribute('maxOccurs') == 'unbounded' ||
305 49
            $node->getAttribute('maxOccurs') > 1
306
        )
307 49
            ? 2
308 49
            : null;
309
310 49
        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...
311 49
            $node,
312 49
            function (
313
                DOMElement $node,
314
                DOMElement $childNode
315
            ) use (
316 49
                $elementContainer,
317 49
                $max
318
            ) {
319 49
                $this->loadSequenceChildNode(
320 49
                    $elementContainer,
321 49
                    $node,
322 49
                    $childNode,
323 49
                    $max
324
                );
325 49
            }
326
        );
327 49
    }
328
329
    /**
330
     * @param int|null $max
331
     */
332 49
    private function loadSequenceChildNode(
333
        ElementContainer $elementContainer,
334
        DOMElement $node,
335
        DOMElement $childNode,
336
        $max
337
    ): void {
338 49
        switch ($childNode->localName) {
339 49
            case 'sequence':
340 49
            case 'choice':
341 49
            case 'all':
342 49
                $this->loadSequence(
343 49
                    $elementContainer,
344 49
                    $childNode,
345 49
                    $max
346
                );
347 49
                break;
348 49
            case 'element':
349 49
                $this->loadSequenceChildNodeLoadElement(
350 49
                    $elementContainer,
351 49
                    $node,
352 49
                    $childNode,
353 49
                    $max
354
                );
355 49
                break;
356 49
            case 'group':
357 49
                $this->addGroupAsElement(
358 49
                    $elementContainer->getSchema(),
359 49
                    $node,
360 49
                    $childNode,
361 49
                    $elementContainer
362
                );
363 49
                break;
364
        }
365 49
    }
366
367
    /**
368
     * @param int|null $max
369
     */
370 49
    private function loadSequenceChildNodeLoadElement(
371
        ElementContainer $elementContainer,
372
        DOMElement $node,
373
        DOMElement $childNode,
374
        $max
375
    ): void {
376 49
        if ($childNode->hasAttribute('ref')) {
377 49
            $element = new ElementRef(
378 49
                $this->findElement($elementContainer->getSchema(), $node, $childNode->getAttribute('ref'))
379
            );
380 49
            $element->setDoc($this->getDocumentation($childNode));
381
382 49
            self::maybeSetMax($element, $childNode);
383 49
            self::maybeSetMin($element, $childNode);
384 49
            if ($childNode->hasAttribute('nillable')) {
385
                $element->setNil($childNode->getAttribute('nillable') == 'true');
386
            }
387 49
            if ($childNode->hasAttribute('form')) {
388 49
                $element->setQualified($childNode->getAttribute('form') == 'qualified');
389
            }
390
        } else {
391 49
            $element = $this->loadElement(
392 49
                $elementContainer->getSchema(),
393 49
                $childNode
394
            );
395
        }
396 49
        if ($max > 1) {
397
            /*
398
            * although one might think the typecast is not needed with $max being `? int $max` after passing > 1,
399
            * phpstan@a4f89fa still thinks it's possibly null.
400
            * see https://github.com/phpstan/phpstan/issues/577 for related issue
401
            */
402 49
            $element->setMax((int) $max);
403
        }
404 49
        $elementContainer->addElement($element);
405 49
    }
406
407 49
    private function addGroupAsElement(
408
        Schema $schema,
409
        DOMElement $node,
410
        DOMElement $childNode,
411
        ElementContainer $elementContainer
412
    ): void {
413 49
        $referencedGroup = $this->findGroup(
414 49
            $schema,
415 49
            $node,
416 49
            $childNode->getAttribute('ref')
417
        );
418
419 49
        $group = $this->loadGroupRef($referencedGroup, $childNode);
420 49
        $elementContainer->addElement($group);
421 49
    }
422
423 49
    private function loadGroup(Schema $schema, DOMElement $node): Closure
424
    {
425 49
        $group = new Group($schema, $node->getAttribute('name'));
426 49
        $group->setDoc($this->getDocumentation($node));
427
428 49
        if ($node->hasAttribute('maxOccurs')) {
429
            /**
430
             * @var GroupRef
431
             */
432
            $group = self::maybeSetMax(new GroupRef($group), $node);
433
        }
434 49
        if ($node->hasAttribute('minOccurs')) {
435
            /**
436
             * @var GroupRef
437
             */
438
            $group = self::maybeSetMin(
439
                $group instanceof GroupRef ? $group : new GroupRef($group),
0 ignored issues
show
Bug introduced by
It seems like $group defined by self::maybeSetMin($group...roupRef($group), $node) on line 438 can also be of type object<GoetasWebservices...ent\InterfaceSetMinMax>; however, GoetasWebservices\XML\XS...GroupRef::__construct() does only seem to accept object<GoetasWebservices...r\Schema\Element\Group>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
440
                $node
441
            );
442
        }
443
444 49
        $schema->addGroup($group);
0 ignored issues
show
Bug introduced by
It seems like $group can also be of type object<GoetasWebservices...ent\InterfaceSetMinMax>; however, GoetasWebservices\XML\XS...hema\Schema::addGroup() does only seem to accept object<GoetasWebservices...r\Schema\Element\Group>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
445
446 49
        return function () use ($group, $node) {
447 49
            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...
448 49
                $node,
449 49
                function (DOMelement $node, DOMElement $childNode) use ($group) {
450 49
                    switch ($childNode->localName) {
451 49
                        case 'sequence':
452 49
                        case 'choice':
453 49
                        case 'all':
454 49
                            $this->loadSequence($group, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $group can also be of type object<GoetasWebservices...ent\InterfaceSetMinMax>; however, GoetasWebservices\XML\XS...aReader::loadSequence() does only seem to accept object<GoetasWebservices...ement\ElementContainer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
455 49
                            break;
456
                    }
457 49
                }
458
            );
459 49
        };
460
    }
461
462 49
    private function loadComplexType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
463
    {
464
        /**
465
         * @var bool
466
         */
467 49
        $isSimple = false;
468
469 49
        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...
470 49
            $node,
471 49
            function (
472
                DOMElement $node,
473
                DOMElement $childNode
474
            ) use (
475 49
                &$isSimple
476
            ) {
477 49
                if ($isSimple) {
478 1
                    return;
479
                }
480 49
                if ($childNode->localName === 'simpleContent') {
481 2
                    $isSimple = true;
482
                }
483 49
            }
484
        );
485
486 49
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name'));
487
488 49
        $type->setDoc($this->getDocumentation($node));
489 49
        if ($node->getAttribute('name')) {
490 49
            $schema->addType($type);
491
        }
492
493 49
        return function () use ($type, $node, $schema, $callback) {
494 49
            $this->fillTypeNode($type, $node, true);
495
496 49
            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...
497 49
                $node,
498 49
                function (
499
                    DOMElement $node,
500
                    DOMElement $childNode
501
                ) use (
502 49
                    $schema,
503 49
                    $type
504
                ) {
505 49
                    $this->loadComplexTypeFromChildNode(
506 49
                        $type,
507 49
                        $node,
508 49
                        $childNode,
509 49
                        $schema
510
                    );
511 49
                }
512
            );
513
514 49
            if ($callback instanceof Closure) {
515 49
                call_user_func($callback, $type);
516
            }
517 49
        };
518
    }
519
520 49
    private function loadComplexTypeFromChildNode(
521
        BaseComplexType $type,
522
        DOMElement $node,
523
        DOMElement $childNode,
524
        Schema $schema
525
    ): void {
526 49
        switch ($childNode->localName) {
527 49
            case 'sequence':
528 49
            case 'choice':
529 49
            case 'all':
530 49
                if ($type instanceof ElementContainer) {
531 49
                    $this->loadSequence(
532 49
                        $type,
533 49
                        $childNode
534
                    );
535
                }
536 49
                break;
537 49
            case 'attribute':
538 49
                $this->addAttributeFromAttributeOrRef(
539 49
                    $type,
540 49
                    $childNode,
541 49
                    $schema,
542 49
                    $node
543
                );
544 49
                break;
545 49
            case 'attributeGroup':
546 2
                $this->findSomethingLikeAttributeGroup(
547 2
                    $schema,
548 2
                    $node,
549 2
                    $childNode,
550 2
                    $type
551
                );
552 2
                break;
553 49
            case 'group':
554
                if (
555 1
                    $type instanceof ComplexType
556
                ) {
557 1
                    $this->addGroupAsElement(
558 1
                        $schema,
559 1
                        $node,
560 1
                        $childNode,
561 1
                        $type
562
                    );
563
                }
564 1
                break;
565
        }
566 49
    }
567
568 49
    private function loadSimpleType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
569
    {
570 49
        $type = new SimpleType($schema, $node->getAttribute('name'));
571 49
        $type->setDoc($this->getDocumentation($node));
572 49
        if ($node->getAttribute('name')) {
573 49
            $schema->addType($type);
574
        }
575
576 49
        return function () use ($type, $node, $callback) {
577 49
            $this->fillTypeNode($type, $node, true);
578
579 49
            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...
580 49
                $node,
581 49
                function (DOMElement $node, DOMElement $childNode) use ($type) {
582 49
                    switch ($childNode->localName) {
583 49
                        case 'union':
584 49
                            $this->loadUnion($type, $childNode);
585 49
                            break;
586 49
                        case 'list':
587 49
                            $this->loadList($type, $childNode);
588 49
                            break;
589
                    }
590 49
                }
591
            );
592
593 49
            if ($callback instanceof Closure) {
594 49
                call_user_func($callback, $type);
595
            }
596 49
        };
597
    }
598
599 49
    private function loadList(SimpleType $type, DOMElement $node): void
600
    {
601 49
        if ($node->hasAttribute('itemType')) {
602
            /**
603
             * @var SimpleType
604
             */
605 49
            $listType = $this->findSomeType($type, $node, 'itemType');
606 49
            $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...
607
        } else {
608 49
            self::againstDOMNodeList(
609 49
                $node,
610 49
                function (
611
                    DOMElement $node,
612
                    DOMElement $childNode
613
                ) use (
614 49
                    $type
615
                ) {
616 49
                    $this->loadTypeWithCallback(
617 49
                        $type->getSchema(),
618 49
                        $childNode,
619 49
                        function (SimpleType $list) use ($type) {
620 49
                            $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...
621 49
                        }
622
                    );
623 49
                }
624
            );
625
        }
626 49
    }
627
628 49
    private function findSomeType(
629
        SchemaItem $fromThis,
630
        DOMElement $node,
631
        string $attributeName
632
    ): SchemaItem {
633 49
        return $this->findSomeTypeFromAttribute(
634 49
            $fromThis,
635 49
            $node,
636 49
            $node->getAttribute($attributeName)
637
        );
638
    }
639
640 49
    private function findSomeTypeFromAttribute(
641
        SchemaItem $fromThis,
642
        DOMElement $node,
643
        string $attributeName
644
    ): SchemaItem {
645 49
        $out = $this->findType(
646 49
            $fromThis->getSchema(),
647 49
            $node,
648 49
            $attributeName
649
        );
650
651 49
        return $out;
652
    }
653
654 49
    private function loadUnion(SimpleType $type, DOMElement $node): void
655
    {
656 49
        if ($node->hasAttribute('memberTypes')) {
657 49
            $types = preg_split('/\s+/', $node->getAttribute('memberTypes'));
658 49
            foreach ($types as $typeName) {
659
                /**
660
                 * @var SimpleType
661
                 */
662 49
                $unionType = $this->findSomeTypeFromAttribute(
663 49
                    $type,
664 49
                    $node,
665 49
                    $typeName
666
                );
667 49
                $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...
668
            }
669
        }
670 49
        self::againstDOMNodeList(
671 49
            $node,
672 49
            function (
673
                DOMElement $node,
674
                DOMElement $childNode
675
            ) use (
676 49
                $type
677
            ) {
678 49
                $this->loadTypeWithCallback(
679 49
                    $type->getSchema(),
680 49
                    $childNode,
681 49
                    function (SimpleType $unType) use ($type) {
682 49
                        $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...
683 49
                    }
684
                );
685 49
            }
686
        );
687 49
    }
688
689 49
    private function fillTypeNode(Type $type, DOMElement $node, bool $checkAbstract = false): void
690
    {
691 49
        if ($checkAbstract) {
692 49
            $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1');
693
        }
694
695 49
        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...
696 49
            $node,
697 49
            function (DOMElement $node, DOMElement $childNode) use ($type) {
698 49
                switch ($childNode->localName) {
699 49
                    case 'restriction':
700 49
                        $this->loadRestriction($type, $childNode);
701 49
                        break;
702 49
                    case 'extension':
703 49
                        if ($type instanceof BaseComplexType) {
704 49
                            $this->loadExtension($type, $childNode);
705
                        }
706 49
                        break;
707 49
                    case 'simpleContent':
708 49
                    case 'complexContent':
709 49
                        $this->fillTypeNode($type, $childNode);
710 49
                        break;
711
                }
712 49
            }
713
        );
714 49
    }
715
716 49
    private function loadExtension(BaseComplexType $type, DOMElement $node): void
717
    {
718 49
        $extension = new Extension();
719 49
        $type->setExtension($extension);
720
721 49
        if ($node->hasAttribute('base')) {
722 49
            $this->findAndSetSomeBase(
723 49
                $type,
724 49
                $extension,
725 49
                $node
726
            );
727
        }
728 49
        $this->loadExtensionChildNodes($type, $node);
729 49
    }
730
731 49
    private function findAndSetSomeBase(
732
        Type $type,
733
        Base $setBaseOnThis,
734
        DOMElement $node
735
    ): void {
736
        /**
737
         * @var Type
738
         */
739 49
        $parent = $this->findSomeType($type, $node, 'base');
740 49
        $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...
741 49
    }
742
743 49
    private function loadExtensionChildNodes(
744
        BaseComplexType $type,
745
        DOMElement $node
746
    ) {
747 49
        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...
748 49
            $node,
749 49
            function (
750
                DOMElement $node,
751
                DOMElement $childNode
752
            ) use (
753 49
                $type
754
            ) {
755 49
                switch ($childNode->localName) {
756 49
                    case 'sequence':
757 49
                    case 'choice':
758 49
                    case 'all':
759 49
                        if ($type instanceof ElementContainer) {
760 49
                            $this->loadSequence(
761 49
                                $type,
762 49
                                $childNode
763
                            );
764
                        }
765 49
                        break;
766 49
                    case 'attribute':
767 49
                        $this->addAttributeFromAttributeOrRef(
768 49
                            $type,
769 49
                            $childNode,
770 49
                            $type->getSchema(),
771 49
                            $node
772
                        );
773 49
                        break;
774 49
                    case 'attributeGroup':
775 49
                        $this->findSomethingLikeAttributeGroup(
776 49
                            $type->getSchema(),
777 49
                            $node,
778 49
                            $childNode,
779 49
                            $type
780
                        );
781 49
                        break;
782
                }
783 49
            }
784
        );
785 49
    }
786
787 49
    private function loadRestriction(Type $type, DOMElement $node): void
788
    {
789 49
        $restriction = new Restriction();
790 49
        $type->setRestriction($restriction);
791 49
        if ($node->hasAttribute('base')) {
792 49
            $this->findAndSetSomeBase($type, $restriction, $node);
793
        } else {
794 49
            self::againstDOMNodeList(
795 49
                $node,
796 49
                function (
797
                    DOMElement $node,
798
                    DOMElement $childNode
799
                ) use (
800 49
                    $type,
801 49
                    $restriction
802
                ) {
803 49
                    $this->loadTypeWithCallback(
804 49
                        $type->getSchema(),
805 49
                        $childNode,
806 49
                        function (Type $restType) use ($restriction) {
807 49
                            $restriction->setBase($restType);
808 49
                        }
809
                    );
810 49
                }
811
            );
812
        }
813 49
        self::againstDOMNodeList(
814 49
            $node,
815 49
            function (
816
                DOMElement $node,
817
                DOMElement $childNode
818
            ) use (
819 49
                $restriction
820
            ) {
821
                if (
822 49
                    in_array(
823 49
                        $childNode->localName,
824
                        [
825 49
                            'enumeration',
826
                            'pattern',
827
                            'length',
828
                            'minLength',
829
                            'maxLength',
830
                            'minInclusive',
831
                            'maxInclusive',
832
                            'minExclusive',
833
                            'maxExclusive',
834
                            'fractionDigits',
835
                            'totalDigits',
836
                            'whiteSpace',
837
                        ],
838 49
                        true
839
                    )
840
                ) {
841 49
                    $restriction->addCheck(
842 49
                        $childNode->localName,
843
                        [
844 49
                            'value' => $childNode->getAttribute('value'),
845 49
                            'doc' => $this->getDocumentation($childNode),
846
                        ]
847
                    );
848
                }
849 49
            }
850
        );
851 49
    }
852
853
    /**
854
     * @return mixed[]
855
     */
856 49
    private static function splitParts(DOMElement $node, string $typeName): array
857
    {
858 49
        $prefix = null;
859 49
        $name = $typeName;
860 49
        if (strpos($typeName, ':') !== false) {
861 49
            list($prefix, $name) = explode(':', $typeName);
862
        }
863
864 49
        $namespace = $node->lookupNamespaceUri($prefix ?: '');
865
866
        return array(
867 49
            $name,
868 49
            $namespace,
869 49
            $prefix,
870
        );
871
    }
872
873 49
    private function findAttributeItem(Schema $schema, DOMElement $node, string $typeName): AttributeItem
874
    {
875 49
        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...
876
877 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
878
879
        try {
880 49
            return $schema->findAttribute($name, $namespace);
881
        } catch (TypeNotFoundException $e) {
882
            throw new TypeException(
883
                sprintf(
884
                    "Can't find %s named {%s}#%s, at line %d in %s ",
885
                    'attribute',
886
                    $namespace,
887
                    $name,
888
                    $node->getLineNo(),
889
                    $node->ownerDocument->documentURI
890
                ),
891
                0,
892
                $e
893
            );
894
        }
895
    }
896
897 49
    private function findAttributeGroup(Schema $schema, DOMElement $node, string $typeName): AttributeGroup
898
    {
899 49
        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...
900
901 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
902
903
        try {
904 49
            return $schema->findAttributeGroup($name, $namespace);
905
        } catch (TypeNotFoundException $e) {
906
            throw new TypeException(
907
                sprintf(
908
                    "Can't find %s named {%s}#%s, at line %d in %s ",
909
                    'attributegroup',
910
                    $namespace,
911
                    $name,
912
                    $node->getLineNo(),
913
                    $node->ownerDocument->documentURI
914
                ),
915
                0,
916
                $e
917
            );
918
        }
919
    }
920
921 49
    private function findElement(Schema $schema, DOMElement $node, string $typeName): ElementDef
922
    {
923 49
        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...
924
925 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
926
927
        try {
928 49
            return $schema->findElement($name, $namespace);
929
        } catch (TypeNotFoundException $e) {
930
            throw new TypeException(
931
                sprintf(
932
                    "Can't find %s named {%s}#%s, at line %d in %s ",
933
                    'element',
934
                    $namespace,
935
                    $name,
936
                    $node->getLineNo(),
937
                    $node->ownerDocument->documentURI
938
                ),
939
                0,
940
                $e
941
            );
942
        }
943
    }
944
945 49
    private function findGroup(Schema $schema, DOMElement $node, string $typeName): Group
946
    {
947 49
        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...
948
949 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
950
951
        try {
952 49
            return $schema->findGroup($name, $namespace);
953
        } catch (TypeNotFoundException $e) {
954
            throw new TypeException(
955
                sprintf(
956
                    "Can't find %s named {%s}#%s, at line %d in %s ",
957
                    'group',
958
                    $namespace,
959
                    $name,
960
                    $node->getLineNo(),
961
                    $node->ownerDocument->documentURI
962
                ),
963
                0,
964
                $e
965
            );
966
        }
967
    }
968
969 49
    private function findType(Schema $schema, DOMElement $node, string $typeName): SchemaItem
970
    {
971 49
        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...
972
973 49
        $namespace = $namespace ?: $schema->getTargetNamespace();
974
975
        try {
976 49
            return $schema->findType($name, $namespace);
977
        } catch (TypeNotFoundException $e) {
978
            throw new TypeException(
979
                sprintf(
980
                    "Can't find %s named {%s}#%s, at line %d in %s ",
981
                    'type',
982
                    $namespace,
983
                    $name,
984
                    $node->getLineNo(),
985
                    $node->ownerDocument->documentURI
986
                ),
987
                0,
988
                $e
989
            );
990
        }
991
    }
992
993
    /**
994
     * @return Closure
995
     */
996 49
    private function loadElementDef(Schema $schema, DOMElement $node): Closure
997
    {
998 49
        return $this->loadAttributeOrElementDef($schema, $node, false);
999
    }
1000
1001 49
    private function fillItem(Item $element, DOMElement $node)
1002
    {
1003
        /**
1004
         * @var bool
1005
         */
1006 49
        $skip = false;
1007 49
        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...
1008 49
            $node,
1009 49
            function (
1010
                DOMElement $node,
1011
                DOMElement $childNode
1012
            ) use (
1013 49
                $element,
1014 49
                &$skip
1015
            ) {
1016
                if (
1017 49
                    !$skip &&
1018 49
                    in_array(
1019 49
                        $childNode->localName,
1020
                        [
1021 49
                            'complexType',
1022
                            'simpleType',
1023
                        ],
1024 49
                        true
1025
                    )
1026
                ) {
1027 49
                    $this->loadTypeWithCallback(
1028 49
                        $element->getSchema(),
1029 49
                        $childNode,
1030 49
                        function (Type $type) use ($element) {
1031 49
                            $element->setType($type);
1032 49
                        }
1033
                    );
1034 49
                    $skip = true;
1035
                }
1036 49
            }
1037
        );
1038 49
        if ($skip) {
1039 49
            return;
1040
        }
1041 49
        $this->fillItemNonLocalType($element, $node);
1042 49
    }
1043
1044 49
    private function fillItemNonLocalType(Item $element, DOMElement $node): void
1045
    {
1046 49
        if ($node->getAttribute('type')) {
1047
            /**
1048
             * @var Type
1049
             */
1050 49
            $type = $this->findSomeType($element, $node, 'type');
1051
        } else {
1052
            /**
1053
             * @var Type
1054
             */
1055 49
            $type = $this->findSomeTypeFromAttribute(
1056 49
                $element,
1057 49
                $node,
1058 49
                ($node->lookupPrefix(self::XSD_NS).':anyType')
1059
            );
1060
        }
1061
1062 49
        $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...
1063 49
    }
1064
1065 49
    private function loadImport(
1066
        Schema $schema,
1067
        DOMElement $node
1068
    ): Closure {
1069 49
        $namespace = $node->getAttribute('namespace');
1070 49
        $schemaLocation = $node->getAttribute('schemaLocation');
1071
1072
        // postpone schema loading
1073 49
        if ($namespace && !$schemaLocation && !isset(self::$globalSchemaInfo[$namespace])) {
1074 2
            return function () use ($schema, $namespace) {
1075 2
                if (!empty($this->loadedSchemas[$namespace])) {
1076 2
                    foreach ($this->loadedSchemas[$namespace] as $s) {
1077 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...
1078
                    }
1079
                }
1080 2
            };
1081 49
        } elseif ($namespace && !$schemaLocation && isset($this->globalSchema[$namespace])) {
1082
            $schema->addSchema($this->globalSchema[$namespace]);
1083
        }
1084
1085 49
        $base = urldecode($node->ownerDocument->documentURI);
1086 49
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));
1087
1088 49
        if (isset($this->loadedFiles[$file])) {
1089 49
            $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...
1090
1091 49
            return function () {
1092 49
            };
1093
        }
1094
1095 1
        return $this->loadImportFresh($namespace, $schema, $file);
1096
    }
1097
1098 1
    private function createOrUseSchemaForNs(
1099
        Schema $schema,
1100
        string $namespace
1101
    ): Schema {
1102 1
        if (('' !== trim($namespace))) {
1103
            $newSchema = new Schema();
1104
            $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...
1105
            $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...
1106
        } else {
1107 1
            $newSchema = $schema;
1108
        }
1109
1110 1
        return $newSchema;
1111
    }
1112
1113
    private function loadImportFresh(
1114
        string $namespace,
1115
        Schema $schema,
1116
        string $file
1117
    ): Closure {
1118 1
        return function () use ($namespace, $schema, $file) {
1119 1
            $dom = $this->getDOM(
1120 1
            isset($this->knownLocationSchemas[$file])
1121
                ? $this->knownLocationSchemas[$file]
1122 1
                : $file
1123
            );
1124
1125 1
            $schemaNew = $this->createOrUseSchemaForNs($schema, $namespace);
1126
1127 1
            $this->setLoadedFile($file, $schemaNew);
1128
1129 1
            $callbacks = $this->schemaNode($schemaNew, $dom->documentElement, $schema);
1130
1131 1
            foreach ($callbacks as $callback) {
1132 1
                $callback();
1133
            }
1134 1
        };
1135
    }
1136
1137
    /**
1138
     * @var Schema|null
1139
     */
1140
    protected $globalSchema;
1141
1142
    /**
1143
     * @return Schema
1144
     */
1145 49
    public function getGlobalSchema(): Schema
1146
    {
1147 49
        if (!($this->globalSchema instanceof Schema)) {
1148 49
            $callbacks = array();
1149 49
            $globalSchemas = array();
1150
            /**
1151
             * @var string $namespace
1152
             */
1153 49
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
1154 49
                $this->setLoadedFile(
1155 49
                    $uri,
1156 49
                    $globalSchemas[$namespace] = $schema = new Schema()
1157
                );
1158 49
                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...
1159 49
                    $this->globalSchema = $schema;
1160
                }
1161 49
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
1162 49
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
1163
            }
1164
1165 49
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType'));
1166 49
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType'));
1167
1168 49
            $globalSchemas[(string) static::XML_NS]->addSchema(
1169 49
                $globalSchemas[(string) static::XSD_NS],
1170 49
                (string) static::XSD_NS
1171
            );
1172 49
            $globalSchemas[(string) static::XSD_NS]->addSchema(
1173 49
                $globalSchemas[(string) static::XML_NS],
1174 49
                (string) static::XML_NS
1175
            );
1176
1177
            /**
1178
             * @var Closure
1179
             */
1180 49
            foreach ($callbacks as $callback) {
1181 49
                $callback();
1182
            }
1183
        }
1184
1185
        /**
1186
         * @var Schema
1187
         */
1188 49
        $out = $this->globalSchema;
1189
1190 49
        if (!($out instanceof Schema)) {
1191
            throw new TypeException('Globa schema not discoverd');
1192
        }
1193
1194 49
        return $out;
1195
    }
1196
1197 1
    public function readNodes(array $nodes, string $file = null)
1198
    {
1199 1
        $rootSchema = new Schema();
1200 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...
1201
1202 1
        if ($file !== null) {
1203
            $this->setLoadedFile($file, $rootSchema);
1204
        }
1205
1206 1
        $all = array();
1207 1
        foreach ($nodes as $k => $node) {
1208 1
            if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') {
1209 1
                $holderSchema = new Schema();
1210 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...
1211
1212 1
                $this->setLoadedSchema($node, $holderSchema);
1213
1214 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...
1215
1216 1
                $callbacks = $this->schemaNode($holderSchema, $node);
1217 1
                $all = array_merge($callbacks, $all);
1218
            }
1219
        }
1220
1221 1
        foreach ($all as $callback) {
1222 1
            call_user_func($callback);
1223
        }
1224
1225 1
        return $rootSchema;
1226
    }
1227
1228 48
    public function readNode(DOMElement $node, string $file = null): Schema
1229
    {
1230 48
        $rootSchema = new Schema();
1231 48
        $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...
1232
1233 48
        if ($file !== null) {
1234 47
            $this->setLoadedFile($file, $rootSchema);
1235
        }
1236
1237 48
        $this->setLoadedSchema($node, $rootSchema);
1238
1239 48
        $callbacks = $this->schemaNode($rootSchema, $node);
1240
1241 48
        foreach ($callbacks as $callback) {
1242 42
            call_user_func($callback);
1243
        }
1244
1245 48
        return $rootSchema;
1246
    }
1247
1248
    /**
1249
     * @throws IOException
1250
     */
1251 46
    public function readString(string $content, string $file = 'schema.xsd'): Schema
1252
    {
1253 46
        $xml = new DOMDocument('1.0', 'UTF-8');
1254 46
        if (!$xml->loadXML($content)) {
1255
            throw new IOException("Can't load the schema");
1256
        }
1257 46
        $xml->documentURI = $file;
1258
1259 46
        return $this->readNode($xml->documentElement, $file);
1260
    }
1261
1262 1
    public function readFile(string $file): Schema
1263
    {
1264 1
        $xml = $this->getDOM($file);
1265
1266 1
        return $this->readNode($xml->documentElement, $file);
1267
    }
1268
1269
    /**
1270
     * @throws IOException
1271
     */
1272 49
    private function getDOM(string $file): DOMDocument
1273
    {
1274 49
        $xml = new DOMDocument('1.0', 'UTF-8');
1275 49
        if (!$xml->load($file)) {
1276
            throw new IOException("Can't load the file $file");
1277
        }
1278
1279 49
        return $xml;
1280
    }
1281
1282 49
    private static function againstDOMNodeList(
1283
        DOMElement $node,
1284
        Closure $againstNodeList
1285
    ) {
1286 49
        $limit = $node->childNodes->length;
1287 49
        for ($i = 0; $i < $limit; $i += 1) {
1288
            /**
1289
             * @var DOMNode
1290
             */
1291 49
            $childNode = $node->childNodes->item($i);
1292
1293 49
            if ($childNode instanceof DOMElement) {
1294 49
                $againstNodeList(
1295 49
                    $node,
1296 49
                    $childNode
1297
                );
1298
            }
1299
        }
1300 49
    }
1301
1302 49
    private function loadTypeWithCallback(
1303
        Schema $schema,
1304
        DOMElement $childNode,
1305
        Closure $callback
1306
    ) {
1307
        /**
1308
         * @var Closure|null $func
1309
         */
1310 49
        $func = null;
1311
1312 49
        switch ($childNode->localName) {
1313 49
            case 'complexType':
1314 49
                $func = $this->loadComplexType($schema, $childNode, $callback);
1315 49
                break;
1316 49
            case 'simpleType':
1317 49
                $func = $this->loadSimpleType($schema, $childNode, $callback);
1318 49
                break;
1319
        }
1320
1321 49
        if ($func instanceof Closure) {
1322 49
            call_user_func($func);
1323
        }
1324 49
    }
1325
1326 49
    private function loadElement(
1327
        Schema $schema,
1328
        DOMElement $node
1329
    ): Element {
1330 49
        $element = new Element($schema, $node->getAttribute('name'));
1331 49
        $element->setDoc($this->getDocumentation($node));
1332
1333 49
        $this->fillItem($element, $node);
1334
1335 49
        self::maybeSetMax($element, $node);
1336 49
        self::maybeSetMin($element, $node);
1337
1338 49
        $xp = new \DOMXPath($node->ownerDocument);
1339 49
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
1340
1341 49
        if ($xp->query('ancestor::xs:choice', $node)->length) {
1342 49
            $element->setMin(0);
1343
        }
1344
1345 49
        if ($node->hasAttribute('nillable')) {
1346 3
            $element->setNil($node->getAttribute('nillable') == 'true');
1347
        }
1348 49
        if ($node->hasAttribute('form')) {
1349 3
            $element->setQualified($node->getAttribute('form') == 'qualified');
1350
        }
1351
1352 49
        return $element;
1353
    }
1354
1355 49
    private function addAttributeFromAttributeOrRef(
1356
        BaseComplexType $type,
1357
        DOMElement $childNode,
1358
        Schema $schema,
1359
        DOMElement $node
1360
    ): void {
1361 49
        $attribute = $this->getAttributeFromAttributeOrRef(
1362 49
            $childNode,
1363 49
            $schema,
1364 49
            $node
1365
        );
1366
1367 49
        $type->addAttribute($attribute);
1368 49
    }
1369
1370 49
    private function findSomethingLikeAttributeGroup(
1371
        Schema $schema,
1372
        DOMElement $node,
1373
        DOMElement $childNode,
1374
        AttributeContainer $addToThis
1375
    ): void {
1376 49
        $attribute = $this->findAttributeGroup($schema, $node, $childNode->getAttribute('ref'));
1377 49
        $addToThis->addAttribute($attribute);
1378 49
    }
1379
1380 49
    private function setLoadedFile(string $key, Schema $schema): void
1381
    {
1382 49
        $this->loadedFiles[$key] = $schema;
1383 49
    }
1384
1385 49
    private function setLoadedSchema(DOMElement $node, Schema $schema): void
1386
    {
1387 49
        if ($node->hasAttribute('targetNamespace')) {
1388 49
            $this->loadedSchemas[$node->getAttribute('targetNamespace')][] = $schema;
1389
        }
1390 49
    }
1391
1392 49
    private function setSchemaThingsFromNode(
1393
        Schema $schema,
1394
        DOMElement $node,
1395
        Schema $parent = null
1396
    ): void {
1397 49
        $schema->setDoc($this->getDocumentation($node));
1398
1399 49
        if ($node->hasAttribute('targetNamespace')) {
1400 49
            $schema->setTargetNamespace($node->getAttribute('targetNamespace'));
1401
        } elseif ($parent instanceof Schema) {
1402
            $schema->setTargetNamespace($parent->getTargetNamespace());
1403
        }
1404 49
        $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
1405 49
        $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
1406 49
        $schema->setDoc($this->getDocumentation($node));
1407 49
    }
1408
}
1409