Completed
Pull Request — 0.2 (#47)
by Carsten
03:11
created

SchemaReader::addKnownNamespaceSchemaLocation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
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 $knownNamespaceSchemaLocations = array();
44
45
    private static $globalSchemaInfo = array(
46
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
47
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd'
48
    );
49
50 55
    public function __construct()
51
    {
52 55
        $this->addKnownSchemaLocation('http://www.w3.org/2001/xml.xsd', __DIR__ . '/Resources/xml.xsd');
53 55
        $this->addKnownSchemaLocation('http://www.w3.org/2001/XMLSchema.xsd', __DIR__ . '/Resources/XMLSchema.xsd');
54 55
        $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');
55 55
        $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');
56 55
        $this->addKnownSchemaLocation('https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__ . '/Resources/xmldsig-core-schema.xsd');
57 55
        $this->addKnownSchemaLocation('http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__ . '/Resources/xmldsig-core-schema.xsd');
58 55
    }
59
60
    /**
61
     * Override remote location with a local file.
62
     *
63
     * @param string $remote remote schema URL
64
     * @param string $local  local file path
65
     */
66 55
    public function addKnownSchemaLocation($remote, $local)
67
    {
68 55
        $this->knownLocationSchemas[$remote] = $local;
69 55
    }
70
71
    /**
72
     * Specify schema location by namespace.
73
     * This can be used for schemas which import namespaces but do not specify schemaLocation attributes.
74
     *
75
     * @param string $namespace namespace
76
     * @param string $location  schema URL
77
     */
78 1
    public function addKnownNamespaceSchemaLocation($namespace, $location)
79
    {
80 1
        $this->knownNamespaceSchemaLocations[$namespace] = $location;
81 1
    }
82
83 46
    private function loadAttributeGroup(Schema $schema, DOMElement $node)
84
    {
85 46
        $attGroup = new AttributeGroup($schema, $node->getAttribute("name"));
86 46
        $attGroup->setDoc($this->getDocumentation($node));
87 46
        $schema->addAttributeGroup($attGroup);
88
89
        return function () use ($schema, $node, $attGroup) {
90 46
            foreach ($node->childNodes as $childNode) {
91 46
                switch ($childNode->localName) {
92 46 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...
93 46
                        if ($childNode->hasAttribute("ref")) {
94 46
                            $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
95 46
                        } else {
96 46
                            $attribute = $this->loadAttribute($schema, $childNode);
97
                        }
98 46
                        $attGroup->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 94 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...
99 46
                        break;
100 46 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...
101
102 1
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
103 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 102 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...
104 1
                        break;
105 46
                }
106 46
            }
107 46
        };
108
    }
109
110 46
    private function loadAttribute(Schema $schema, DOMElement $node)
111
    {
112 46
        $attribute = new Attribute($schema, $node->getAttribute("name"));
113 46
        $attribute->setDoc($this->getDocumentation($node));
114 46
        $this->fillItem($attribute, $node);
115
116 46
        if ($node->hasAttribute("nillable")) {
117 1
            $attribute->setNil($node->getAttribute("nillable") == "true");
118 1
        }
119 46
        if ($node->hasAttribute("form")) {
120 1
            $attribute->setQualified($node->getAttribute("form") == "qualified");
121 1
        }
122 46
        if ($node->hasAttribute("use")) {
123 46
            $attribute->setUse($node->getAttribute("use"));
124 46
        }
125 46
        return $attribute;
126
    }
127
128
129 46 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...
130
    {
131 46
        $attribute = new AttributeDef($schema, $node->getAttribute("name"));
132
133 46
        $schema->addAttribute($attribute);
134
135
        return function () use ($attribute, $schema, $node) {
136 46
            $this->fillItem($attribute, $node);
137 46
        };
138
    }
139
140
    /**
141
     * @param DOMElement $node
142
     * @return string
143
     */
144 46
    private function getDocumentation(DOMElement $node)
145
    {
146 46
        $doc = '';
147 46
        foreach ($node->childNodes as $childNode) {
148 46
            if ($childNode->localName == "annotation") {
149 46
                foreach ($childNode->childNodes as $subChildNode) {
150 46
                    if ($subChildNode->localName == "documentation") {
151 46
                        $doc .= ($subChildNode->nodeValue);
152 46
                    }
153 46
                }
154 46
            }
155 46
        }
156 46
        $doc = preg_replace('/[\t ]+/', ' ', $doc);
157 46
        return trim($doc);
158
    }
159
160
    /**
161
     *
162
     * @param Schema $schema
163
     * @param DOMElement $node
164
     * @param Schema $parent
165
     * @return array
166
     */
167 46
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null)
168
    {
169 46
        $schema->setDoc($this->getDocumentation($node));
170
171 46
        if ($node->hasAttribute("targetNamespace")) {
172 46
            $schema->setTargetNamespace($node->getAttribute("targetNamespace"));
173 46
        } elseif ($parent) {
174
            $schema->setTargetNamespace($parent->getTargetNamespace());
175
        }
176 46
        $schema->setElementsQualification($node->getAttribute("elementFormDefault") == "qualified");
177 46
        $schema->setAttributesQualification($node->getAttribute("attributeFormDefault") == "qualified");
178 46
        $schema->setDoc($this->getDocumentation($node));
179 46
        $functions = array();
180
181 46
        foreach ($node->childNodes as $childNode) {
182 46
            switch ($childNode->localName) {
183 46
                case 'include':
184 46
                case 'import':
185 46
                    $functions[] = $this->loadImport($schema, $childNode);
186 46
                    break;
187 46
                case 'element':
188 46
                    $functions[] = $this->loadElementDef($schema, $childNode);
189 46
                    break;
190 46
                case 'attribute':
191 46
                    $functions[] = $this->loadAttributeDef($schema, $childNode);
192 46
                    break;
193 46
                case 'attributeGroup':
194 46
                    $functions[] = $this->loadAttributeGroup($schema, $childNode);
195 46
                    break;
196 46
                case 'group':
197 46
                    $functions[] = $this->loadGroup($schema, $childNode);
198 46
                    break;
199 46
                case 'complexType':
200 46
                    $functions[] = $this->loadComplexType($schema, $childNode);
201 46
                    break;
202 46
                case 'simpleType':
203 46
                    $functions[] = $this->loadSimpleType($schema, $childNode);
204 46
                    break;
205 46
            }
206 46
        }
207
208 46
        return $functions;
209
    }
210
211 46
    private function loadElement(Schema $schema, DOMElement $node)
212
    {
213 46
        $element = new Element($schema, $node->getAttribute("name"));
214 46
        $element->setDoc($this->getDocumentation($node));
215
216 46
        $this->fillItem($element, $node);
217
218 46
        if ($node->hasAttribute("maxOccurs")) {
219 46
            $element->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
220 46
        }
221 46
        if ($node->hasAttribute("minOccurs")) {
222 46
            $element->setMin((int)$node->getAttribute("minOccurs"));
223 46
        }
224
225 46
        $xp = new \DOMXPath($node->ownerDocument);
226 46
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
227
        
228 46
        if ($xp->query('ancestor::xs:choice', $node)->length) {
229 46
            $element->setMin(0);
230 46
        }
231
232 46
        if ($node->hasAttribute("nillable")) {
233 3
            $element->setNil($node->getAttribute("nillable") == "true");
234 3
        }
235 46
        if ($node->hasAttribute("form")) {
236 3
            $element->setQualified($node->getAttribute("form") == "qualified");
237 3
        }
238 46
        return $element;
239
    }
240
241 46
    private function loadGroupRef(Group $referenced, DOMElement $node)
242
    {
243 46
        $ref = new GroupRef($referenced);
244 46
        $ref->setDoc($this->getDocumentation($node));
245
246 46 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...
247 46
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
248 46
        }
249 46
        if ($node->hasAttribute("minOccurs")) {
250 46
            $ref->setMin((int)$node->getAttribute("minOccurs"));
251 46
        }
252
253 46
        return $ref;
254
    }
255
256 46
    private function loadElementRef(ElementDef $referenced, DOMElement $node)
257
    {
258 46
        $ref = new ElementRef($referenced);
259 46
        $ref->setDoc($this->getDocumentation($node));
260
261 46 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...
262 46
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
263 46
        }
264 46
        if ($node->hasAttribute("minOccurs")) {
265 46
            $ref->setMin((int)$node->getAttribute("minOccurs"));
266 46
        }
267 46
        if ($node->hasAttribute("nillable")) {
268
            $ref->setNil($node->getAttribute("nillable") == "true");
269
        }
270 46
        if ($node->hasAttribute("form")) {
271
            $ref->setQualified($node->getAttribute("form") == "qualified");
272
        }
273
274 46
        return $ref;
275
    }
276
277
278 46
    private function loadAttributeRef(AttributeDef $referencedAttribiute, DOMElement $node)
279
    {
280 46
        $attribute = new AttributeRef($referencedAttribiute);
281 46
        $attribute->setDoc($this->getDocumentation($node));
282
283 46
        if ($node->hasAttribute("nillable")) {
284
            $attribute->setNil($node->getAttribute("nillable") == "true");
285
        }
286 46
        if ($node->hasAttribute("form")) {
287
            $attribute->setQualified($node->getAttribute("form") == "qualified");
288
        }
289 46
        if ($node->hasAttribute("use")) {
290
            $attribute->setUse($node->getAttribute("use"));
291
        }
292 46
        return $attribute;
293
    }
294
295 46
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null)
296
    {
297 46
        $max = $max || $node->getAttribute("maxOccurs") == "unbounded" || $node->getAttribute("maxOccurs") > 1 ? 2 : null;
298
299 46
        foreach ($node->childNodes as $childNode) {
300
301 46
            switch ($childNode->localName) {
302 46
                case 'choice':
303 46
                case 'sequence':
304 46
                case 'all':
305 46
                    $this->loadSequence($elementContainer, $childNode, $max);
306 46
                    break;
307 46
                case 'element':
308 46
                    if ($childNode->hasAttribute("ref")) {
309 46
                        $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
310 46
                        $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 309 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...
311 46
                    } else {
312 46
                        $element = $this->loadElement($elementContainer->getSchema(), $childNode);
313
                    }
314 46
                    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...
315 46
                        $element->setMax($max);
316 46
                    }
317 46
                    $elementContainer->addElement($element);
318 46
                    break;
319 46 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...
320 46
                    $referencedGroup = $this->findSomething('findGroup', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
321
322 46
                    $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 320 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...
323 46
                    $elementContainer->addElement($group);
324 46
                    break;
325 46
            }
326 46
        }
327 46
    }
328
329 46
    private function loadGroup(Schema $schema, DOMElement $node)
330
    {
331 46
        $group = new Group($schema, $node->getAttribute("name"));
332 46
        $group->setDoc($this->getDocumentation($node));
333
334 46 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...
335
            $group->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
336
        }
337 46
        if ($node->hasAttribute("minOccurs")) {
338
            $group->setMin((int)$node->getAttribute("minOccurs"));
339
        }
340
341 46
        $schema->addGroup($group);
342
343
        return function () use ($group, $node) {
344 46
            foreach ($node->childNodes as $childNode) {
345 46
                switch ($childNode->localName) {
346 46
                    case 'sequence':
347 46
                    case 'choice':
348 46
                    case 'all':
349 46
                        $this->loadSequence($group, $childNode);
350 46
                        break;
351 46
                }
352 46
            }
353 46
        };
354
    }
355
356 46
    private function loadComplexType(Schema $schema, DOMElement $node, $callback = null)
357
    {
358 46
        $isSimple = false;
359
360 46
        foreach ($node->childNodes as $childNode) {
361 46
            if ($childNode->localName === "simpleContent") {
362 2
                $isSimple = true;
363 2
                break;
364
            }
365 46
        }
366
367 46
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute("name")) : new ComplexType($schema, $node->getAttribute("name"));
368
369 46
        $type->setDoc($this->getDocumentation($node));
370 46
        if ($node->getAttribute("name")) {
371 46
            $schema->addType($type);
372 46
        }
373
374
        return function () use ($type, $node, $schema, $callback) {
375
376 46
            $this->fillTypeNode($type, $node);
377
378 46
            foreach ($node->childNodes as $childNode) {
379 46
                switch ($childNode->localName) {
380 46
                    case 'sequence':
381 46
                    case 'choice':
382 46
                    case 'all':
383 46
                        $this->loadSequence($type, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $type defined by $isSimple ? new \GoetasW...->getAttribute('name')) on line 367 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...
384 46
                        break;
385 46
                    case 'attribute':
386 46
                        if ($childNode->hasAttribute("ref")) {
387 46
                            $referencedAttribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
388 46
                            $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 387 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...
389 46
                        } else {
390 46
                            $attribute = $this->loadAttribute($schema, $childNode);
391
                        }
392
393 46
                        $type->addAttribute($attribute);
394 46
                        break;
395 46 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...
396 1
                        $referencedGroup = $this->findSomething('findGroup', $schema, $node, $childNode->getAttribute("ref"));
397 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 396 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...
398 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...
399 1
                        break;
400 46 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...
401 2
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
402 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 401 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...
403 2
                        break;
404 46
                }
405 46
            }
406
407 46
            if ($callback) {
408 46
                call_user_func($callback, $type);
409 46
            }
410 46
        };
411
    }
412
413 46
    private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null)
414
    {
415 46
        $type = new SimpleType($schema, $node->getAttribute("name"));
416 46
        $type->setDoc($this->getDocumentation($node));
417 46
        if ($node->getAttribute("name")) {
418 46
            $schema->addType($type);
419 46
        }
420
421
        return function () use ($type, $node, $callback) {
422 46
            $this->fillTypeNode($type, $node);
423
424 46
            foreach ($node->childNodes as $childNode) {
425 46
                switch ($childNode->localName) {
426 46
                    case 'union':
427 46
                        $this->loadUnion($type, $childNode);
428 46
                        break;
429 46
                    case 'list':
430 46
                        $this->loadList($type, $childNode);
431 46
                        break;
432 46
                }
433 46
            }
434
435 46
            if ($callback) {
436 46
                call_user_func($callback, $type);
437 46
            }
438 46
        };
439
    }
440
441 46
    private function loadList(SimpleType $type, DOMElement $node)
442
    {
443 46 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...
444 46
            $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...
445 46
        } else {
446
            $addCallback = function ($list) use ($type) {
447 46
                $type->setList($list);
448 46
            };
449
450 46
            foreach ($node->childNodes as $childNode) {
451 46
                switch ($childNode->localName) {
452 46
                    case 'simpleType':
453 46
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
454 46
                        break;
455 46
                }
456 46
            }
457
        }
458 46
    }
459
460 46
    private function loadUnion(SimpleType $type, DOMElement $node)
461
    {
462 46
        if ($node->hasAttribute("memberTypes")) {
463 46
            $types = preg_split('/\s+/', $node->getAttribute("memberTypes"));
464 46
            foreach ($types as $typeName) {
465 46
                $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...
466 46
            }
467 46
        }
468
        $addCallback = function ($unType) use ($type) {
469 46
            $type->addUnion($unType);
470 46
        };
471
472 46
        foreach ($node->childNodes as $childNode) {
473 46
            switch ($childNode->localName) {
474 46
                case 'simpleType':
475 46
                    call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
476 46
                    break;
477 46
            }
478 46
        }
479 46
    }
480
481 46
    private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = true)
482
    {
483
484 46
        if ($checkAbstract) {
485 46
            $type->setAbstract($node->getAttribute("abstract") === "true" || $node->getAttribute("abstract") === "1");
486 46
        }
487
488 46
        foreach ($node->childNodes as $childNode) {
489 46
            switch ($childNode->localName) {
490 46
                case 'restriction':
491 46
                    $this->loadRestriction($type, $childNode);
492 46
                    break;
493 46
                case 'extension':
494 46
                    $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...
495 46
                    break;
496 46
                case 'simpleContent':
497 46
                case 'complexContent':
498 46
                    $this->fillTypeNode($type, $childNode, false);
499 46
                    break;
500 46
            }
501 46
        }
502 46
    }
503
504 46
    private function loadExtension(BaseComplexType $type, DOMElement $node)
505
    {
506 46
        $extension = new Extension();
507 46
        $type->setExtension($extension);
508
509 46
        if ($node->hasAttribute("base")) {
510 46
            $parent = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
511 46
            $extension->setBase($parent);
0 ignored issues
show
Bug introduced by
It seems like $parent defined by $this->findSomething('fi...->getAttribute('base')) on line 510 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...
512 46
        }
513
514 46
        foreach ($node->childNodes as $childNode) {
515 46
            switch ($childNode->localName) {
516 46
                case 'sequence':
517 46
                case 'choice':
518 46
                case 'all':
519 46
                    $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...
520 46
                    break;
521 46 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...
522 46
                    if ($childNode->hasAttribute("ref")) {
523 46
                        $attribute = $this->findSomething('findAttribute', $type->getSchema(), $node, $childNode->getAttribute("ref"));
524 46
                    } else {
525 46
                        $attribute = $this->loadAttribute($type->getSchema(), $childNode);
526
                    }
527 46
                    $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 523 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...
528 46
                    break;
529 46
                case 'attributeGroup':
530 46
                    $attribute = $this->findSomething('findAttributeGroup', $type->getSchema(), $node, $childNode->getAttribute("ref"));
531 46
                    $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 530 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...
532 46
                    break;
533 46
            }
534 46
        }
535 46
    }
536
537 46
    private function loadRestriction(Type $type, DOMElement $node)
538
    {
539 46
        $restriction = new Restriction();
540 46
        $type->setRestriction($restriction);
541 46 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...
542 46
            $restrictedType = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
543 46
            $restriction->setBase($restrictedType);
0 ignored issues
show
Bug introduced by
It seems like $restrictedType defined by $this->findSomething('fi...->getAttribute('base')) on line 542 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...
544 46
        } else {
545
            $addCallback = function ($restType) use ($restriction) {
546 46
                $restriction->setBase($restType);
547 46
            };
548
549 46
            foreach ($node->childNodes as $childNode) {
550 46
                switch ($childNode->localName) {
551 46
                    case 'simpleType':
552 46
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
553 46
                        break;
554 46
                }
555 46
            }
556
        }
557 46
        foreach ($node->childNodes as $childNode) {
558 46
            if (in_array($childNode->localName,
559
                [
560 46
                    'enumeration',
561 46
                    'pattern',
562 46
                    'length',
563 46
                    'minLength',
564 46
                    'maxLength',
565 46
                    'minInclusive',
566 46
                    'maxInclusive',
567 46
                    'minExclusive',
568 46
                    'maxExclusive',
569 46
                    'fractionDigits',
570 46
                    'totalDigits',
571
                    'whiteSpace'
572 46
                ], true)) {
573 46
                $restriction->addCheck($childNode->localName,
574
                    [
575 46
                        'value' => $childNode->getAttribute("value"),
576 46
                        'doc' => $this->getDocumentation($childNode)
577 46
                    ]);
578 46
            }
579 46
        }
580 46
    }
581
582 46
    private static function splitParts(DOMElement $node, $typeName)
583
    {
584 46
        $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...
585 46
        $prefix = null;
586 46
        $name = $typeName;
587 46
        if (strpos($typeName, ':') !== false) {
588 46
            list ($prefix, $name) = explode(':', $typeName);
589 46
        }
590
591 46
        $namespace = $node->lookupNamespaceURI($prefix ?: null);
592
        return array(
593 46
            $name,
594 46
            $namespace,
595
            $prefix
596 46
        );
597
    }
598
599
    /**
600
     *
601
     * @param string $finder
602
     * @param Schema $schema
603
     * @param DOMElement $node
604
     * @param string $typeName
605
     * @throws TypeException
606
     * @return ElementItem|Group|AttributeItem|AttribiuteGroup|Type
607
     */
608 46
    private function findSomething($finder, Schema $schema, DOMElement $node, $typeName)
609
    {
610 46
        list ($name, $namespace) = self::splitParts($node, $typeName);
611
612 46
        $namespace = $namespace ?: $schema->getTargetNamespace();
613
614
        try {
615 46
            return $schema->$finder($name, $namespace);
616 1
        } catch (TypeNotFoundException $e) {
617 1
            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);
618
        }
619
    }
620
621 46 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...
622
    {
623 46
        $element = new ElementDef($schema, $node->getAttribute("name"));
624 46
        $schema->addElement($element);
625
626
        return function () use ($element, $node) {
627 46
            $this->fillItem($element, $node);
628 46
        };
629
    }
630
631 46
    private function fillItem(Item $element, DOMElement $node)
632
    {
633 46
        $localType = null;
634 46
        foreach ($node->childNodes as $childNode) {
635 46
            switch ($childNode->localName) {
636 46
                case 'complexType':
637 46
                case 'simpleType':
638 46
                    $localType = $childNode;
639 46
                    break 2;
640 46
            }
641 46
        }
642
643 46
        if ($localType) {
644
            $addCallback = function ($type) use ($element) {
645 46
                $element->setType($type);
646 46
            };
647 46
            switch ($localType->localName) {
648 46
                case 'complexType':
649 46
                    call_user_func($this->loadComplexType($element->getSchema(), $localType, $addCallback));
650 46
                    break;
651 46
                case 'simpleType':
652 46
                    call_user_func($this->loadSimpleType($element->getSchema(), $localType, $addCallback));
653 46
                    break;
654 46
            }
655 46
        } else {
656
657 46
            if ($node->getAttribute("type")) {
658 46
                $type = $this->findSomething('findType', $element->getSchema(), $node, $node->getAttribute("type"));
659 46
            } else {
660 46
                $type = $this->findSomething('findType', $element->getSchema(), $node, ($node->lookupPrefix(self::XSD_NS) . ":anyType"));
661
            }
662
663 46
            $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...
664
        }
665 46
    }
666
667 46
    private function loadImport(Schema $schema, DOMElement $node)
668
    {
669 46
        $base = urldecode($node->ownerDocument->documentURI);
670 46
        $schemaLocation = $node->getAttribute("schemaLocation");
671 46
        if (!$schemaLocation && $node->hasAttribute("namespace") && isset($this->knownNamespaceSchemaLocations[$node->getAttribute("namespace")])) {
672 1
            $schemaLocation = $this->knownNamespaceSchemaLocations[$this->knownNamespaceSchemaLocations[$node->getAttribute("namespace")]];
673 1
        }
674 46
        $file = UrlUtils::resolveRelativeUrl($base, $schemaLocation);
675 46
        if ($node->hasAttribute("namespace")
676 46
            && isset(self::$globalSchemaInfo[$node->getAttribute("namespace")])
677 46
            && isset($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]])
678 46
        ) {
679
680 46
            $schema->addSchema($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]]);
681
682
            return function () {
683 46
            };
684 4
        } elseif ($node->hasAttribute("namespace")
685 4
            && isset($this->loadedFiles[$this->getNamespaceSpecificFileIndex($file, $node->getAttribute("namespace"))])) {
686 2
            $schema->addSchema($this->loadedFiles[$this->getNamespaceSpecificFileIndex($file, $node->getAttribute("namespace"))]);
687
            return function () {
688 2
            };
689 2
        } elseif (isset($this->loadedFiles[$file])) {
690 1
            $schema->addSchema($this->loadedFiles[$file]);
691
            return function () {
692 1
            };
693
        }
694
695 2
        if (!$node->getAttribute("namespace")) {
696 1
            $this->loadedFiles[$file] = $newSchema = $schema;
697 1
        } else {
698 1
            $this->loadedFiles[$file] = $newSchema = new Schema();
699 1
            $newSchema->addSchema($this->getGlobalSchema());
700
        }
701
702 2
        $xml = $this->getDOM(isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] : $file);
703
704 2
        $callbacks = $this->schemaNode($newSchema, $xml->documentElement, $schema);
705
706 2
        if ($node->getAttribute("namespace")) {
707 1
            $schema->addSchema($newSchema);
708 1
        }
709
710
711 2
        return function () use ($callbacks) {
712 2
            foreach ($callbacks as $callback) {
713 2
                call_user_func($callback);
714 2
            }
715 2
        };
716
    }
717
718
    private $globalSchema;
719
720
    /**
721
     *
722
     * @return Schema
723
     */
724 46
    public function getGlobalSchema()
725
    {
726 46
        if (!$this->globalSchema) {
727 46
            $callbacks = array();
728 46
            $globalSchemas = array();
729 46
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
730 46
                $this->loadedFiles[$uri] = $globalSchemas [$namespace] = $schema = new Schema();
731 46
                if ($namespace === self::XSD_NS) {
732 46
                    $this->globalSchema = $schema;
733 46
                }
734 46
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
735 46
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
736 46
            }
737
738 46
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anySimpleType"));
739 46
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anyType"));
740
741 46
            $globalSchemas[self::XML_NS]->addSchema($globalSchemas[self::XSD_NS], self::XSD_NS);
742 46
            $globalSchemas[self::XSD_NS]->addSchema($globalSchemas[self::XML_NS], self::XML_NS);
743
744 46
            foreach ($callbacks as $callback) {
745 46
                $callback();
746 46
            }
747 46
        }
748 46
        return $this->globalSchema;
749
    }
750
751
    /**
752
     * @param DOMNode $node
753
     * @param string  $file
754
     * 
755
     * @return Schema
756
     */
757 46
    public function readNode(DOMNode $node, $file = 'schema.xsd')
758
    {
759 46
        $fileKey = $node instanceof DOMElement && $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file;
760 46
        $this->loadedFiles[$fileKey] = $rootSchema = new Schema();
761
762 46
        $rootSchema->addSchema($this->getGlobalSchema());
763 46
        $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...
764
765 46
        foreach ($callbacks as $callback) {
766 40
            call_user_func($callback);
767 45
        }
768
769 45
        return $rootSchema;
770
    }
771
772
    /**
773
     * It is possible that a single file contains multiple <xsd:schema/> nodes, for instance in a WSDL file.
774
     *
775
     * Each of these  <xsd:schema/> nodes typically target a specific namespace. Append the target namespace to the
776
     * file to distinguish between multiple schemas in a single file.
777
     *
778
     * @param string $file
779
     * @param string $targetNamespace
780
     *
781
     * @return string
782
     */
783 46
    private function getNamespaceSpecificFileIndex($file, $targetNamespace)
784
    {
785 46
        return $file . '#' . $targetNamespace;
786
    }
787
788
    /**
789
     * @param string $content
790
     * @param string $file
791
     *
792
     * @return Schema
793
     *
794
     * @throws IOException
795
     */
796 44
    public function readString($content, $file = 'schema.xsd')
797
    {
798 44
        $xml = new DOMDocument('1.0', 'UTF-8');
799 44
        if (!$xml->loadXML($content)) {
800
            throw new IOException("Can't load the schema");
801
        }
802 44
        $xml->documentURI = $file;
803
804 44
        return $this->readNode($xml->documentElement, $file);
805
    }
806
807
    /**
808
     * @param string $file
809
     *
810
     * @return Schema
811
     */
812 2
    public function readFile($file)
813
    {
814 2
        $xml = $this->getDOM($file);
815 2
        return $this->readNode($xml->documentElement, $file);
816
    }
817
818
    /**
819
     * @param string $file
820
     *
821
     * @return DOMDocument
822
     *
823
     * @throws IOException
824
     */
825 46
    private function getDOM($file)
826
    {
827 46
        $xml = new DOMDocument('1.0', 'UTF-8');
828 46
        if (!$xml->load($file)) {
829
            throw new IOException("Can't load the file $file");
830
        }
831 46
        return $xml;
832
    }
833
}
834