Completed
Push — master ( b3ea0d...a472ab )
by Asmir
03:28
created

SchemaReader::getDOM()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2.032
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
            $schema->setTargetNamespace($parent->getTargetNamespace());
155
        }
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 'element':
168 45
                    $functions[] = $this->loadElementDef($schema, $childNode);
169 45
                    break;
170 45
                case 'attribute':
171 45
                    $functions[] = $this->loadAttributeDef($schema, $childNode);
172 45
                    break;
173 45
                case 'attributeGroup':
174 45
                    $functions[] = $this->loadAttributeGroup($schema, $childNode);
175 45
                    break;
176 45
                case 'group':
177 45
                    $functions[] = $this->loadGroup($schema, $childNode);
178 45
                    break;
179 45
                case 'complexType':
180 45
                    $functions[] = $this->loadComplexType($schema, $childNode);
181 45
                    break;
182 45
                case 'simpleType':
183 45
                    $functions[] = $this->loadSimpleType($schema, $childNode);
184 45
                    break;
185 45
            }
186 45
        }
187
188 45
        return $functions;
189
    }
190
191 45
    private function loadElement(Schema $schema, DOMElement $node)
192
    {
193 45
        $element = new Element($schema, $node->getAttribute("name"));
194 45
        $element->setDoc($this->getDocumentation($node));
195
196 45
        $this->fillItem($element, $node);
197
198 45
        if ($node->hasAttribute("maxOccurs")) {
199 45
            $element->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
200 45
        }
201 45
        if ($node->hasAttribute("minOccurs")) {
202 45
            $element->setMin((int)$node->getAttribute("minOccurs"));
203 45
        }
204
205 45
        $xp = new \DOMXPath($node->ownerDocument);
206 45
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
207
        
208 45
        if ($xp->query('ancestor::xs:choice', $node)->length) {
209 45
            $element->setMin(0);
210 45
        }
211
212 45
        if ($node->hasAttribute("nillable")) {
213 3
            $element->setNil($node->getAttribute("nillable") == "true");
214 3
        }
215 45
        if ($node->hasAttribute("form")) {
216 3
            $element->setQualified($node->getAttribute("form") == "qualified");
217 3
        }
218 45
        return $element;
219
    }
220
221 45
    private function loadGroupRef(Group $referenced, DOMElement $node)
222
    {
223 45
        $ref = new GroupRef($referenced);
224 45
        $ref->setDoc($this->getDocumentation($node));
225
226 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...
227 45
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
228 45
        }
229 45
        if ($node->hasAttribute("minOccurs")) {
230 45
            $ref->setMin((int)$node->getAttribute("minOccurs"));
231 45
        }
232
233 45
        return $ref;
234
    }
235
236 45
    private function loadElementRef(ElementDef $referenced, DOMElement $node)
237
    {
238 45
        $ref = new ElementRef($referenced);
239 45
        $ref->setDoc($this->getDocumentation($node));
240
241 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...
242 45
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
243 45
        }
244 45
        if ($node->hasAttribute("minOccurs")) {
245 45
            $ref->setMin((int)$node->getAttribute("minOccurs"));
246 45
        }
247 45
        if ($node->hasAttribute("nillable")) {
248
            $ref->setNil($node->getAttribute("nillable") == "true");
249
        }
250 45
        if ($node->hasAttribute("form")) {
251
            $ref->setQualified($node->getAttribute("form") == "qualified");
252
        }
253
254 45
        return $ref;
255
    }
256
257
258 45
    private function loadAttributeRef(AttributeDef $referencedAttribiute, DOMElement $node)
259
    {
260 45
        $attribute = new AttributeRef($referencedAttribiute);
261 45
        $attribute->setDoc($this->getDocumentation($node));
262
263 45
        if ($node->hasAttribute("nillable")) {
264
            $attribute->setNil($node->getAttribute("nillable") == "true");
265
        }
266 45
        if ($node->hasAttribute("form")) {
267
            $attribute->setQualified($node->getAttribute("form") == "qualified");
268
        }
269 45
        if ($node->hasAttribute("use")) {
270
            $attribute->setUse($node->getAttribute("use"));
271
        }
272 45
        return $attribute;
273
    }
274
275 45
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null)
276
    {
277 45
        $max = $max || $node->getAttribute("maxOccurs") == "unbounded" || $node->getAttribute("maxOccurs") > 1 ? 2 : null;
278
279 45
        foreach ($node->childNodes as $childNode) {
280
281 45
            switch ($childNode->localName) {
282 45
                case 'choice':
283 45
                case 'sequence':
284 45
                case 'all':
285 45
                    $this->loadSequence($elementContainer, $childNode, $max);
286 45
                    break;
287 45
                case 'element':
288 45
                    if ($childNode->hasAttribute("ref")) {
289 45
                        $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
290 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 289 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...
291 45
                    } else {
292 45
                        $element = $this->loadElement($elementContainer->getSchema(), $childNode);
293
                    }
294 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...
295 45
                        $element->setMax($max);
296 45
                    }
297 45
                    $elementContainer->addElement($element);
298 45
                    break;
299 45 View Code Duplication
                case 'group':
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...
300 45
                    $referencedGroup = $this->findSomething('findGroup', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
301
302 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 300 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...
303 45
                    $elementContainer->addElement($group);
304 45
                    break;
305 45
            }
306 45
        }
307 45
    }
308
309 45
    private function loadGroup(Schema $schema, DOMElement $node)
310
    {
311 45
        $group = new Group($schema, $node->getAttribute("name"));
312 45
        $group->setDoc($this->getDocumentation($node));
313
314 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...
315
            $group->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
316
        }
317 45
        if ($node->hasAttribute("minOccurs")) {
318
            $group->setMin((int)$node->getAttribute("minOccurs"));
319
        }
320
321 45
        $schema->addGroup($group);
322
323
        return function () use ($group, $node) {
324 45
            foreach ($node->childNodes as $childNode) {
325 45
                switch ($childNode->localName) {
326 45
                    case 'sequence':
327 45
                    case 'choice':
328 45
                    case 'all':
329 45
                        $this->loadSequence($group, $childNode);
330 45
                        break;
331 45
                }
332 45
            }
333 45
        };
334
    }
335
336 45
    private function loadComplexType(Schema $schema, DOMElement $node, $callback = null)
337
    {
338 45
        $isSimple = false;
339
340 45
        foreach ($node->childNodes as $childNode) {
341 45
            if ($childNode->localName === "simpleContent") {
342 2
                $isSimple = true;
343 2
                break;
344
            }
345 45
        }
346
347 45
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute("name")) : new ComplexType($schema, $node->getAttribute("name"));
348
349 45
        $type->setDoc($this->getDocumentation($node));
350 45
        if ($node->getAttribute("name")) {
351 45
            $schema->addType($type);
352 45
        }
353
354
        return function () use ($type, $node, $schema, $callback) {
355
356 45
            $this->fillTypeNode($type, $node);
357
358 45
            foreach ($node->childNodes as $childNode) {
359 45
                switch ($childNode->localName) {
360 45
                    case 'sequence':
361 45
                    case 'choice':
362 45
                    case 'all':
363 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 347 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...
364 45
                        break;
365 45
                    case 'attribute':
366 45
                        if ($childNode->hasAttribute("ref")) {
367 45
                            $referencedAttribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
368 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 367 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...
369 45
                        } else {
370 45
                            $attribute = $this->loadAttribute($schema, $childNode);
371
                        }
372
373 45
                        $type->addAttribute($attribute);
374 45
                        break;
375 45 View Code Duplication
                    case 'group':
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...
376 1
                        $referencedGroup = $this->findSomething('findGroup', $schema, $node, $childNode->getAttribute("ref"));
377 1
                        $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 376 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...
378 1
                        $type->addElement($group);
0 ignored issues
show
Bug introduced by
The method addElement does only exist in GoetasWebservices\XML\XS...Schema\Type\ComplexType, but not in GoetasWebservices\XML\XS...omplexTypeSimpleContent.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
379 1
                        break;
380 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...
381 2
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
382 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 381 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...
383 2
                        break;
384 45
                }
385 45
            }
386
387 45
            if ($callback) {
388 45
                call_user_func($callback, $type);
389 45
            }
390 45
        };
391
    }
392
393 45
    private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null)
394
    {
395 45
        $type = new SimpleType($schema, $node->getAttribute("name"));
396 45
        $type->setDoc($this->getDocumentation($node));
397 45
        if ($node->getAttribute("name")) {
398 45
            $schema->addType($type);
399 45
        }
400
401
        return function () use ($type, $node, $callback) {
402 45
            $this->fillTypeNode($type, $node);
403
404 45
            foreach ($node->childNodes as $childNode) {
405 45
                switch ($childNode->localName) {
406 45
                    case 'union':
407 45
                        $this->loadUnion($type, $childNode);
408 45
                        break;
409 45
                    case 'list':
410 45
                        $this->loadList($type, $childNode);
411 45
                        break;
412 45
                }
413 45
            }
414
415 45
            if ($callback) {
416 45
                call_user_func($callback, $type);
417 45
            }
418 45
        };
419
    }
420
421 45
    private function loadList(SimpleType $type, DOMElement $node)
422
    {
423 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...
424 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...
425 45
        } else {
426
            $addCallback = function ($list) use ($type) {
427 45
                $type->setList($list);
428 45
            };
429
430 45
            foreach ($node->childNodes as $childNode) {
431 45
                switch ($childNode->localName) {
432 45
                    case 'simpleType':
433 45
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
434 45
                        break;
435 45
                }
436 45
            }
437
        }
438 45
    }
439
440 45
    private function loadUnion(SimpleType $type, DOMElement $node)
441
    {
442 45
        if ($node->hasAttribute("memberTypes")) {
443 45
            $types = preg_split('/\s+/', $node->getAttribute("memberTypes"));
444 45
            foreach ($types as $typeName) {
445 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...
446 45
            }
447 45
        }
448
        $addCallback = function ($unType) use ($type) {
449 45
            $type->addUnion($unType);
450 45
        };
451
452 45
        foreach ($node->childNodes as $childNode) {
453 45
            switch ($childNode->localName) {
454 45
                case 'simpleType':
455 45
                    call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
456 45
                    break;
457 45
            }
458 45
        }
459 45
    }
460
461 45
    private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = true)
462
    {
463
464 45
        if ($checkAbstract) {
465 45
            $type->setAbstract($node->getAttribute("abstract") === "true" || $node->getAttribute("abstract") === "1");
466 45
        }
467
468 45
        foreach ($node->childNodes as $childNode) {
469 45
            switch ($childNode->localName) {
470 45
                case 'restriction':
471 45
                    $this->loadRestriction($type, $childNode);
472 45
                    break;
473 45
                case 'extension':
474 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...
475 45
                    break;
476 45
                case 'simpleContent':
477 45
                case 'complexContent':
478 45
                    $this->fillTypeNode($type, $childNode, false);
479 45
                    break;
480 45
            }
481 45
        }
482 45
    }
483
484 45
    private function loadExtension(BaseComplexType $type, DOMElement $node)
485
    {
486 45
        $extension = new Extension();
487 45
        $type->setExtension($extension);
488
489 45
        if ($node->hasAttribute("base")) {
490 45
            $parent = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
491 45
            $extension->setBase($parent);
0 ignored issues
show
Bug introduced by
It seems like $parent defined by $this->findSomething('fi...->getAttribute('base')) on line 490 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...
492 45
        }
493
494 45
        foreach ($node->childNodes as $childNode) {
495 45
            switch ($childNode->localName) {
496 45
                case 'sequence':
497 45
                case 'choice':
498 45
                case 'all':
499 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...
500 45
                    break;
501 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...
502 45
                    if ($childNode->hasAttribute("ref")) {
503 45
                        $attribute = $this->findSomething('findAttribute', $type->getSchema(), $node, $childNode->getAttribute("ref"));
504 45
                    } else {
505 45
                        $attribute = $this->loadAttribute($type->getSchema(), $childNode);
506
                    }
507 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 503 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...
508 45
                    break;
509 45
                case 'attributeGroup':
510 45
                    $attribute = $this->findSomething('findAttributeGroup', $type->getSchema(), $node, $childNode->getAttribute("ref"));
511 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 510 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...
512 45
                    break;
513 45
            }
514 45
        }
515 45
    }
516
517 45
    private function loadRestriction(Type $type, DOMElement $node)
518
    {
519 45
        $restriction = new Restriction();
520 45
        $type->setRestriction($restriction);
521 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...
522 45
            $restrictedType = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
523 45
            $restriction->setBase($restrictedType);
0 ignored issues
show
Bug introduced by
It seems like $restrictedType defined by $this->findSomething('fi...->getAttribute('base')) on line 522 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...
524 45
        } else {
525
            $addCallback = function ($restType) use ($restriction) {
526 45
                $restriction->setBase($restType);
527 45
            };
528
529 45
            foreach ($node->childNodes as $childNode) {
530 45
                switch ($childNode->localName) {
531 45
                    case 'simpleType':
532 45
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
533 45
                        break;
534 45
                }
535 45
            }
536
        }
537 45
        foreach ($node->childNodes as $childNode) {
538 45
            if (in_array($childNode->localName,
539
                [
540 45
                    'enumeration',
541 45
                    'pattern',
542 45
                    'length',
543 45
                    'minLength',
544 45
                    'maxLength',
545 45
                    'minInclusive',
546 45
                    'maxInclusive',
547 45
                    'minExclusive',
548 45
                    'maxExclusive',
549 45
                    'fractionDigits',
550 45
                    'totalDigits',
551
                    'whiteSpace'
552 45
                ], true)) {
553 45
                $restriction->addCheck($childNode->localName,
554
                    [
555 45
                        'value' => $childNode->getAttribute("value"),
556 45
                        'doc' => $this->getDocumentation($childNode)
557 45
                    ]);
558 45
            }
559 45
        }
560 45
    }
561
562 45
    private static function splitParts(DOMElement $node, $typeName)
563
    {
564 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...
565 45
        $prefix = null;
566 45
        $name = $typeName;
567 45
        if (strpos($typeName, ':') !== false) {
568 45
            list ($prefix, $name) = explode(':', $typeName);
569 45
        }
570
571 45
        $namespace = $node->lookupNamespaceURI($prefix ?: null);
572
        return array(
573 45
            $name,
574 45
            $namespace,
575
            $prefix
576 45
        );
577
    }
578
579
    /**
580
     *
581
     * @param string $finder
582
     * @param Schema $schema
583
     * @param DOMElement $node
584
     * @param string $typeName
585
     * @throws TypeException
586
     * @return ElementItem|Group|AttributeItem|AttribiuteGroup|Type
587
     */
588 45
    private function findSomething($finder, Schema $schema, DOMElement $node, $typeName)
589
    {
590 45
        list ($name, $namespace) = self::splitParts($node, $typeName);
591
592 45
        $namespace = $namespace ?: $schema->getTargetNamespace();
593
594
        try {
595 45
            return $schema->$finder($name, $namespace);
596
        } catch (TypeNotFoundException $e) {
597
            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);
598
        }
599
    }
600
601 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...
602
    {
603 45
        $element = new ElementDef($schema, $node->getAttribute("name"));
604 45
        $schema->addElement($element);
605
606
        return function () use ($element, $node) {
607 45
            $this->fillItem($element, $node);
608 45
        };
609
    }
610
611 45
    private function fillItem(Item $element, DOMElement $node)
612
    {
613 45
        $localType = null;
614 45
        foreach ($node->childNodes as $childNode) {
615 45
            switch ($childNode->localName) {
616 45
                case 'complexType':
617 45
                case 'simpleType':
618 45
                    $localType = $childNode;
619 45
                    break 2;
620 45
            }
621 45
        }
622
623 45
        if ($localType) {
624
            $addCallback = function ($type) use ($element) {
625 45
                $element->setType($type);
626 45
            };
627 45
            switch ($localType->localName) {
628 45
                case 'complexType':
629 45
                    call_user_func($this->loadComplexType($element->getSchema(), $localType, $addCallback));
630 45
                    break;
631 45
                case 'simpleType':
632 45
                    call_user_func($this->loadSimpleType($element->getSchema(), $localType, $addCallback));
633 45
                    break;
634 45
            }
635 45
        } else {
636
637 45
            if ($node->getAttribute("type")) {
638 45
                $type = $this->findSomething('findType', $element->getSchema(), $node, $node->getAttribute("type"));
639 45
            } else {
640 45
                $type = $this->findSomething('findType', $element->getSchema(), $node, ($node->lookupPrefix(self::XSD_NS) . ":anyType"));
641
            }
642
643 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...
644
        }
645 45
    }
646
647 45
    private function loadImport(Schema $schema, DOMElement $node)
648
    {
649 45
        $base = urldecode($node->ownerDocument->documentURI);
650 45
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute("schemaLocation"));
651 45
        if ($node->hasAttribute("namespace")
652 45
            && isset(self::$globalSchemaInfo[$node->getAttribute("namespace")])
653 45
            && isset($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]])
654 45
        ) {
655
656 45
            $schema->addSchema($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]]);
657
658
            return function () {
659 45
            };
660 3
        } elseif ($node->hasAttribute("namespace")
661 3
            && isset($this->loadedFiles[$this->getNamespaceSpecificFileIndex($file, $node->getAttribute("namespace"))])) {
662 2
            $schema->addSchema($this->loadedFiles[$this->getNamespaceSpecificFileIndex($file, $node->getAttribute("namespace"))]);
663
            return function () {
664 2
            };
665 1
        } elseif (isset($this->loadedFiles[$file])) {
666
            $schema->addSchema($this->loadedFiles[$file]);
667
            return function () {
668
            };
669
        }
670
671 1
        if (!$node->getAttribute("namespace")) {
672 1
            $this->loadedFiles[$file] = $newSchema = $schema;
673 1
        } else {
674
            $this->loadedFiles[$file] = $newSchema = new Schema();
675
            $newSchema->addSchema($this->getGlobalSchema());
676
        }
677
678 1
        $xml = $this->getDOM(isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] : $file);
679
680 1
        $callbacks = $this->schemaNode($newSchema, $xml->documentElement, $schema);
681
682 1
        if ($node->getAttribute("namespace")) {
683
            $schema->addSchema($newSchema);
684
        }
685
686
687 1
        return function () use ($callbacks) {
688 1
            foreach ($callbacks as $callback) {
689 1
                call_user_func($callback);
690 1
            }
691 1
        };
692
    }
693
694
    private $globalSchema;
695
696
    /**
697
     *
698
     * @return Schema
699
     */
700 45
    public function getGlobalSchema()
701
    {
702 45
        if (!$this->globalSchema) {
703 45
            $callbacks = array();
704 45
            $globalSchemas = array();
705 45
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
706 45
                $this->loadedFiles[$uri] = $globalSchemas [$namespace] = $schema = new Schema();
707 45
                if ($namespace === self::XSD_NS) {
708 45
                    $this->globalSchema = $schema;
709 45
                }
710 45
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
711 45
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
712 45
            }
713
714 45
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anySimpleType"));
715 45
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anyType"));
716
717 45
            $globalSchemas[self::XML_NS]->addSchema($globalSchemas[self::XSD_NS], self::XSD_NS);
718 45
            $globalSchemas[self::XSD_NS]->addSchema($globalSchemas[self::XML_NS], self::XML_NS);
719
720 45
            foreach ($callbacks as $callback) {
721 45
                $callback();
722 45
            }
723 45
        }
724 45
        return $this->globalSchema;
725
    }
726
727
    /**
728
     * @param DOMNode $node
729
     * @param string  $file
730
     * 
731
     * @return Schema
732
     */
733 45
    public function readNode(DOMNode $node, $file = 'schema.xsd')
734
    {
735 45
        $fileKey = $node instanceof DOMElement && $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file;
736 45
        $this->loadedFiles[$fileKey] = $rootSchema = new Schema();
737
738 45
        $rootSchema->addSchema($this->getGlobalSchema());
739 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...
740
741 45
        foreach ($callbacks as $callback) {
742 39
            call_user_func($callback);
743 45
        }
744
745 45
        return $rootSchema;
746
    }
747
748
    /**
749
     * It is possible that a single file contains multiple <xsd:schema/> nodes, for instance in a WSDL file.
750
     *
751
     * Each of these  <xsd:schema/> nodes typically target a specific namespace. Append the target namespace to the
752
     * file to distinguish between multiple schemas in a single file.
753
     *
754
     * @param string $file
755
     * @param string $targetNamespace
756
     *
757
     * @return string
758
     */
759 45
    private function getNamespaceSpecificFileIndex($file, $targetNamespace)
760
    {
761 45
        return $file . '#' . $targetNamespace;
762
    }
763
764
    /**
765
     * @param string $content
766
     * @param string $file
767
     *
768
     * @return Schema
769
     *
770
     * @throws IOException
771
     */
772 44
    public function readString($content, $file = 'schema.xsd')
773
    {
774 44
        $xml = new DOMDocument('1.0', 'UTF-8');
775 44
        if (!$xml->loadXML($content)) {
776
            throw new IOException("Can't load the schema");
777
        }
778 44
        $xml->documentURI = $file;
779
780 44
        return $this->readNode($xml->documentElement, $file);
781
    }
782
783
    /**
784
     * @param string $file
785
     *
786
     * @return Schema
787
     */
788 1
    public function readFile($file)
789
    {
790 1
        $xml = $this->getDOM($file);
791 1
        return $this->readNode($xml->documentElement, $file);
792
    }
793
794
    /**
795
     * @param string $file
796
     *
797
     * @return DOMDocument
798
     *
799
     * @throws IOException
800
     */
801 45
    private function getDOM($file)
802
    {
803 45
        $xml = new DOMDocument('1.0', 'UTF-8');
804 45
        if (!$xml->load($file)) {
805
            throw new IOException("Can't load the file $file");
806
        }
807 45
        return $xml;
808
    }
809
}
810