Completed
Pull Request — master (#17)
by
unknown
04:41
created

SchemaReader::schemaNode()   C

Complexity

Conditions 13
Paths 33

Size

Total Lines 46
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 41
CRAP Score 13

Importance

Changes 0
Metric Value
dl 0
loc 46
ccs 41
cts 41
cp 1
rs 5.1118
c 0
b 0
f 0
cc 13
eloc 38
nc 33
nop 3
crap 13

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace GoetasWebservices\XML\XSDReader;
3
4
use DOMDocument;
5
use DOMElement;
6
use DOMNode;
7
use GoetasWebservices\XML\XSDReader\Exception\IOException;
8
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
9
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
10
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
11
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeRef;
12
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
13
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
14
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
15
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
16
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
17
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
18
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
19
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
20
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
21
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
22
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
23
use GoetasWebservices\XML\XSDReader\Schema\Item;
24
use GoetasWebservices\XML\XSDReader\Schema\Schema;
25
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
26
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
27
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
28
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
29
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
30
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
31
32
class SchemaReader
33
{
34
35
    const XSD_NS = "http://www.w3.org/2001/XMLSchema";
36
37
    const XML_NS = "http://www.w3.org/XML/1998/namespace";
38
39
    private $loadedFiles = array();
40
41
    private $knownLocationSchemas = array();
42
43
    private static $globalSchemaInfo = array(
44
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
45
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd'
46
    );
47
48 54
    public function __construct()
49
    {
50 54
        $this->addKnownSchemaLocation('http://www.w3.org/2001/xml.xsd', __DIR__ . '/Resources/xml.xsd');
51 54
        $this->addKnownSchemaLocation('http://www.w3.org/2001/XMLSchema.xsd', __DIR__ . '/Resources/XMLSchema.xsd');
52 54
        $this->addKnownSchemaLocation('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd', __DIR__ . '/Resources/oasis-200401-wss-wssecurity-secext-1.0.xsd');
53 54
        $this->addKnownSchemaLocation('http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', __DIR__ . '/Resources/oasis-200401-wss-wssecurity-utility-1.0.xsd');
54 54
        $this->addKnownSchemaLocation('https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__ . '/Resources/xmldsig-core-schema.xsd');
55 54
        $this->addKnownSchemaLocation('http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__ . '/Resources/xmldsig-core-schema.xsd');
56 54
    }
57
58 54
    public function addKnownSchemaLocation($remote, $local)
59
    {
60 54
        $this->knownLocationSchemas[$remote] = $local;
61 54
    }
62
63 45
    private function loadAttributeGroup(Schema $schema, DOMElement $node)
64
    {
65 45
        $attGroup = new AttributeGroup($schema, $node->getAttribute("name"));
66 45
        $attGroup->setDoc($this->getDocumentation($node));
67 45
        $schema->addAttributeGroup($attGroup);
68
69
        return function () use ($schema, $node, $attGroup) {
70 45
            foreach ($node->childNodes as $childNode) {
71 45
                switch ($childNode->localName) {
72 45 View Code Duplication
                    case 'attribute':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
73 45
                        if ($childNode->hasAttribute("ref")) {
74 45
                            $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
75 45
                        } else {
76 45
                            $attribute = $this->loadAttribute($schema, $childNode);
77
                        }
78 45
                        $attGroup->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 74 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...e\Group::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, 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...
79 45
                        break;
80 45 View Code Duplication
                    case 'attributeGroup':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
81
82 1
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
83 1
                        $attGroup->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 82 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...e\Group::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, 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...
84 1
                        break;
85 45
                }
86 45
            }
87 45
        };
88
    }
89
90 45
    private function loadAttribute(Schema $schema, DOMElement $node)
91
    {
92 45
        $attribute = new Attribute($schema, $node->getAttribute("name"));
93 45
        $attribute->setDoc($this->getDocumentation($node));
94 45
        $this->fillItem($attribute, $node);
95
96 45
        if ($node->hasAttribute("nillable")) {
97 1
            $attribute->setNil($node->getAttribute("nillable") == "true");
98 1
        }
99 45
        if ($node->hasAttribute("form")) {
100 1
            $attribute->setQualified($node->getAttribute("form") == "qualified");
101 1
        }
102 45
        if ($node->hasAttribute("use")) {
103 45
            $attribute->setUse($node->getAttribute("use"));
104 45
        }
105 45
        return $attribute;
106
    }
107
108
109 45 View Code Duplication
    private function loadAttributeDef(Schema $schema, DOMElement $node)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
110
    {
111 45
        $attribute = new AttributeDef($schema, $node->getAttribute("name"));
112
113 45
        $schema->addAttribute($attribute);
114
115
        return function () use ($attribute, $schema, $node) {
116 45
            $this->fillItem($attribute, $node);
117 45
        };
118
    }
119
120
    /**
121
     * @param DOMElement $node
122
     * @return string
123
     */
124 45
    private function getDocumentation(DOMElement $node)
125
    {
126 45
        $doc = '';
127 45
        foreach ($node->childNodes as $childNode) {
128 45
            if ($childNode->localName == "annotation") {
129 45
                foreach ($childNode->childNodes as $subChildNode) {
130 45
                    if ($subChildNode->localName == "documentation") {
131 45
                        $doc .= ($subChildNode->nodeValue);
132 45
                    }
133 45
                }
134 45
            }
135 45
        }
136 45
        $doc = preg_replace('/[\t ]+/', ' ', $doc);
137 45
        return trim($doc);
138
    }
139
140
    /**
141
     *
142
     * @param Schema $schema
143
     * @param DOMElement $node
144
     * @param Schema $parent
145
     * @return array
146
     */
147 45
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null)
148
    {
149 45
        $schema->setDoc($this->getDocumentation($node));
150
151 45
        if ($node->hasAttribute("targetNamespace")) {
152 45
            $schema->setTargetNamespace($node->getAttribute("targetNamespace"));
153 45
        } elseif ($parent) {
154 1
            $schema->setTargetNamespace($parent->getTargetNamespace());
155 1
        }
156 45
        $schema->setElementsQualification($node->getAttribute("elementFormDefault") == "qualified");
157 45
        $schema->setAttributesQualification($node->getAttribute("attributeFormDefault") == "qualified");
158 45
        $schema->setDoc($this->getDocumentation($node));
159 45
        $functions = array();
160
161 45
        foreach ($node->childNodes as $childNode) {
162 45
            switch ($childNode->localName) {
163 45
                case 'include':
164 45
                case 'import':
165 45
                    $functions[] = $this->loadImport($schema, $childNode);
166 45
                    break;
167 45
                case 'redefine':
168 1
                    $functions[] = $this->loadRedefine($schema, $childNode);
169 1
                    break;
170 45
                case 'element':
171 45
                    $functions[] = $this->loadElementDef($schema, $childNode);
172 45
                    break;
173 45
                case 'attribute':
174 45
                    $functions[] = $this->loadAttributeDef($schema, $childNode);
175 45
                    break;
176 45
                case 'attributeGroup':
177 45
                    $functions[] = $this->loadAttributeGroup($schema, $childNode);
178 45
                    break;
179 45
                case 'group':
180 45
                    $functions[] = $this->loadGroup($schema, $childNode);
181 45
                    break;
182 45
                case 'complexType':
183 45
                    $functions[] = $this->loadComplexType($schema, $childNode);
184 45
                    break;
185 45
                case 'simpleType':
186 45
                    $functions[] = $this->loadSimpleType($schema, $childNode);
187 45
                    break;
188 45
            }
189 45
        }
190
191 45
        return $functions;
192
    }
193
194 45
    private function loadElement(Schema $schema, DOMElement $node)
195
    {
196 45
        $element = new Element($schema, $node->getAttribute("name"));
197 45
        $element->setDoc($this->getDocumentation($node));
198
199 45
        $this->fillItem($element, $node);
200
201 45
        if ($node->hasAttribute("maxOccurs")) {
202 45
            $element->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
203 45
        }
204 45
        if ($node->hasAttribute("minOccurs")) {
205 45
            $element->setMin((int)$node->getAttribute("minOccurs"));
206 45
        }
207
208 45
        $xp = new \DOMXPath($node->ownerDocument);
209 45
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
210
211 45
        if ($xp->query('ancestor::xs:choice', $node)->length) {
212 45
            $element->setMin(0);
213 45
        }
214
215 45
        if ($node->hasAttribute("nillable")) {
216 3
            $element->setNil($node->getAttribute("nillable") == "true");
217 3
        }
218 45
        if ($node->hasAttribute("form")) {
219 3
            $element->setQualified($node->getAttribute("form") == "qualified");
220 3
        }
221 45
        return $element;
222
    }
223
224 45
    private function loadGroupRef(Group $referenced, DOMElement $node)
225
    {
226 45
        $ref = new GroupRef($referenced);
227 45
        $ref->setDoc($this->getDocumentation($node));
228
229 45 View Code Duplication
        if ($node->hasAttribute("maxOccurs")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
230 45
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
231 45
        }
232 45
        if ($node->hasAttribute("minOccurs")) {
233 45
            $ref->setMin((int)$node->getAttribute("minOccurs"));
234 45
        }
235
236 45
        return $ref;
237
    }
238
239 45
    private function loadElementRef(ElementDef $referenced, DOMElement $node)
240
    {
241 45
        $ref = new ElementRef($referenced);
242 45
        $ref->setDoc($this->getDocumentation($node));
243
244 45 View Code Duplication
        if ($node->hasAttribute("maxOccurs")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
245 45
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
246 45
        }
247 45
        if ($node->hasAttribute("minOccurs")) {
248 45
            $ref->setMin((int)$node->getAttribute("minOccurs"));
249 45
        }
250 45
        if ($node->hasAttribute("nillable")) {
251
            $ref->setNil($node->getAttribute("nillable") == "true");
252
        }
253 45
        if ($node->hasAttribute("form")) {
254
            $ref->setQualified($node->getAttribute("form") == "qualified");
255
        }
256
257 45
        return $ref;
258
    }
259
260
261 45
    private function loadAttributeRef(AttributeDef $referencedAttribiute, DOMElement $node)
262
    {
263 45
        $attribute = new AttributeRef($referencedAttribiute);
264 45
        $attribute->setDoc($this->getDocumentation($node));
265
266 45
        if ($node->hasAttribute("nillable")) {
267
            $attribute->setNil($node->getAttribute("nillable") == "true");
268
        }
269 45
        if ($node->hasAttribute("form")) {
270
            $attribute->setQualified($node->getAttribute("form") == "qualified");
271
        }
272 45
        if ($node->hasAttribute("use")) {
273
            $attribute->setUse($node->getAttribute("use"));
274
        }
275 45
        return $attribute;
276
    }
277
278 45
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null)
279
    {
280 45
        $max = $max || $node->getAttribute("maxOccurs") == "unbounded" || $node->getAttribute("maxOccurs") > 1 ? 2 : null;
281
282 45
        foreach ($node->childNodes as $childNode) {
283
284 45
            switch ($childNode->localName) {
285 45
                case 'choice':
286 45
                case 'sequence':
287 45
                case 'all':
288 45
                    $this->loadSequence($elementContainer, $childNode, $max);
289 45
                    break;
290 45
                case 'element':
291 45
                    if ($childNode->hasAttribute("ref")) {
292 45
                        $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
293 45
                        $element = $this->loadElementRef($referencedElement, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $referencedElement defined by $this->findSomething('fi...e->getAttribute('ref')) on line 292 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...eader::loadElementRef() does only seem to accept object<GoetasWebservices...ema\Element\ElementDef>, 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...
294 45
                    } else {
295 45
                        $element = $this->loadElement($elementContainer->getSchema(), $childNode);
296
                    }
297 45
                    if ($max) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $max of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
298 45
                        $element->setMax($max);
299 45
                    }
300 45
                    $elementContainer->addElement($element);
301 45
                    break;
302 45
                case 'group':
303 45
                    $referencedGroup = $this->findSomething('findGroup', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
304
305 45
                    $group = $this->loadGroupRef($referencedGroup, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $referencedGroup defined by $this->findSomething('fi...e->getAttribute('ref')) on line 303 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...aReader::loadGroupRef() 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...
306 45
                    $elementContainer->addElement($group);
307 45
                    break;
308 45
            }
309 45
        }
310 45
    }
311
312 45
    private function loadGroup(Schema $schema, DOMElement $node)
313
    {
314 45
        $group = new Group($schema, $node->getAttribute("name"));
315 45
        $group->setDoc($this->getDocumentation($node));
316
317 45 View Code Duplication
        if ($node->hasAttribute("maxOccurs")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
318
            $group->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
319
        }
320 45
        if ($node->hasAttribute("minOccurs")) {
321
            $group->setMin((int)$node->getAttribute("minOccurs"));
322
        }
323
324 45
        $schema->addGroup($group);
325
326
        return function () use ($group, $node) {
327 45
            foreach ($node->childNodes as $childNode) {
328 45
                switch ($childNode->localName) {
329 45
                    case 'sequence':
330 45
                    case 'choice':
331 45
                    case 'all':
332 45
                        $this->loadSequence($group, $childNode);
333 45
                        break;
334 45
                }
335 45
            }
336 45
        };
337
    }
338
339 45
    private function loadComplexType(Schema $schema, DOMElement $node, $callback = null)
340
    {
341 45
        $isSimple = false;
342
343 45
        foreach ($node->childNodes as $childNode) {
344 45
            if ($childNode->localName === "simpleContent") {
345 2
                $isSimple = true;
346 2
                break;
347
            }
348 45
        }
349
350 45
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute("name")) : new ComplexType($schema, $node->getAttribute("name"));
351
352 45
        $type->setDoc($this->getDocumentation($node));
353 45
        if ($node->getAttribute("name")) {
354 45
            $schema->addType($type);
355 45
        }
356
357
        return function () use ($type, $node, $schema, $callback) {
358
359 45
            $this->fillTypeNode($type, $node);
360
361 45
            foreach ($node->childNodes as $childNode) {
362 45
                switch ($childNode->localName) {
363 45
                    case 'sequence':
364 45
                    case 'choice':
365 45
                    case 'all':
366 45
                        $this->loadSequence($type, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $type defined by $isSimple ? new \GoetasW...->getAttribute('name')) on line 350 can also be of type object<GoetasWebservices...mplexTypeSimpleContent>; 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...
367 45
                        break;
368 45
                    case 'attribute':
369 45
                        if ($childNode->hasAttribute("ref")) {
370 45
                            $referencedAttribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
371 45
                            $attribute = $this->loadAttributeRef($referencedAttribute, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $referencedAttribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 370 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...der::loadAttributeRef() does only seem to accept object<GoetasWebservices...Attribute\AttributeDef>, 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...
372 45
                        } else {
373 45
                            $attribute = $this->loadAttribute($schema, $childNode);
374
                        }
375
376 45
                        $type->addAttribute($attribute);
377 45
                        break;
378 45 View Code Duplication
                    case 'attributeGroup':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
379 2
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
380 2
                        $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 379 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...lexType::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, 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...
381 2
                        break;
382 45
                }
383 45
            }
384
385 45
            if ($callback) {
386 45
                call_user_func($callback, $type);
387 45
            }
388 45
        };
389
    }
390
391 45
    private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null)
392
    {
393 45
        $type = new SimpleType($schema, $node->getAttribute("name"));
394 45
        $type->setDoc($this->getDocumentation($node));
395 45
        if ($node->getAttribute("name")) {
396 45
            $schema->addType($type);
397 45
        }
398
399
        return function () use ($type, $node, $callback) {
400 45
            $this->fillTypeNode($type, $node);
401
402 45
            foreach ($node->childNodes as $childNode) {
403 45
                switch ($childNode->localName) {
404 45
                    case 'union':
405 45
                        $this->loadUnion($type, $childNode);
406 45
                        break;
407 45
                    case 'list':
408 45
                        $this->loadList($type, $childNode);
409 45
                        break;
410 45
                }
411 45
            }
412
413 45
            if ($callback) {
414 45
                call_user_func($callback, $type);
415 45
            }
416 45
        };
417
    }
418
419 45
    private function loadList(SimpleType $type, DOMElement $node)
420
    {
421 45 View Code Duplication
        if ($node->hasAttribute("itemType")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
422 45
            $type->setList($this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("itemType")));
0 ignored issues
show
Bug introduced by
It seems like $this->findSomething('fi...tAttribute('itemType')) targeting GoetasWebservices\XML\XS...Reader::findSomething() can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...e\SimpleType::setList() does only seem to accept object<GoetasWebservices...Schema\Type\SimpleType>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
423 45
        } else {
424
            $addCallback = function ($list) use ($type) {
425 45
                $type->setList($list);
426 45
            };
427
428 45
            foreach ($node->childNodes as $childNode) {
429 45
                switch ($childNode->localName) {
430 45
                    case 'simpleType':
431 45
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
432 45
                        break;
433 45
                }
434 45
            }
435
        }
436 45
    }
437
438 45
    private function loadUnion(SimpleType $type, DOMElement $node)
439
    {
440 45
        if ($node->hasAttribute("memberTypes")) {
441 45
            $types = preg_split('/\s+/', $node->getAttribute("memberTypes"));
442 45
            foreach ($types as $typeName) {
443 45
                $type->addUnion($this->findSomething('findType', $type->getSchema(), $node, $typeName));
0 ignored issues
show
Bug introduced by
It seems like $this->findSomething('fi...ma(), $node, $typeName) targeting GoetasWebservices\XML\XS...Reader::findSomething() can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...\SimpleType::addUnion() does only seem to accept object<GoetasWebservices...Schema\Type\SimpleType>, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
444 45
            }
445 45
        }
446
        $addCallback = function ($unType) use ($type) {
447 45
            $type->addUnion($unType);
448 45
        };
449
450 45
        foreach ($node->childNodes as $childNode) {
451 45
            switch ($childNode->localName) {
452 45
                case 'simpleType':
453 45
                    call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
454 45
                    break;
455 45
            }
456 45
        }
457 45
    }
458
459 45
    private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = true)
460
    {
461
462 45
        if ($checkAbstract) {
463 45
            $type->setAbstract($node->getAttribute("abstract") === "true" || $node->getAttribute("abstract") === "1");
464 45
        }
465
466 45
        foreach ($node->childNodes as $childNode) {
467 45
            switch ($childNode->localName) {
468 45
                case 'restriction':
469 45
                    $this->loadRestriction($type, $childNode);
470 45
                    break;
471 45
                case 'extension':
472 45
                    $this->loadExtension($type, $childNode);
0 ignored issues
show
Compatibility introduced by
$type of type object<GoetasWebservices...eader\Schema\Type\Type> is not a sub-type of object<GoetasWebservices...a\Type\BaseComplexType>. It seems like you assume a child class of the class GoetasWebservices\XML\XSDReader\Schema\Type\Type 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...
473 45
                    break;
474 45
                case 'simpleContent':
475 45
                case 'complexContent':
476 45
                    $this->fillTypeNode($type, $childNode, false);
477 45
                    break;
478 45
            }
479 45
        }
480 45
    }
481
482 45
    private function loadExtension(BaseComplexType $type, DOMElement $node)
483
    {
484 45
        $extension = new Extension();
485 45
        $type->setExtension($extension);
486
487 45
        if ($node->hasAttribute("base")) {
488 45
            $parent = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
489 45
            $extension->setBase($parent);
0 ignored issues
show
Bug introduced by
It seems like $parent defined by $this->findSomething('fi...->getAttribute('base')) on line 488 can also be of type object<GoetasWebservices...ma\Element\ElementItem>; however, GoetasWebservices\XML\XS...ritance\Base::setBase() does only seem to accept object<GoetasWebservices...eader\Schema\Type\Type>, 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...
490 45
        }
491
492 45
        foreach ($node->childNodes as $childNode) {
493 45
            switch ($childNode->localName) {
494 45
                case 'sequence':
495 45
                case 'choice':
496 45
                case 'all':
497 45
                    $this->loadSequence($type, $childNode);
0 ignored issues
show
Documentation introduced by
$type is of type object<GoetasWebservices...a\Type\BaseComplexType>, but the function expects a object<GoetasWebservices...ement\ElementContainer>.

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...
498 45
                    break;
499 45 View Code Duplication
                case 'attribute':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
500 45
                    if ($childNode->hasAttribute("ref")) {
501 45
                        $attribute = $this->findSomething('findAttribute', $type->getSchema(), $node, $childNode->getAttribute("ref"));
502 45
                    } else {
503 45
                        $attribute = $this->loadAttribute($type->getSchema(), $childNode);
504
                    }
505 45
                    $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 501 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...lexType::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, 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...
506 45
                    break;
507 45
                case 'attributeGroup':
508 45
                    $attribute = $this->findSomething('findAttributeGroup', $type->getSchema(), $node, $childNode->getAttribute("ref"));
509 45
                    $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 508 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...lexType::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, 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...
510 45
                    break;
511 45
            }
512 45
        }
513 45
    }
514
515 45
    private function loadRestriction(Type $type, DOMElement $node)
516
    {
517 45
        $restriction = new Restriction();
518 45
        $type->setRestriction($restriction);
519 45 View Code Duplication
        if ($node->hasAttribute("base")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
520 45
            $restrictedType = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
521 45
            $restriction->setBase($restrictedType);
0 ignored issues
show
Bug introduced by
It seems like $restrictedType defined by $this->findSomething('fi...->getAttribute('base')) on line 520 can also be of type object<GoetasWebservices...ma\Element\ElementItem>; however, GoetasWebservices\XML\XS...ritance\Base::setBase() does only seem to accept object<GoetasWebservices...eader\Schema\Type\Type>, 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...
522 45
        } else {
523
            $addCallback = function ($restType) use ($restriction) {
524 45
                $restriction->setBase($restType);
525 45
            };
526
527 45
            foreach ($node->childNodes as $childNode) {
528 45
                switch ($childNode->localName) {
529 45
                    case 'simpleType':
530 45
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
531 45
                        break;
532 45
                }
533 45
            }
534
        }
535 45
        foreach ($node->childNodes as $childNode) {
536 45
            if (in_array($childNode->localName,
537
                [
538 45
                    'enumeration',
539 45
                    'pattern',
540 45
                    'length',
541 45
                    'minLength',
542 45
                    'maxLength',
543 45
                    'minInclusive',
544 45
                    'maxInclusive',
545 45
                    'minExclusive',
546 45
                    'maxExclusive',
547 45
                    'fractionDigits',
548 45
                    'totalDigits',
549
                    'whiteSpace'
550 45
                ], true)) {
551 45
                $restriction->addCheck($childNode->localName,
552
                    [
553 45
                        'value' => $childNode->getAttribute("value"),
554 45
                        'doc' => $this->getDocumentation($childNode)
555 45
                    ]);
556 45
            }
557 45
        }
558 45
    }
559
560 45
    private static function splitParts(DOMElement $node, $typeName)
561
    {
562 45
        $namespace = null;
0 ignored issues
show
Unused Code introduced by
$namespace is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
563 45
        $prefix = null;
564 45
        $name = $typeName;
565 45
        if (strpos($typeName, ':') !== false) {
566 45
            list ($prefix, $name) = explode(':', $typeName);
567 45
        }
568
569 45
        $namespace = $node->lookupNamespaceURI($prefix ?: null);
570
        return array(
571 45
            $name,
572 45
            $namespace,
573
            $prefix
574 45
        );
575
    }
576
577
    /**
578
     *
579
     * @param string $finder
580
     * @param Schema $schema
581
     * @param DOMElement $node
582
     * @param string $typeName
583
     * @throws TypeException
584
     * @return ElementItem|Group|AttributeItem|AttribiuteGroup|Type
585
     */
586 45
    private function findSomething($finder, Schema $schema, DOMElement $node, $typeName)
587
    {
588 45
        list ($name, $namespace) = self::splitParts($node, $typeName);
589
590 45
        $namespace = $namespace ?: $schema->getTargetNamespace();
591
592
        try {
593 45
            return $schema->$finder($name, $namespace);
594
        } catch (TypeNotFoundException $e) {
595
            throw new TypeException(sprintf("Can't find %s named {%s}#%s, at line %d in %s ", strtolower(substr($finder, 4)), $namespace, $name, $node->getLineNo(), $node->ownerDocument->documentURI), 0, $e);
596
        }
597
    }
598
599 45 View Code Duplication
    private function loadElementDef(Schema $schema, DOMElement $node)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
600
    {
601 45
        $element = new ElementDef($schema, $node->getAttribute("name"));
602 45
        $schema->addElement($element);
603
604
        return function () use ($element, $node) {
605 45
            $this->fillItem($element, $node);
606 45
        };
607
    }
608
609 45
    private function fillItem(Item $element, DOMElement $node)
610
    {
611 45
        $localType = null;
612 45
        foreach ($node->childNodes as $childNode) {
613 45
            switch ($childNode->localName) {
614 45
                case 'complexType':
615 45
                case 'simpleType':
616 45
                    $localType = $childNode;
617 45
                    break 2;
618 45
            }
619 45
        }
620
621 45
        if ($localType) {
622
            $addCallback = function ($type) use ($element) {
623 45
                $element->setType($type);
624 45
            };
625 45
            switch ($localType->localName) {
626 45
                case 'complexType':
627 45
                    call_user_func($this->loadComplexType($element->getSchema(), $localType, $addCallback));
628 45
                    break;
629 45
                case 'simpleType':
630 45
                    call_user_func($this->loadSimpleType($element->getSchema(), $localType, $addCallback));
631 45
                    break;
632 45
            }
633 45
        } else {
634
635 45
            if ($node->getAttribute("type")) {
636 45
                $type = $this->findSomething('findType', $element->getSchema(), $node, $node->getAttribute("type"));
637 45
            } else {
638 45
                $type = $this->findSomething('findType', $element->getSchema(), $node, ($node->lookupPrefix(self::XSD_NS) . ":anyType"));
639
            }
640
641 45
            $element->setType($type);
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type object<GoetasWebservices...ma\Element\ElementItem>; however, GoetasWebservices\XML\XS...\Schema\Item::setType() does only seem to accept object<GoetasWebservices...eader\Schema\Type\Type>, 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...
642
        }
643 45
    }
644
645 1
    private function loadRedefine(Schema $schema, DOMElement $node)
646
    {
647 1
        $base = urldecode($node->ownerDocument->documentURI);
648 1
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute("schemaLocation"));
649
650 1
        if (isset($this->loadedFiles[$file])) {
651
            /* @var $redefined Schema */
652 1
            $redefined = clone $this->loadedFiles[$file];
653
654 1
            if($schema->getTargetNamespace() != $redefined->getTargetNamespace()){
655 1
                $redefined->setTargetNamespace($schema->getTargetNamespace());
656 1
            }
657
658 1
            $schema->addSchema($redefined);
659
660 1
            $callbacks = $this->schemaNode($redefined, $node, $schema);
661 1
        }
662
        else{
663
            $redefined = new Schema();
664
            $redefined->addSchema($this->getGlobalSchema());
665
666
            $xml = $this->getDOM(isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] : $file);
667
668
            $callbacks = $this->schemaNode($redefined, $xml->documentElement, $schema);
669
670
            $schema->addSchema($redefined);
671
        }
672
673
        return function () use ($callbacks) {
674 1
            foreach ($callbacks as $callback) {
675 1
                call_user_func($callback);
676 1
            }
677 1
        };
678
    }
679
680 45
    private function loadImport(Schema $schema, DOMElement $node)
681
    {
682 45
        $base = urldecode($node->ownerDocument->documentURI);
683 45
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute("schemaLocation"));
684 45
        if ($node->hasAttribute("namespace")
685 45
            && isset(self::$globalSchemaInfo[$node->getAttribute("namespace")])
686 45
            && isset($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]])
687 45
        ) {
688
689 45
            $schema->addSchema($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]]);
690
691
            return function () {
692 45
            };
693 3
        } elseif ($node->hasAttribute("namespace")
694 3
            && isset($this->loadedFiles[$this->getNamespaceSpecificFileIndex($file, $node->getAttribute("namespace"))])) {
695 2
            $schema->addSchema($this->loadedFiles[$this->getNamespaceSpecificFileIndex($file, $node->getAttribute("namespace"))]);
696
            return function () {
697 2
            };
698 1
        } elseif (isset($this->loadedFiles[$file])) {
699
            $schema->addSchema($this->loadedFiles[$file]);
700
            return function () {
701
            };
702
        }
703
704 1
        if (!$node->getAttribute("namespace")) {
705 1
            $this->loadedFiles[$file] = $newSchema = $schema;
706 1
        } else {
707
            $this->loadedFiles[$file] = $newSchema = new Schema();
708
            $newSchema->addSchema($this->getGlobalSchema());
709
        }
710
711 1
        $xml = $this->getDOM(isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] : $file);
712
713 1
        $callbacks = $this->schemaNode($newSchema, $xml->documentElement, $schema);
714
715 1
        if ($node->getAttribute("namespace")) {
716
            $schema->addSchema($newSchema);
717
        }
718
719
720 1
        return function () use ($callbacks) {
721 1
            foreach ($callbacks as $callback) {
722 1
                call_user_func($callback);
723 1
            }
724 1
        };
725
    }
726
727
    private $globalSchema;
728
729
    /**
730
     *
731
     * @return Schema
732
     */
733 45
    public function getGlobalSchema()
734
    {
735 45
        if (!$this->globalSchema) {
736 45
            $callbacks = array();
737 45
            $globalSchemas = array();
738 45
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
739 45
                $this->loadedFiles[$uri] = $globalSchemas [$namespace] = $schema = new Schema();
740 45
                if ($namespace === self::XSD_NS) {
741 45
                    $this->globalSchema = $schema;
742 45
                }
743 45
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
744 45
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
745 45
            }
746
747 45
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anySimpleType"));
748 45
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anyType"));
749
750 45
            $globalSchemas[self::XML_NS]->addSchema($globalSchemas[self::XSD_NS], self::XSD_NS);
751 45
            $globalSchemas[self::XSD_NS]->addSchema($globalSchemas[self::XML_NS], self::XML_NS);
752
753 45
            foreach ($callbacks as $callback) {
754 45
                $callback();
755 45
            }
756 45
        }
757 45
        return $this->globalSchema;
758
    }
759
760
    /**
761
     * @param DOMNode $node
762
     * @param string  $file
763
     *
764
     * @return Schema
765
     */
766 45
    public function readNode(DOMNode $node, $file = 'schema.xsd')
767
    {
768 45
        $fileKey = $node instanceof DOMElement && $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file;
769 45
        $this->loadedFiles[$fileKey] = $rootSchema = new Schema();
770
771 45
        $rootSchema->addSchema($this->getGlobalSchema());
772 45
        $callbacks = $this->schemaNode($rootSchema, $node);
0 ignored issues
show
Compatibility introduced by
$node of type object<DOMNode> is not a sub-type of object<DOMElement>. It seems like you assume a child class of the class DOMNode 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...
773
774 45
        foreach ($callbacks as $callback) {
775 39
            call_user_func($callback);
776 45
        }
777
778 45
        return $rootSchema;
779
    }
780
781
    /**
782
     * It is possible that a single file contains multiple <xsd:schema/> nodes, for instance in a WSDL file.
783
     *
784
     * Each of these  <xsd:schema/> nodes typically target a specific namespace. Append the target namespace to the
785
     * file to distinguish between multiple schemas in a single file.
786
     *
787
     * @param string $file
788
     * @param string $targetNamespace
789
     *
790
     * @return string
791
     */
792 45
    private function getNamespaceSpecificFileIndex($file, $targetNamespace)
793
    {
794 45
        return $file . '#' . $targetNamespace;
795
    }
796
797
    /**
798
     * @param string $content
799
     * @param string $file
800
     *
801
     * @return Schema
802
     *
803
     * @throws IOException
804
     */
805 44
    public function readString($content, $file = 'schema.xsd')
806
    {
807 44
        $xml = new DOMDocument('1.0', 'UTF-8');
808 44
        if (!$xml->loadXML($content)) {
809
            throw new IOException("Can't load the schema");
810
        }
811 44
        $xml->documentURI = $file;
812
813 44
        return $this->readNode($xml->documentElement, $file);
814
    }
815
816
    /**
817
     * @param string $file
818
     *
819
     * @return Schema
820
     */
821 1
    public function readFile($file)
822
    {
823 1
        $xml = $this->getDOM($file);
824 1
        return $this->readNode($xml->documentElement, $file);
825
    }
826
827
    /**
828
     * @param string $file
829
     *
830
     * @return DOMDocument
831
     *
832
     * @throws IOException
833
     */
834 45
    private function getDOM($file)
835
    {
836 45
        $xml = new DOMDocument('1.0', 'UTF-8');
837 45
        if (!$xml->load($file)) {
838
            throw new IOException("Can't load the file $file");
839
        }
840 45
        return $xml;
841
    }
842
}
843