Completed
Pull Request — master (#30)
by Asmir
02:53 queued 01:31
created

SchemaReader::setLoadedFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1097
1098 58
            return function () {
1099 58
            };
1100
        }
1101
1102 2
        return $this->loadImportFresh($namespace, $schema, $file);
1103
    }
1104
1105 2
    private function createOrUseSchemaForNs(
1106
        Schema $schema,
1107
        string $namespace
1108
    ): Schema {
1109 2
        if (('' !== trim($namespace))) {
1110 1
            $newSchema = new Schema();
1111 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...
1112 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...
1113
        } else {
1114 1
            $newSchema = $schema;
1115
        }
1116
1117 2
        return $newSchema;
1118
    }
1119
1120
    private function loadImportFresh(
1121
        string $namespace,
1122
        Schema $schema,
1123
        string $file
1124
    ): Closure {
1125 2
        return function () use ($namespace, $schema, $file) {
1126 2
            $dom = $this->getDOM(
1127 2
                isset($this->knownLocationSchemas[$file])
1128 1
                    ? $this->knownLocationSchemas[$file]
1129 2
                    : $file
1130
            );
1131
1132 2
            $schemaNew = $this->createOrUseSchemaForNs($schema, $namespace);
1133
1134 2
            $this->setLoadedFile($file, $schemaNew);
1135
1136 2
            $callbacks = $this->schemaNode($schemaNew, $dom->documentElement, $schema);
1137
1138 2
            foreach ($callbacks as $callback) {
1139 2
                $callback();
1140
            }
1141 2
        };
1142
    }
1143
1144
    /**
1145
     * @var Schema|null
1146
     */
1147
    protected $globalSchema;
1148
1149
    /**
1150
     * @return Schema
1151
     */
1152 58
    public function getGlobalSchema(): Schema
1153
    {
1154 58
        if (!($this->globalSchema instanceof Schema)) {
1155 58
            $callbacks = array();
1156 58
            $globalSchemas = array();
1157
            /**
1158
             * @var string $namespace
1159
             */
1160 58
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
1161 58
                $this->setLoadedFile(
1162 58
                    $uri,
1163 58
                    $globalSchemas[$namespace] = $schema = new Schema()
1164
                );
1165 58
                $this->setLoadedSchema($namespace, $schema);
1166 58
                if ($namespace === self::XSD_NS) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $namespace (integer) and self::XSD_NS (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1167 58
                    $this->globalSchema = $schema;
1168
                }
1169 58
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
1170 58
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
1171
            }
1172
1173 58
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType'));
1174 58
            $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType'));
1175
1176 58
            $globalSchemas[(string)static::XML_NS]->addSchema(
1177 58
                $globalSchemas[(string)static::XSD_NS],
1178 58
                (string)static::XSD_NS
1179
            );
1180 58
            $globalSchemas[(string)static::XSD_NS]->addSchema(
1181 58
                $globalSchemas[(string)static::XML_NS],
1182 58
                (string)static::XML_NS
1183
            );
1184
1185
            /**
1186
             * @var Closure
1187
             */
1188 58
            foreach ($callbacks as $callback) {
1189 58
                $callback();
1190
            }
1191
        }
1192
1193
        /**
1194
         * @var Schema
1195
         */
1196 58
        $out = $this->globalSchema;
1197
1198 58
        if (!($out instanceof Schema)) {
1199
            throw new TypeException('Globa schema not discoverd');
1200
        }
1201
1202 58
        return $out;
1203
    }
1204
1205 1
    public function readNodes(array $nodes, string $file = null)
1206
    {
1207 1
        $rootSchema = new Schema();
1208 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...
1209
1210 1
        if ($file !== null) {
1211 1
            $this->setLoadedFile($file, $rootSchema);
1212
        }
1213
1214 1
        $all = array();
1215 1
        foreach ($nodes as $k => $node) {
1216 1
            if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') {
1217 1
                $holderSchema = new Schema();
1218 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...
1219
1220 1
                $this->setLoadedSchemaFromElement($node, $holderSchema);
1221
1222 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...
1223
1224 1
                $callbacks = $this->schemaNode($holderSchema, $node);
1225 1
                $all = array_merge($callbacks, $all);
1226
            }
1227
        }
1228
1229 1
        foreach ($all as $callback) {
1230 1
            call_user_func($callback);
1231
        }
1232
1233 1
        return $rootSchema;
1234
    }
1235
1236 57
    public function readNode(DOMElement $node, string $file = null): Schema
1237
    {
1238 57
        $rootSchema = new Schema();
1239 57
        $rootSchema->addSchema($this->getGlobalSchema());
0 ignored issues
show
Documentation introduced by
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema>, but the function expects a object<self>.

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

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

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

function acceptsInteger($int) { }

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

// Instead of
acceptsInteger($x);

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