Completed
Push — master ( 1b0b24...55881e )
by SignpostMarv
05:36
created

SchemaReader::loadTypeWithCallback()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 0
Metric Value
dl 0
loc 23
c 0
b 0
f 0
ccs 7
cts 8
cp 0.875
rs 8.7972
cc 4
eloc 14
nc 6
nop 3
crap 4.0312
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 string[]
59
     */
60
    protected $knownLocationSchemas = [
61
        'http://www.w3.org/2001/xml.xsd' => (
62
            __DIR__.'/Resources/xml.xsd'
63
        ),
64
        'http://www.w3.org/2001/XMLSchema.xsd' => (
65
            __DIR__.'/Resources/XMLSchema.xsd'
66
        ),
67
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' => (
68
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-secext-1.0.xsd'
69
        ),
70
        'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' => (
71
            __DIR__.'/Resources/oasis-200401-wss-wssecurity-utility-1.0.xsd'
72
        ),
73
        'https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
74
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
75
        ),
76
        'http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => (
77
            __DIR__.'/Resources/xmldsig-core-schema.xsd'
78
        ),
79
    ];
80
81
    /**
82
     * @var string[]
83
     */
84
    protected static $globalSchemaInfo = array(
85
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
86
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd',
87
    );
88 56
89
    public function __construct(DocumentationReader $documentationReader = null)
90 56
    {
91 56
        if (null === $documentationReader) {
92 56
            $documentationReader = new StandardDocumentationReader();
93 56
        }
94 56
        $this->documentationReader = $documentationReader;
95
    }
96
97
    public function addKnownSchemaLocation(string $remote, string $local): void
98
    {
99
        $this->knownLocationSchemas[$remote] = $local;
100
    }
101
102
    private function loadAttributeGroup(
103
        Schema $schema,
104
        DOMElement $node
105
    ): Closure {
106
        $attGroup = new AttributeGroup($schema, $node->getAttribute('name'));
107
        $attGroup->setDoc($this->getDocumentation($node));
108 47
        $schema->addAttributeGroup($attGroup);
109
110
        return function () use ($schema, $node, $attGroup) {
111
            SchemaReader::againstDOMNodeList(
112 47
                $node,
113 47
                function (
114 47
                    DOMElement $node,
115
                    DOMElement $childNode
116
                ) use (
117 47
                    $schema,
118 47
                    $attGroup
119
                ) {
120
                    switch ($childNode->localName) {
121
                        case 'attribute':
122
                            $attribute = $this->getAttributeFromAttributeOrRef(
123 47
                                $childNode,
124 47
                                $schema,
125
                                $node
126 47
                            );
127 47
                            $attGroup->addAttribute($attribute);
128 47
                            break;
129 47
                        case 'attributeGroup':
130 47
                            $this->findSomethingLikeAttributeGroup(
131
                                $schema,
132 47
                                $node,
133 47
                                $childNode,
134 47
                                $attGroup
135 47
                            );
136 1
                            break;
137 1
                    }
138 1
                }
139 1
            );
140
        };
141 1
    }
142 1
143 47
    private function getAttributeFromAttributeOrRef(
144 47
        DOMElement $childNode,
145 47
        Schema $schema,
146 47
        DOMElement $node
147
    ): AttributeItem {
148
        if ($childNode->hasAttribute('ref')) {
149
            $attribute = $this->findAttributeItem($schema, $node, $childNode->getAttribute('ref'));
150
        } else {
151
            /**
152 47
             * @var Attribute
153
             */
154
            $attribute = $this->loadAttribute($schema, $childNode);
155
        }
156
157 47
        return $attribute;
158
    }
159
160
    private function loadAttribute(
161 47
        Schema $schema,
162 47
        DOMElement $node
163
    ): Attribute {
164
        $attribute = new Attribute($schema, $node->getAttribute('name'));
165
        $attribute->setDoc($this->getDocumentation($node));
166 47
        $this->fillItem($attribute, $node);
167
168
        if ($node->hasAttribute('nillable')) {
169 47
            $attribute->setNil($node->getAttribute('nillable') == 'true');
170
        }
171
        if ($node->hasAttribute('form')) {
172
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
173
        }
174
        if ($node->hasAttribute('use')) {
175 47
            $attribute->setUse($node->getAttribute('use'));
176
        }
177
178
        return $attribute;
179 47
    }
180 47
181 47
    private function loadAttributeOrElementDef(
182
        Schema $schema,
183 47
        DOMElement $node,
184 1
        bool $attributeDef
185 1
    ): Closure {
186 47
        $name = $node->getAttribute('name');
187 1
        if ($attributeDef) {
188 1
            $attribute = new AttributeDef($schema, $name);
189 47
            $schema->addAttribute($attribute);
190 47
        } else {
191 47
            $attribute = new ElementDef($schema, $name);
192
            $schema->addElement($attribute);
193 47
        }
194
195
        return function () use ($attribute, $node) {
196
            $this->fillItem($attribute, $node);
197
        };
198
    }
199
200
    private function loadAttributeDef(Schema $schema, DOMElement $node): Closure
201 47
    {
202
        return $this->loadAttributeOrElementDef($schema, $node, true);
203
    }
204
205
    private function getDocumentation(DOMElement $node): string
206 47
    {
207 47
        return $this->documentationReader->get($node);
208 47
    }
209 47
210 47
    /**
211 47
     * @return Closure[]
212 47
     */
213
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null): array
214
    {
215
        $this->setSchemaThingsFromNode($schema, $node, $parent);
216 47
        $functions = array();
217 47
218
        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...
219
            $node,
220
            function (
221
                DOMElement $node,
222
                DOMElement $childNode
223 47
            ) use (
224
                $schema,
225 47
                &$functions
226
            ) {
227
                $callback = null;
228
229
                switch ($childNode->localName) {
230
                    case 'attributeGroup':
231
                        $callback = $this->loadAttributeGroup($schema, $childNode);
232
                        break;
233 47
                    case 'include':
234
                    case 'import':
235 47
                        $callback = $this->loadImport($schema, $childNode);
236
                        break;
237
                    case 'element':
238
                        $callback = $this->loadElementDef($schema, $childNode);
239
                        break;
240
                    case 'attribute':
241
                        $callback = $this->loadAttributeDef($schema, $childNode);
242
                        break;
243
                    case 'group':
244
                        $callback = $this->loadGroup($schema, $childNode);
245 47
                        break;
246
                    case 'complexType':
247 47
                        $callback = $this->loadComplexType($schema, $childNode);
248 47
                        break;
249
                    case 'simpleType':
250 47
                        $callback = $this->loadSimpleType($schema, $childNode);
251 47
                        break;
252
                }
253
254
                if ($callback instanceof Closure) {
255
                    $functions[] = $callback;
256 47
                }
257
            }
258
        );
259 47
260
        return $functions;
261 47
    }
262 47
263 47
    private function loadGroupRef(Group $referenced, DOMElement $node): GroupRef
264 47
    {
265 47
        $ref = new GroupRef($referenced);
266 47
        $ref->setDoc($this->getDocumentation($node));
267 47
268 47
        self::maybeSetMax($ref, $node);
269 47
        self::maybeSetMin($ref, $node);
270 47
271 47
        return $ref;
272 47
    }
273 47
274 47
    private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
275 47
    {
276 47
        if (
277 47
            $node->hasAttribute('maxOccurs')
278 47
        ) {
279 47
            $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
280 47
        }
281 47
282 47
        return $ref;
283 47
    }
284 47
285
    private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax
286 47
    {
287 47
        if ($node->hasAttribute('minOccurs')) {
288 47
            $ref->setMin((int) $node->getAttribute('minOccurs'));
289 47
        }
290 47
291
        return $ref;
292 47
    }
293
294
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void
295
    {
296
        $max =
297
        (
298 47
            (is_int($max) && (bool) $max) ||
299
            $node->getAttribute('maxOccurs') == 'unbounded' ||
300 47
            $node->getAttribute('maxOccurs') > 1
301 47
        )
302
            ? 2
303 47
            : null;
304 47
305
        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...
306 47
            $node,
307
            function (
308
                DOMElement $node,
309
                DOMElement $childNode
310
            ) use (
311
                $elementContainer,
312 47
                $max
313
            ) {
314
                $this->loadSequenceChildNode(
315 47
                    $elementContainer,
316 47
                    $node,
317 47
                    $childNode,
318 47
                    $max
319
                );
320 47
            }
321
        );
322
    }
323
324
    /**
325
     * @param int|null $max
326 47
     */
327
    private function loadSequenceChildNode(
328 47
        ElementContainer $elementContainer,
329 47
        DOMElement $node,
330 47
        DOMElement $childNode,
331
        $max
332 47
    ): void {
333
        switch ($childNode->localName) {
334
            case 'sequence':
335
            case 'choice':
336
            case 'all':
337
                $this->loadSequence(
338 47
                    $elementContainer,
339
                    $childNode,
340
                    $max
341
                );
342 47
                break;
343 47
            case 'element':
344 47
                $this->loadSequenceChildNodeLoadElement(
345 47
                    $elementContainer,
346 47
                    $node,
347 47
                    $childNode,
348
                    $max
349 47
                );
350 47
                break;
351
            case 'group':
352
                $this->addGroupAsElement(
353
                    $elementContainer->getSchema(),
354
                    $node,
355 47
                    $childNode,
356 47
                    $elementContainer
357
                );
358 47
                break;
359 47
        }
360 47
    }
361 47
362
    /**
363 47
     * @param int|null $max
364 47
     */
365 47
    private function loadSequenceChildNodeLoadElement(
366 47
        ElementContainer $elementContainer,
367
        DOMElement $node,
368
        DOMElement $childNode,
369
        $max
370
    ): void {
371 47
        if ($childNode->hasAttribute('ref')) {
372
            $element = new ElementRef(
373
                $this->findElement($elementContainer->getSchema(), $node, $childNode->getAttribute('ref'))
374
            );
375
            $element->setDoc($this->getDocumentation($childNode));
376
377 47
            self::maybeSetMax($element, $childNode);
378 47
            self::maybeSetMin($element, $childNode);
379 47
            if ($childNode->hasAttribute('nillable')) {
380 47
                $element->setNil($childNode->getAttribute('nillable') == 'true');
381 47
            }
382 47
            if ($childNode->hasAttribute('form')) {
383 47
                $element->setQualified($childNode->getAttribute('form') == 'qualified');
384
            }
385 47
        } else {
386 47
            $element = $this->loadElement(
387 47
                $elementContainer->getSchema(),
388 47
                $childNode
389 47
            );
390 47
        }
391 47
        if ($max > 1) {
392
            /*
393 47
            * although one might think the typecast is not needed with $max being `? int $max` after passing > 1,
394 47
            * phpstan@a4f89fa still thinks it's possibly null.
395 47
            * see https://github.com/phpstan/phpstan/issues/577 for related issue
396 47
            */
397 47
            $element->setMax((int) $max);
398 47
        }
399 47
        $elementContainer->addElement($element);
400
    }
401 47
402 47
    private function addGroupAsElement(
403 47
        Schema $schema,
404 47
        DOMElement $node,
405
        DOMElement $childNode,
406
        ElementContainer $elementContainer
407
    ): void {
408
        $referencedGroup = $this->findGroup(
409 47
            $schema,
410
            $node,
411
            $childNode->getAttribute('ref')
412
        );
413
414
        $group = $this->loadGroupRef($referencedGroup, $childNode);
415 47
        $elementContainer->addElement($group);
416
    }
417
418
    private function loadGroup(Schema $schema, DOMElement $node): Closure
419 47
    {
420 47
        $group = new Group($schema, $node->getAttribute('name'));
421 47
        $group->setDoc($this->getDocumentation($node));
422
423 47
        if ($node->hasAttribute('maxOccurs')) {
424 47
            /**
425 47
             * @var GroupRef
426
             */
427
            $group = self::maybeSetMax(new GroupRef($group), $node);
428 47
        }
429
        if ($node->hasAttribute('minOccurs')) {
430
            /**
431 47
             * @var GroupRef
432 47
             */
433 47
            $group = self::maybeSetMin(
434
                $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 433 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...
435 47
                $node
436
            );
437 47
        }
438
439
        $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...
440
441
        return function () use ($group, $node) {
442
            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...
443 47
                $node,
444 47
                function (DOMelement $node, DOMElement $childNode) use ($group) {
445 47
                    switch ($childNode->localName) {
446 47
                        case 'sequence':
447
                        case 'choice':
448 47
                        case 'all':
449
                            $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...
450
                            break;
451
                    }
452
                }
453
            );
454
        };
455
    }
456
457 47
    private function loadComplexType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
458 47
    {
459 47
        /**
460 47
         * @var bool
461 47
         */
462 47
        $isSimple = false;
463
464 47
        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...
465 47
            $node,
466 47
            function (
467
                DOMElement $node,
468
                DOMElement $childNode
469
            ) use (
470
                &$isSimple
471 47
            ) {
472
                if ($isSimple) {
473 47
                    return;
474 47
                }
475
                if ($childNode->localName === 'simpleContent') {
476 47
                    $isSimple = true;
477
                }
478
            }
479
        );
480
481
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name'));
482 47
483
        $type->setDoc($this->getDocumentation($node));
484
        if ($node->getAttribute('name')) {
485
            $schema->addType($type);
486
        }
487
488
        return function () use ($type, $node, $schema, $callback) {
489
            $this->fillTypeNode($type, $node, true);
490
491
            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...
492 47
                $node,
493
                function (
494
                    DOMElement $node,
495 47
                    DOMElement $childNode
496 47
                ) use (
497
                    $schema,
498 47
                    $type
499 47
                ) {
500 47
                    $this->loadComplexTypeFromChildNode(
501 47
                        $type,
502 47
                        $node,
503 47
                        $childNode,
504 47
                        $schema
505 47
                    );
506 47
                }
507 47
            );
508
509
            if ($callback instanceof Closure) {
510
                call_user_func($callback, $type);
511
            }
512
        };
513
    }
514
515 47
    private function loadComplexTypeFromChildNode(
516
        BaseComplexType $type,
517
        DOMElement $node,
518
        DOMElement $childNode,
519
        Schema $schema
520 47
    ): void {
521
        switch ($childNode->localName) {
522 47
            case 'sequence':
523 47
            case 'choice':
524
            case 'all':
525
                if ($type instanceof ElementContainer) {
526
                    $this->loadSequence(
527
                        $type,
528
                        $childNode
529
                    );
530 47
                }
531 1
                break;
532
            case 'attribute':
533 47
                $this->addAttributeFromAttributeOrRef(
534 2
                    $type,
535 2
                    $childNode,
536 47
                    $schema,
537 47
                    $node
538
                );
539 47
                break;
540
            case 'attributeGroup':
541 47
                $this->findSomethingLikeAttributeGroup(
542 47
                    $schema,
543 47
                    $node,
544 47
                    $childNode,
545
                    $type
546
                );
547 47
                break;
548
            case 'group':
549 47
                if (
550 47
                    $type instanceof ComplexType
551
                ) {
552
                    $this->addGroupAsElement(
553
                        $schema,
554
                        $node,
555 47
                        $childNode,
556 47
                        $type
557
                    );
558 47
                }
559 47
                break;
560 47
        }
561 47
    }
562
563 47
    private function loadSimpleType(Schema $schema, DOMElement $node, Closure $callback = null): Closure
564 47
    {
565 47
        $type = new SimpleType($schema, $node->getAttribute('name'));
566
        $type->setDoc($this->getDocumentation($node));
567 47
        if ($node->getAttribute('name')) {
568 47
            $schema->addType($type);
569 47
        }
570 47
571
        return function () use ($type, $node, $callback) {
572
            $this->fillTypeNode($type, $node, true);
573 47
574
            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...
575
                $node,
576
                function (DOMElement $node, DOMElement $childNode) use ($type) {
577
                    switch ($childNode->localName) {
578
                        case 'union':
579 47
                            $this->loadUnion($type, $childNode);
580 47
                            break;
581 47
                        case 'list':
582 47
                            $this->loadList($type, $childNode);
583 47
                            break;
584 47
                    }
585 47
                }
586
            );
587 47
588 47
            if ($callback instanceof Closure) {
589 47
                call_user_func($callback, $type);
590 47
            }
591 47
        };
592 47
    }
593 47
594 47
    private function loadList(SimpleType $type, DOMElement $node): void
595
    {
596 47
        if ($node->hasAttribute('itemType')) {
597 47
            /**
598 47
             * @var SimpleType
599 2
             */
600 2
            $listType = $this->findSomeType($type, $node, 'itemType');
601 2
            $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...
602 2
        } else {
603
            self::againstDOMNodeList(
604 2
                $node,
605 2
                function (
606 47
                    DOMElement $node,
607
                    DOMElement $childNode
608
                ) use (
609 1
                    $type
610 1
                ) {
611 1
                    $this->loadTypeWithCallback(
612 1
                        $type->getSchema(),
613 1
                        $childNode,
614
                        function (SimpleType $list) use ($type) {
615 1
                            $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...
616 1
                        }
617 1
                    );
618 47
                }
619 47
            );
620
        }
621
    }
622
623
    private function findSomeType(
624
        SchemaItem $fromThis,
625
        DOMElement $node,
626 47
        string $attributeName
627
    ): SchemaItem {
628 47
        return $this->findSomeTypeFromAttribute(
629 47
            $fromThis,
630 47
            $node,
631 47
            $node->getAttribute($attributeName)
632 47
        );
633
    }
634
635 47
    private function findSomeTypeFromAttribute(
636
        SchemaItem $fromThis,
637 47
        DOMElement $node,
638 47
        string $attributeName
639
    ): SchemaItem {
640 47
        $out = $this->findType(
641 47
            $fromThis->getSchema(),
642 47
            $node,
643 47
            $attributeName
644 47
        );
645 47
646 47
        return $out;
647 47
    }
648 47
649 47
    private function loadUnion(SimpleType $type, DOMElement $node): void
650
    {
651 47
        if ($node->hasAttribute('memberTypes')) {
652 47
            $types = preg_split('/\s+/', $node->getAttribute('memberTypes'));
653 47
            foreach ($types as $typeName) {
654 47
                /**
655
                 * @var SimpleType
656
                 */
657 47
                $unionType = $this->findSomeTypeFromAttribute(
658
                    $type,
659 47
                    $node,
660
                    $typeName
661
                );
662
                $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...
663 47
            }
664 47
        }
665 47
        self::againstDOMNodeList(
666 47
            $node,
667 47
            function (
668
                DOMElement $node,
669
                DOMElement $childNode
670
            ) use (
671
                $type
672 47
            ) {
673
                $this->loadTypeWithCallback(
674 47
                    $type->getSchema(),
675 47
                    $childNode,
676 47
                    function (SimpleType $unType) use ($type) {
677
                        $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...
678 47
                    }
679 47
                );
680 47
            }
681 47
        );
682 47
    }
683
684 47
    private function fillTypeNode(Type $type, DOMElement $node, bool $checkAbstract = false): void
685
    {
686
        if ($checkAbstract) {
687
            $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1');
688
        }
689
690
        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...
691 47
            $node,
692
            function (DOMElement $node, DOMElement $childNode) use ($type) {
693
                switch ($childNode->localName) {
694
                    case 'restriction':
695
                        $this->loadRestriction($type, $childNode);
696 47
                        break;
697 47
                    case 'extension':
698 47
                        if ($type instanceof BaseComplexType) {
699 47
                            $this->loadExtension($type, $childNode);
700 47
                        }
701
                        break;
702
                    case 'simpleContent':
703
                    case 'complexContent':
704
                        $this->fillTypeNode($type, $childNode);
705
                        break;
706
                }
707
            }
708 47
        );
709
    }
710
711
    private function loadExtension(BaseComplexType $type, DOMElement $node): void
712
    {
713
        $extension = new Extension();
714
        $type->setExtension($extension);
715
716 47
        if ($node->hasAttribute('base')) {
717 47
            $this->findAndSetSomeBase(
718 47
                $type,
719 47
                $extension,
720
                $node
721 47
            );
722
        }
723 47
        $this->loadExtensionChildNodes($type, $node);
724
    }
725
726 47
    private function findAndSetSomeBase(
727
        Type $type,
728 47
        Base $setBaseOnThis,
729 47
        DOMElement $node
730 47
    ): void {
731
        /**
732
         * @var Type
733
         */
734 47
        $parent = $this->findSomeType($type, $node, 'base');
735 47
        $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...
736 47
    }
737
738 47
    private function loadExtensionChildNodes(
739 47
        BaseComplexType $type,
740 47
        DOMElement $node
741 47
    ) {
742 47
        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...
743 47
            $node,
744
            function (
745
                DOMElement $node,
746
                DOMElement $childNode
747
            ) use (
748 47
                $type
749
            ) {
750 47
                switch ($childNode->localName) {
751 47
                    case 'sequence':
752 47
                    case 'choice':
753
                    case 'all':
754 47
                        if ($type instanceof ElementContainer) {
755 47
                            $this->loadSequence(
756 47
                                $type,
757 47
                                $childNode
758 47
                            );
759 47
                        }
760
                        break;
761
                    case 'attribute':
762
                        $this->addAttributeFromAttributeOrRef(
763
                            $type,
764 47
                            $childNode,
765
                            $type->getSchema(),
766 47
                            $node
767 47
                        );
768 47
                        break;
769
                    case 'attributeGroup':
770 47
                        $this->findSomethingLikeAttributeGroup(
771 47
                            $type->getSchema(),
772
                            $node,
773 47
                            $childNode,
774 47
                            $type
775 47
                        );
776 47
                        break;
777 47
                }
778 47
            }
779 47
        );
780 47
    }
781 47
782 47
    private function loadRestriction(Type $type, DOMElement $node): void
783 47
    {
784 47
        $restriction = new Restriction();
785 47
        $type->setRestriction($restriction);
786 47
        if ($node->hasAttribute('base')) {
787 47
            $this->findAndSetSomeBase($type, $restriction, $node);
788 47
        } else {
789 47
            self::againstDOMNodeList(
790
                $node,
791 47
                function (
792
                    DOMElement $node,
793 47
                    DOMElement $childNode
794 47
                ) use (
795
                    $type,
796 47
                    $restriction
797 47
                ) {
798 47
                    $this->loadTypeWithCallback(
799 47
                        $type->getSchema(),
800
                        $childNode,
801 47
                        function (Type $restType) use ($restriction) {
802 47
                            $restriction->setBase($restType);
803 47
                        }
804 47
                    );
805
                }
806 47
            );
807
        }
808
        self::againstDOMNodeList(
809
            $node,
810
            function (
811
                DOMElement $node,
812
                DOMElement $childNode
813
            ) use (
814 47
                $restriction
815 47
            ) {
816 47
                if (
817
                    in_array(
818 47
                        $childNode->localName,
819
                        [
820
                            'enumeration',
821
                            'pattern',
822 47
                            'length',
823 47
                            'minLength',
824
                            'maxLength',
825
                            'minInclusive',
826
                            'maxInclusive',
827
                            'minExclusive',
828 47
                            'maxExclusive',
829
                            'fractionDigits',
830 47
                            'totalDigits',
831 47
                            'whiteSpace',
832 47
                        ],
833 47
                        true
834 47
                    )
835 47
                ) {
836 47
                    $restriction->addCheck(
837
                        $childNode->localName,
838 47
                        [
839 47
                            'value' => $childNode->getAttribute('value'),
840 47
                            'doc' => $this->getDocumentation($childNode),
841 47
                        ]
842 47
                    );
843 47
                }
844 47
            }
845 47
        );
846
    }
847 47
848 47
    /**
849 47
     * @return mixed[]
850 47
     */
851 47
    private static function splitParts(DOMElement $node, string $typeName): array
852 47
    {
853 47
        $prefix = null;
854
        $name = $typeName;
855 47
        if (strpos($typeName, ':') !== false) {
856 47
            list($prefix, $name) = explode(':', $typeName);
857 47
        }
858 47
859 47
        $namespace = $node->lookupNamespaceUri($prefix ?: '');
860 47
861
        return array(
862 47
            $name,
863
            $namespace,
864 47
            $prefix,
865 47
        );
866 47
    }
867 47
868 47
    private function findAttributeItem(Schema $schema, DOMElement $node, string $typeName): AttributeItem
869 47
    {
870 47
        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...
871
872
        $namespace = $namespace ?: $schema->getTargetNamespace();
873
874
        try {
875 47
            return $schema->findAttribute($name, $namespace);
876 47
        } catch (TypeNotFoundException $e) {
877
            throw new TypeException(
878 47
                sprintf(
879 47
                    "Can't find %s named {%s}#%s, at line %d in %s ",
880 47
                    'attribute',
881
                    $namespace,
882 47
                    $name,
883 47
                    $node->getLineNo(),
884 47
                    $node->ownerDocument->documentURI
885 47
                ),
886 47
                0,
887
                $e
888 47
            );
889 47
        }
890
    }
891
892
    private function findAttributeGroup(Schema $schema, DOMElement $node, string $typeName): AttributeGroup
893
    {
894 47
        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...
895
896
        $namespace = $namespace ?: $schema->getTargetNamespace();
897 47
898 47
        try {
899
            return $schema->findAttributeGroup($name, $namespace);
900 47
        } catch (TypeNotFoundException $e) {
901 47
            throw new TypeException(
902 47
                sprintf(
903 47
                    "Can't find %s named {%s}#%s, at line %d in %s ",
904 47
                    'attributegroup',
905 47
                    $namespace,
906 47
                    $name,
907 47
                    $node->getLineNo(),
908 47
                    $node->ownerDocument->documentURI
909 47
                ),
910 47
                0,
911 47
                $e
912 47
            );
913
        }
914 47
    }
915 47
916 47
    private function findElement(Schema $schema, DOMElement $node, string $typeName): ElementDef
917 47
    {
918
        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...
919 47
920 47
        $namespace = $namespace ?: $schema->getTargetNamespace();
921
922 47
        try {
923 47
            return $schema->findElement($name, $namespace);
924 47
        } catch (TypeNotFoundException $e) {
925 47
            throw new TypeException(
926 47
                sprintf(
927
                    "Can't find %s named {%s}#%s, at line %d in %s ",
928
                    'element',
929
                    $namespace,
930
                    $name,
931
                    $node->getLineNo(),
932
                    $node->ownerDocument->documentURI
933 47
                ),
934
                0,
935 47
                $e
936 47
            );
937 47
        }
938 47
    }
939 47
940
    private function findGroup(Schema $schema, DOMElement $node, string $typeName): Group
941 47
    {
942
        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...
943
944 47
        $namespace = $namespace ?: $schema->getTargetNamespace();
945 47
946 47
        try {
947 47
            return $schema->findGroup($name, $namespace);
948
        } catch (TypeNotFoundException $e) {
949
            throw new TypeException(
950
                sprintf(
951
                    "Can't find %s named {%s}#%s, at line %d in %s ",
952
                    'group',
953
                    $namespace,
954
                    $name,
955
                    $node->getLineNo(),
956
                    $node->ownerDocument->documentURI
957
                ),
958
                0,
959
                $e
960 47
            );
961
        }
962 47
    }
963
964
    private function findType(Schema $schema, DOMElement $node, string $typeName): SchemaItem
965
    {
966
        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...
967 47
968
        $namespace = $namespace ?: $schema->getTargetNamespace();
969
970
        try {
971
            return $schema->findType($name, $namespace);
972
        } catch (TypeNotFoundException $e) {
973 47
            throw new TypeException(
974
                sprintf(
975 47
                    "Can't find %s named {%s}#%s, at line %d in %s ",
976
                    'type',
977
                    $namespace,
978
                    $name,
979
                    $node->getLineNo(),
980
                    $node->ownerDocument->documentURI
981
                ),
982
                0,
983
                $e
984 47
            );
985
        }
986 47
    }
987
988
    /**
989 47
     * @return Closure
990
     */
991
    private function loadElementDef(Schema $schema, DOMElement $node): Closure
992
    {
993
        return $this->loadAttributeOrElementDef($schema, $node, false);
994 47
    }
995 47
996 47
    private function fillItem(Item $element, DOMElement $node)
997
    {
998
        /**
999
         * @var bool
1000
         */
1001 47
        $skip = false;
1002
        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...
1003
            $node,
1004
            function (
1005 47
                DOMElement $node,
1006 47
                DOMElement $childNode
1007 47
            ) use (
1008
                $element,
1009 47
                &$skip
1010 47
            ) {
1011
                if (
1012 47
                    !$skip &&
1013 47
                    in_array(
1014 47
                        $childNode->localName,
1015 47
                        [
1016 47
                            'complexType',
1017
                            'simpleType',
1018 47
                        ],
1019 47
                        true
1020 47
                    )
1021 47
                ) {
1022 47
                    $this->loadTypeWithCallback(
1023 47
                        $element->getSchema(),
1024 47
                        $childNode,
1025 47
                        function (Type $type) use ($element) {
1026 47
                            $element->setType($type);
1027
                        }
1028 47
                    );
1029 47
                    $skip = true;
1030
                }
1031 47
            }
1032
        );
1033 47
        if ($skip) {
1034
            return;
1035
        }
1036
        $this->fillItemNonLocalType($element, $node);
1037 47
    }
1038 47
1039
    private function fillItemNonLocalType(Item $element, DOMElement $node): void
1040
    {
1041
        if ($node->getAttribute('type')) {
1042 47
            /**
1043 47
             * @var Type
1044 47
             */
1045 47
            $type = $this->findSomeType($element, $node, 'type');
1046 47
        } else {
1047
            /**
1048
             * @var Type
1049 47
             */
1050 47
            $type = $this->findSomeTypeFromAttribute(
1051
                $element,
1052
                $node,
1053
                ($node->lookupPrefix(self::XSD_NS).':anyType')
1054
            );
1055 47
        }
1056
1057
        $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...
1058
    }
1059 47
1060 47
    private function loadImport(
1061
        Schema $schema,
1062 47
        DOMElement $node
1063
    ): Closure {
1064 47
        $base = urldecode($node->ownerDocument->documentURI);
1065
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));
1066 47
1067 47
        $namespace = $node->getAttribute('namespace');
1068 47
1069
        $keys = $this->loadImportFreshKeys($namespace, $file);
1070
1071 47
        foreach ($keys as $key) {
1072
            if (isset($this->loadedFiles[$key])) {
1073 1
                $schema->addSchema($this->loadedFiles[$key]);
0 ignored issues
show
Documentation introduced by
$this->loadedFiles[$key] 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...
1074
1075 1
                return function () {
1076
                };
1077
            }
1078
        }
1079
1080
        return $this->loadImportFresh($namespace, $schema, $file);
1081
    }
1082
1083
    /**
1084 47
     * @return string[]
1085
     */
1086
    private function loadImportFreshKeys(
1087
        string $namespace,
1088 47
        string $file
1089
    ): array {
1090 47
        $globalSchemaInfo = $this->getGlobalSchemaInfo();
1091
1092 47
        $keys = [];
1093 47
1094 47
        if (isset($globalSchemaInfo[$namespace])) {
1095
            $keys[] = $globalSchemaInfo[$namespace];
1096 47
        }
1097 47
1098
        $keys[] = $this->getNamespaceSpecificFileIndex(
1099 47
            $file,
1100
            $namespace
1101 47
        );
1102
1103 47
        $keys[] = $file;
1104
1105
        return $keys;
1106
    }
1107
1108
    private function loadImportFreshCallbacksNewSchema(
1109
        string $namespace,
1110
        Schema $schema,
1111
        string $file
1112 1
    ): Schema {
1113
        /**
1114
         * @var Schema $newSchema
1115
         */
1116
        $newSchema = $this->setLoadedFile(
1117
            $file,
1118
            (('' !== trim($namespace)) ? new Schema() : $schema)
1119
        );
1120 1
1121 1
        if ('' !== trim($namespace)) {
1122 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...
1123 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...
1124
        }
1125 1
1126
        return $newSchema;
1127
    }
1128
1129
    /**
1130 1
     * @return Closure[]
1131
     */
1132
    private function loadImportFreshCallbacks(
1133
        string $namespace,
1134
        Schema $schema,
1135
        string $file
1136
    ): array {
1137
        /**
1138
         * @var string
1139 1
         */
1140
        $file = $file;
0 ignored issues
show
Bug introduced by
Why assign $file to itself?

This checks looks for cases where a variable has been assigned to itself.

This assignement can be removed without consequences.

Loading history...
1141
1142
        return $this->schemaNode(
1143
            $this->loadImportFreshCallbacksNewSchema(
1144
                $namespace,
1145
                $schema,
1146
                $file
1147 1
            ),
1148
            $this->getDOM(
1149 1
                isset($this->knownLocationSchemas[$file])
1150 1
                    ? $this->knownLocationSchemas[$file]
1151 1
                    : $file
1152 1
            )->documentElement,
1153
            $schema
1154 1
        );
1155 1
    }
1156 1
1157 1
    private function loadImportFresh(
1158
        string $namespace,
1159 1
        Schema $schema,
1160
        string $file
1161 1
    ): Closure {
1162
        return function () use ($namespace, $schema, $file) {
1163
            foreach (
1164
                $this->loadImportFreshCallbacks(
1165
                    $namespace,
1166
                    $schema,
1167
                    $file
1168
                ) as $callback
1169
            ) {
1170
                $callback();
1171
            }
1172
        };
1173
    }
1174
1175 1
    /**
1176
     * @var Schema|null
1177 1
     */
1178 1
    protected $globalSchema;
1179 1
1180
    /**
1181 1
     * @return string[]
1182 1
     */
1183 1
    public function getGlobalSchemaInfo(): array
1184 1
    {
1185 1
        return self::$globalSchemaInfo;
1186
    }
1187
1188
    /**
1189
     * @return Schema
1190
     */
1191
    public function getGlobalSchema(): Schema
1192
    {
1193
        if (!($this->globalSchema instanceof Schema)) {
1194
            $callbacks = array();
1195
            $globalSchemas = array();
1196 47
            /**
1197
             * @var string $namespace
1198 47
             */
1199
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
1200
                $this->setLoadedFile(
1201
                    $uri,
1202
                    $globalSchemas[$namespace] = $schema = new Schema()
1203
                );
1204 47
                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...
1205
                    $this->globalSchema = $schema;
1206 47
                }
1207 47
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
1208 47
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
1209
            }
1210
1211
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType'));
1212 47
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType'));
1213 47
1214 47
            $globalSchemas[(string) static::XML_NS]->addSchema(
1215 47
                $globalSchemas[(string) static::XSD_NS],
1216 47
                (string) static::XSD_NS
1217 47
            );
1218 47
            $globalSchemas[(string) static::XSD_NS]->addSchema(
1219 47
                $globalSchemas[(string) static::XML_NS],
1220 47
                (string) static::XML_NS
1221 47
            );
1222 47
1223
            /**
1224 47
             * @var Closure
1225 47
             */
1226
            foreach ($callbacks as $callback) {
1227 47
                $callback();
1228 47
            }
1229
        }
1230 47
1231 47
        /**
1232 47
         * @var Schema
1233
         */
1234 47
        $out = $this->globalSchema;
1235
1236
        if (!($out instanceof Schema)) {
1237
            throw new TypeException('Globa schema not discoverd');
1238
        }
1239 47
1240 47
        return $out;
1241 47
    }
1242 47
1243
    private function readNode(DOMElement $node, string $file = 'schema.xsd'): Schema
1244
    {
1245
        $fileKey = $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file;
1246
        $this->setLoadedFile($fileKey, $rootSchema = new Schema());
1247 47
1248
        $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...
1249 47
        $callbacks = $this->schemaNode($rootSchema, $node);
1250
1251
        foreach ($callbacks as $callback) {
1252
            call_user_func($callback);
1253
        }
1254
1255
        return $rootSchema;
1256
    }
1257
1258 47
    /**
1259
     * It is possible that a single file contains multiple <xsd:schema/> nodes, for instance in a WSDL file.
1260 47
     *
1261 47
     * Each of these  <xsd:schema/> nodes typically target a specific namespace. Append the target namespace to the
1262
     * file to distinguish between multiple schemas in a single file.
1263 47
     */
1264 47
    private function getNamespaceSpecificFileIndex(string $file, string $targetNamespace): string
1265
    {
1266 47
        return $file.'#'.$targetNamespace;
1267 41
    }
1268 47
1269
    /**
1270 47
     * @throws IOException
1271
     */
1272
    public function readString(string $content, string $file = 'schema.xsd'): Schema
1273
    {
1274
        $xml = new DOMDocument('1.0', 'UTF-8');
1275
        if (!$xml->loadXML($content)) {
1276
            throw new IOException("Can't load the schema");
1277
        }
1278
        $xml->documentURI = $file;
1279
1280
        return $this->readNode($xml->documentElement, $file);
1281
    }
1282
1283
    public function readFile(string $file): Schema
1284 47
    {
1285
        $xml = $this->getDOM($file);
1286 47
1287
        return $this->readNode($xml->documentElement, $file);
1288
    }
1289
1290
    /**
1291
     * @throws IOException
1292
     */
1293
    private function getDOM(string $file): DOMDocument
1294
    {
1295
        $xml = new DOMDocument('1.0', 'UTF-8');
1296
        if (!$xml->load($file)) {
1297 46
            throw new IOException("Can't load the file $file");
1298
        }
1299 46
1300 46
        return $xml;
1301
    }
1302
1303 46
    private static function againstDOMNodeList(
1304
        DOMElement $node,
1305 46
        Closure $againstNodeList
1306
    ) {
1307
        $limit = $node->childNodes->length;
1308
        for ($i = 0; $i < $limit; $i += 1) {
1309
            /**
1310
             * @var DOMNode
1311
             */
1312
            $childNode = $node->childNodes->item($i);
1313 1
1314
            if ($childNode instanceof DOMElement) {
1315 1
                $againstNodeList(
1316
                    $node,
1317 1
                    $childNode
1318
                );
1319
            }
1320
        }
1321
    }
1322
1323
    private function loadTypeWithCallback(
1324
        Schema $schema,
1325
        DOMElement $childNode,
1326
        Closure $callback
1327 47
    ) {
1328
        /**
1329 47
         * @var Closure|null $func
1330 47
         */
1331
        $func = null;
1332
1333
        switch ($childNode->localName) {
1334 47
            case 'complexType':
1335
                $func = $this->loadComplexType($schema, $childNode, $callback);
1336
                break;
1337 47
            case 'simpleType':
1338
                $func = $this->loadSimpleType($schema, $childNode, $callback);
1339
                break;
1340
        }
1341 47
1342 47
        if ($func instanceof Closure) {
1343
            call_user_func($func);
1344
        }
1345
    }
1346 47
1347
    private function loadElement(
1348 47
        Schema $schema,
1349 47
        DOMElement $node
1350 47
    ): Element {
1351
        $element = new Element($schema, $node->getAttribute('name'));
1352 47
        $element->setDoc($this->getDocumentation($node));
1353 47
1354 47
        $this->fillItem($element, $node);
1355 47
1356
        self::maybeSetMax($element, $node);
1357 47
        self::maybeSetMin($element, $node);
1358
1359
        $xp = new \DOMXPath($node->ownerDocument);
1360
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
1361
1362
        if ($xp->query('ancestor::xs:choice', $node)->length) {
1363
            $element->setMin(0);
1364
        }
1365 47
1366
        if ($node->hasAttribute('nillable')) {
1367 47
            $element->setNil($node->getAttribute('nillable') == 'true');
1368 47
        }
1369 47
        if ($node->hasAttribute('form')) {
1370 47
            $element->setQualified($node->getAttribute('form') == 'qualified');
1371 47
        }
1372 47
1373 47
        return $element;
1374 47
    }
1375
1376 47
    private function addAttributeFromAttributeOrRef(
1377 47
        BaseComplexType $type,
1378 47
        DOMElement $childNode,
1379 47
        Schema $schema,
1380
        DOMElement $node
1381
    ): void {
1382
        $attribute = $this->getAttributeFromAttributeOrRef(
1383
            $childNode,
1384 47
            $schema,
1385
            $node
1386
        );
1387
1388 47
        $type->addAttribute($attribute);
1389 47
    }
1390
1391 47
    private function findSomethingLikeAttributeGroup(
1392
        Schema $schema,
1393 47
        DOMElement $node,
1394 47
        DOMElement $childNode,
1395
        AttributeContainer $addToThis
1396 47
    ): void {
1397 47
        $attribute = $this->findAttributeGroup($schema, $node, $childNode->getAttribute('ref'));
1398
        $addToThis->addAttribute($attribute);
1399 47
    }
1400 47
1401 47
    private function setLoadedFile(string $key, Schema $schema): Schema
1402
    {
1403 47
        $this->loadedFiles[$key] = $schema;
1404 3
1405 3
        return $schema;
1406 47
    }
1407 3
1408 3
    private function setSchemaThingsFromNode(
1409
        Schema $schema,
1410 47
        DOMElement $node,
1411
        Schema $parent = null
1412
    ): void {
1413 47
        $schema->setDoc($this->getDocumentation($node));
1414
1415
        if ($node->hasAttribute('targetNamespace')) {
1416
            $schema->setTargetNamespace($node->getAttribute('targetNamespace'));
1417
        } elseif ($parent instanceof Schema) {
1418
            $schema->setTargetNamespace($parent->getTargetNamespace());
1419 47
        }
1420 47
        $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
1421 47
        $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
1422
        $schema->setDoc($this->getDocumentation($node));
1423 47
    }
1424
}
1425