Completed
Pull Request — master (#23)
by
unknown
02:14
created

SchemaReader::getDocumentation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace GoetasWebservices\XML\XSDReader;
4
5
use DOMDocument;
6
use DOMElement;
7
use DOMNode;
8
use GoetasWebservices\XML\XSDReader\Documentation\DocumentationReader;
9
use GoetasWebservices\XML\XSDReader\Documentation\StandardDocumentationReader;
10
use GoetasWebservices\XML\XSDReader\Exception\IOException;
11
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
12
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
13
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
14
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeRef;
15
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
16
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
17
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
18
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
19
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
20
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
21
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
22
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
23
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
24
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
25
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
26
use GoetasWebservices\XML\XSDReader\Schema\Item;
27
use GoetasWebservices\XML\XSDReader\Schema\Schema;
28
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
29
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
30
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
31
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
32
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
33
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
34
35
class SchemaReader
36
{
37
    const XSD_NS = 'http://www.w3.org/2001/XMLSchema';
38
39
    const XML_NS = 'http://www.w3.org/XML/1998/namespace';
40
41
    /**
42
     * @var DocumentationReader
43
     */
44
    private $documentationReader;
45
46
    private $loadedFiles = array();
47
48
    private $knownLocationSchemas = array();
49
50
    private static $globalSchemaInfo = array(
51
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
52
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd',
53
    );
54
55 56
    public function __construct(DocumentationReader $documentationReader = null)
56
    {
57 56
        if(null === $documentationReader) {
58 56
            $documentationReader = new StandardDocumentationReader();
59 56
        }
60 56
        $this->documentationReader = $documentationReader;
61
62 56
        $this->addKnownSchemaLocation('http://www.w3.org/2001/xml.xsd', __DIR__.'/Resources/xml.xsd');
63 56
        $this->addKnownSchemaLocation('http://www.w3.org/2001/XMLSchema.xsd', __DIR__.'/Resources/XMLSchema.xsd');
64 56
        $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');
65 56
        $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');
66 56
        $this->addKnownSchemaLocation('https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__.'/Resources/xmldsig-core-schema.xsd');
67 56
        $this->addKnownSchemaLocation('http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__.'/Resources/xmldsig-core-schema.xsd');
68 56
    }
69
70 56
    public function addKnownSchemaLocation($remote, $local)
71
    {
72 56
        $this->knownLocationSchemas[$remote] = $local;
73 56
    }
74
75 47
    private function loadAttributeGroup(Schema $schema, DOMElement $node)
76
    {
77 47
        $attGroup = new AttributeGroup($schema, $node->getAttribute('name'));
78 47
        $attGroup->setDoc($this->getDocumentation($node));
79 47
        $schema->addAttributeGroup($attGroup);
80
81
        return function () use ($schema, $node, $attGroup) {
82 47
            foreach ($node->childNodes as $childNode) {
83 47
                switch ($childNode->localName) {
84 47 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...
85 47
                        if ($childNode->hasAttribute('ref')) {
86 47
                            $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute('ref'));
87 47
                        } else {
88 47
                            $attribute = $this->loadAttribute($schema, $childNode);
89
                        }
90 47
                        $attGroup->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 86 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...
91 47
                        break;
92 47 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...
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...
93
94 1
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute('ref'));
95 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 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...
96 1
                        break;
97 47
                }
98 47
            }
99 47
        };
100
    }
101
102 47
    private function loadAttribute(Schema $schema, DOMElement $node)
103
    {
104 47
        $attribute = new Attribute($schema, $node->getAttribute('name'));
105 47
        $attribute->setDoc($this->getDocumentation($node));
106 47
        $this->fillItem($attribute, $node);
107
108 47
        if ($node->hasAttribute('nillable')) {
109 1
            $attribute->setNil($node->getAttribute('nillable') == 'true');
110 1
        }
111 47
        if ($node->hasAttribute('form')) {
112 1
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
113 1
        }
114 47
        if ($node->hasAttribute('use')) {
115 47
            $attribute->setUse($node->getAttribute('use'));
116 47
        }
117
118 47
        return $attribute;
119
    }
120
121 47 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...
122
    {
123 47
        $attribute = new AttributeDef($schema, $node->getAttribute('name'));
124
125 47
        $schema->addAttribute($attribute);
126
127
        return function () use ($attribute, $schema, $node) {
128 47
            $this->fillItem($attribute, $node);
129 47
        };
130
    }
131
132
    /**
133
     * @param DOMElement $node
134
     *
135
     * @return string
136
     */
137 47
    private function getDocumentation(DOMElement $node)
138
    {
139 47
        return $this->documentationReader->get($node);
140
    }
141
142
    /**
143
     * @param Schema     $schema
144
     * @param DOMElement $node
145
     * @param Schema     $parent
146
     *
147
     * @return array
148
     */
149 47
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null)
150
    {
151 47
        $schema->setDoc($this->getDocumentation($node));
152
153 47
        if ($node->hasAttribute('targetNamespace')) {
154 47
            $schema->setTargetNamespace($node->getAttribute('targetNamespace'));
155 47
        } elseif ($parent) {
156
            $schema->setTargetNamespace($parent->getTargetNamespace());
157
        }
158 47
        $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
159 47
        $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
160 47
        $schema->setDoc($this->getDocumentation($node));
161 47
        $functions = array();
162
163 47
        foreach ($node->childNodes as $childNode) {
164 47
            switch ($childNode->localName) {
165 47
                case 'include':
166 47
                case 'import':
167 47
                    $functions[] = $this->loadImport($schema, $childNode);
168 47
                    break;
169 47
                case 'element':
170 47
                    $functions[] = $this->loadElementDef($schema, $childNode);
171 47
                    break;
172 47
                case 'attribute':
173 47
                    $functions[] = $this->loadAttributeDef($schema, $childNode);
174 47
                    break;
175 47
                case 'attributeGroup':
176 47
                    $functions[] = $this->loadAttributeGroup($schema, $childNode);
177 47
                    break;
178 47
                case 'group':
179 47
                    $functions[] = $this->loadGroup($schema, $childNode);
180 47
                    break;
181 47
                case 'complexType':
182 47
                    $functions[] = $this->loadComplexType($schema, $childNode);
183 47
                    break;
184 47
                case 'simpleType':
185 47
                    $functions[] = $this->loadSimpleType($schema, $childNode);
186 47
                    break;
187 47
            }
188 47
        }
189
190 47
        return $functions;
191
    }
192
193 47
    private function loadElement(Schema $schema, DOMElement $node)
194
    {
195 47
        $element = new Element($schema, $node->getAttribute('name'));
196 47
        $element->setDoc($this->getDocumentation($node));
197
198 47
        $this->fillItem($element, $node);
199
200 47
        if ($node->hasAttribute('maxOccurs')) {
201 47
            $element->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
202 47
        }
203 47
        if ($node->hasAttribute('minOccurs')) {
204 47
            $element->setMin((int) $node->getAttribute('minOccurs'));
205 47
        }
206
207 47
        $xp = new \DOMXPath($node->ownerDocument);
208 47
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
209
210 47
        if ($xp->query('ancestor::xs:choice', $node)->length) {
211 47
            $element->setMin(0);
212 47
        }
213
214 47
        if ($node->hasAttribute('nillable')) {
215 3
            $element->setNil($node->getAttribute('nillable') == 'true');
216 3
        }
217 47
        if ($node->hasAttribute('form')) {
218 3
            $element->setQualified($node->getAttribute('form') == 'qualified');
219 3
        }
220
221 47
        return $element;
222
    }
223
224 47
    private function loadGroupRef(Group $referenced, DOMElement $node)
225
    {
226 47
        $ref = new GroupRef($referenced);
227 47
        $ref->setDoc($this->getDocumentation($node));
228
229 47 View Code Duplication
        if ($node->hasAttribute('maxOccurs')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

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

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

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

Loading history...
245 47
            $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
246 47
        }
247 47
        if ($node->hasAttribute('minOccurs')) {
248 47
            $ref->setMin((int) $node->getAttribute('minOccurs'));
249 47
        }
250 47
        if ($node->hasAttribute('nillable')) {
251
            $ref->setNil($node->getAttribute('nillable') == 'true');
252
        }
253 47
        if ($node->hasAttribute('form')) {
254
            $ref->setQualified($node->getAttribute('form') == 'qualified');
255
        }
256
257 47
        return $ref;
258
    }
259
260 47
    private function loadAttributeRef(AttributeDef $referencedAttribiute, DOMElement $node)
261
    {
262 47
        $attribute = new AttributeRef($referencedAttribiute);
263 47
        $attribute->setDoc($this->getDocumentation($node));
264
265 47
        if ($node->hasAttribute('nillable')) {
266
            $attribute->setNil($node->getAttribute('nillable') == 'true');
267
        }
268 47
        if ($node->hasAttribute('form')) {
269
            $attribute->setQualified($node->getAttribute('form') == 'qualified');
270
        }
271 47
        if ($node->hasAttribute('use')) {
272
            $attribute->setUse($node->getAttribute('use'));
273
        }
274
275 47
        return $attribute;
276
    }
277
278 47
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null)
279
    {
280 47
        $max = $max || $node->getAttribute('maxOccurs') == 'unbounded' || $node->getAttribute('maxOccurs') > 1 ? 2 : null;
281
282 47
        foreach ($node->childNodes as $childNode) {
283 47
            switch ($childNode->localName) {
284 47
                case 'choice':
285 47
                case 'sequence':
286 47
                case 'all':
287 47
                    $this->loadSequence($elementContainer, $childNode, $max);
288 47
                    break;
289 47
                case 'element':
290 47
                    if ($childNode->hasAttribute('ref')) {
291 47
                        $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute('ref'));
292 47
                        $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 291 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...
293 47
                    } else {
294 47
                        $element = $this->loadElement($elementContainer->getSchema(), $childNode);
295
                    }
296 47
                    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...
297 47
                        $element->setMax($max);
298 47
                    }
299 47
                    $elementContainer->addElement($element);
300 47
                    break;
301 47 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...
302 47
                    $referencedGroup = $this->findSomething('findGroup', $elementContainer->getSchema(), $node, $childNode->getAttribute('ref'));
303
304 47
                    $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 302 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...
305 47
                    $elementContainer->addElement($group);
306 47
                    break;
307 47
            }
308 47
        }
309 47
    }
310
311 47
    private function loadGroup(Schema $schema, DOMElement $node)
312
    {
313 47
        $group = new Group($schema, $node->getAttribute('name'));
314 47
        $group->setDoc($this->getDocumentation($node));
315
316 47 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...
317
            $group->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs'));
318
        }
319 47
        if ($node->hasAttribute('minOccurs')) {
320
            $group->setMin((int) $node->getAttribute('minOccurs'));
321
        }
322
323 47
        $schema->addGroup($group);
324
325
        return function () use ($group, $node) {
326 47
            foreach ($node->childNodes as $childNode) {
327 47
                switch ($childNode->localName) {
328 47
                    case 'sequence':
329 47
                    case 'choice':
330 47
                    case 'all':
331 47
                        $this->loadSequence($group, $childNode);
332 47
                        break;
333 47
                }
334 47
            }
335 47
        };
336
    }
337
338 47
    private function loadComplexType(Schema $schema, DOMElement $node, $callback = null)
339
    {
340 47
        $isSimple = false;
341
342 47
        foreach ($node->childNodes as $childNode) {
343 47
            if ($childNode->localName === 'simpleContent') {
344 2
                $isSimple = true;
345 2
                break;
346
            }
347 47
        }
348
349 47
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name'));
350
351 47
        $type->setDoc($this->getDocumentation($node));
352 47
        if ($node->getAttribute('name')) {
353 47
            $schema->addType($type);
354 47
        }
355
356
        return function () use ($type, $node, $schema, $callback) {
357 47
            $this->fillTypeNode($type, $node);
358
359 47
            foreach ($node->childNodes as $childNode) {
360 47
                switch ($childNode->localName) {
361 47
                    case 'sequence':
362 47
                    case 'choice':
363 47
                    case 'all':
364 47
                        $this->loadSequence($type, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $type defined by $isSimple ? new \GoetasW...->getAttribute('name')) on line 349 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...
365 47
                        break;
366 47
                    case 'attribute':
367 47
                        if ($childNode->hasAttribute('ref')) {
368 47
                            $referencedAttribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute('ref'));
369 47
                            $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 368 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...
370 47
                        } else {
371 47
                            $attribute = $this->loadAttribute($schema, $childNode);
372
                        }
373
374 47
                        $type->addAttribute($attribute);
375 47
                        break;
376 47 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...
377 1
                        $referencedGroup = $this->findSomething('findGroup', $schema, $node, $childNode->getAttribute('ref'));
378 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 377 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...
379 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...
380 1
                        break;
381 47 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...
382 2
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute('ref'));
383 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 382 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...
384 2
                        break;
385 47
                }
386 47
            }
387
388 47
            if ($callback) {
389 47
                call_user_func($callback, $type);
390 47
            }
391 47
        };
392
    }
393
394 47
    private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null)
395
    {
396 47
        $type = new SimpleType($schema, $node->getAttribute('name'));
397 47
        $type->setDoc($this->getDocumentation($node));
398 47
        if ($node->getAttribute('name')) {
399 47
            $schema->addType($type);
400 47
        }
401
402
        return function () use ($type, $node, $callback) {
403 47
            $this->fillTypeNode($type, $node);
404
405 47
            foreach ($node->childNodes as $childNode) {
406 47
                switch ($childNode->localName) {
407 47
                    case 'union':
408 47
                        $this->loadUnion($type, $childNode);
409 47
                        break;
410 47
                    case 'list':
411 47
                        $this->loadList($type, $childNode);
412 47
                        break;
413 47
                }
414 47
            }
415
416 47
            if ($callback) {
417 47
                call_user_func($callback, $type);
418 47
            }
419 47
        };
420
    }
421
422 47
    private function loadList(SimpleType $type, DOMElement $node)
423
    {
424 47 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...
425 47
            $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...
426 47
        } else {
427
            $addCallback = function ($list) use ($type) {
428 47
                $type->setList($list);
429 47
            };
430
431 47
            foreach ($node->childNodes as $childNode) {
432 47
                switch ($childNode->localName) {
433 47
                    case 'simpleType':
434 47
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
435 47
                        break;
436 47
                }
437 47
            }
438
        }
439 47
    }
440
441 47
    private function loadUnion(SimpleType $type, DOMElement $node)
442
    {
443 47
        if ($node->hasAttribute('memberTypes')) {
444 47
            $types = preg_split('/\s+/', $node->getAttribute('memberTypes'));
445 47
            foreach ($types as $typeName) {
446 47
                $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...
447 47
            }
448 47
        }
449
        $addCallback = function ($unType) use ($type) {
450 47
            $type->addUnion($unType);
451 47
        };
452
453 47
        foreach ($node->childNodes as $childNode) {
454 47
            switch ($childNode->localName) {
455 47
                case 'simpleType':
456 47
                    call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
457 47
                    break;
458 47
            }
459 47
        }
460 47
    }
461
462 47
    private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = true)
463
    {
464 47
        if ($checkAbstract) {
465 47
            $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1');
466 47
        }
467
468 47
        foreach ($node->childNodes as $childNode) {
469 47
            switch ($childNode->localName) {
470 47
                case 'restriction':
471 47
                    $this->loadRestriction($type, $childNode);
472 47
                    break;
473 47
                case 'extension':
474 47
                    $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 47
                    break;
476 47
                case 'simpleContent':
477 47
                case 'complexContent':
478 47
                    $this->fillTypeNode($type, $childNode, false);
479 47
                    break;
480 47
            }
481 47
        }
482 47
    }
483
484 47
    private function loadExtension(BaseComplexType $type, DOMElement $node)
485
    {
486 47
        $extension = new Extension();
487 47
        $type->setExtension($extension);
488
489 47
        if ($node->hasAttribute('base')) {
490 47
            $parent = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute('base'));
491 47
            $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 47
        }
493
494 47
        foreach ($node->childNodes as $childNode) {
495 47
            switch ($childNode->localName) {
496 47
                case 'sequence':
497 47
                case 'choice':
498 47
                case 'all':
499 47
                    $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 47
                    break;
501 47 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 47
                    if ($childNode->hasAttribute('ref')) {
503 47
                        $attribute = $this->findSomething('findAttribute', $type->getSchema(), $node, $childNode->getAttribute('ref'));
504 47
                    } else {
505 47
                        $attribute = $this->loadAttribute($type->getSchema(), $childNode);
506
                    }
507 47
                    $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 47
                    break;
509 47
                case 'attributeGroup':
510 47
                    $attribute = $this->findSomething('findAttributeGroup', $type->getSchema(), $node, $childNode->getAttribute('ref'));
511 47
                    $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 47
                    break;
513 47
            }
514 47
        }
515 47
    }
516
517 47
    private function loadRestriction(Type $type, DOMElement $node)
518
    {
519 47
        $restriction = new Restriction();
520 47
        $type->setRestriction($restriction);
521 47 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 47
            $restrictedType = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute('base'));
523 47
            $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 47
        } else {
525
            $addCallback = function ($restType) use ($restriction) {
526 47
                $restriction->setBase($restType);
527 47
            };
528
529 47
            foreach ($node->childNodes as $childNode) {
530 47
                switch ($childNode->localName) {
531 47
                    case 'simpleType':
532 47
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
533 47
                        break;
534 47
                }
535 47
            }
536
        }
537 47
        foreach ($node->childNodes as $childNode) {
538 47
            if (in_array($childNode->localName,
539
                [
540 47
                    'enumeration',
541 47
                    'pattern',
542 47
                    'length',
543 47
                    'minLength',
544 47
                    'maxLength',
545 47
                    'minInclusive',
546 47
                    'maxInclusive',
547 47
                    'minExclusive',
548 47
                    'maxExclusive',
549 47
                    'fractionDigits',
550 47
                    'totalDigits',
551 47
                    'whiteSpace',
552 47
                ], true)) {
553 47
                $restriction->addCheck($childNode->localName,
554
                    [
555 47
                        'value' => $childNode->getAttribute('value'),
556 47
                        'doc' => $this->getDocumentation($childNode),
557 47
                    ]);
558 47
            }
559 47
        }
560 47
    }
561
562 47
    private static function splitParts(DOMElement $node, $typeName)
563
    {
564 47
        $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 47
        $prefix = null;
566 47
        $name = $typeName;
567 47
        if (strpos($typeName, ':') !== false) {
568 47
            list($prefix, $name) = explode(':', $typeName);
569 47
        }
570
571 47
        $namespace = $node->lookupNamespaceURI($prefix ?: null);
572
573
        return array(
574 47
            $name,
575 47
            $namespace,
576 47
            $prefix,
577 47
        );
578
    }
579
580
    /**
581
     * @param string     $finder
582
     * @param Schema     $schema
583
     * @param DOMElement $node
584
     * @param string     $typeName
585
     *
586
     * @throws TypeException
587
     *
588
     * @return ElementItem|Group|AttributeItem|AttribiuteGroup|Type
589
     */
590 47
    private function findSomething($finder, Schema $schema, DOMElement $node, $typeName)
591
    {
592 47
        list($name, $namespace) = self::splitParts($node, $typeName);
593
594 47
        $namespace = $namespace ?: $schema->getTargetNamespace();
595
596
        try {
597 47
            return $schema->$finder($name, $namespace);
598
        } catch (TypeNotFoundException $e) {
599
            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);
600
        }
601
    }
602
603 47 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...
604
    {
605 47
        $element = new ElementDef($schema, $node->getAttribute('name'));
606 47
        $schema->addElement($element);
607
608
        return function () use ($element, $node) {
609 47
            $this->fillItem($element, $node);
610 47
        };
611
    }
612
613 47
    private function fillItem(Item $element, DOMElement $node)
614
    {
615 47
        $localType = null;
616 47
        foreach ($node->childNodes as $childNode) {
617 47
            switch ($childNode->localName) {
618 47
                case 'complexType':
619 47
                case 'simpleType':
620 47
                    $localType = $childNode;
621 47
                    break 2;
622 47
            }
623 47
        }
624
625 47
        if ($localType) {
626
            $addCallback = function ($type) use ($element) {
627 47
                $element->setType($type);
628 47
            };
629 47
            switch ($localType->localName) {
630 47
                case 'complexType':
631 47
                    call_user_func($this->loadComplexType($element->getSchema(), $localType, $addCallback));
632 47
                    break;
633 47
                case 'simpleType':
634 47
                    call_user_func($this->loadSimpleType($element->getSchema(), $localType, $addCallback));
635 47
                    break;
636 47
            }
637 47
        } else {
638 47
            if ($node->getAttribute('type')) {
639 47
                $type = $this->findSomething('findType', $element->getSchema(), $node, $node->getAttribute('type'));
640 47
            } else {
641 47
                $type = $this->findSomething('findType', $element->getSchema(), $node, ($node->lookupPrefix(self::XSD_NS).':anyType'));
642
            }
643
644 47
            $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...
645
        }
646 47
    }
647
648 47
    private function loadImport(Schema $schema, DOMElement $node)
649
    {
650 47
        $base = urldecode($node->ownerDocument->documentURI);
651 47
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation'));
652 47
        if ($node->hasAttribute('namespace')
653 47
            && isset(self::$globalSchemaInfo[$node->getAttribute('namespace')])
654 47
            && isset($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute('namespace')]])
655 47
        ) {
656 47
            $schema->addSchema($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute('namespace')]]);
657
658
            return function () {
659 47
            };
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
664
            return function () {
665 2
            };
666 1
        } elseif (isset($this->loadedFiles[$file])) {
667
            $schema->addSchema($this->loadedFiles[$file]);
668
669
            return function () {
670
            };
671
        }
672
673 1
        if (!$node->getAttribute('namespace')) {
674 1
            $this->loadedFiles[$file] = $newSchema = $schema;
675 1
        } else {
676
            $this->loadedFiles[$file] = $newSchema = new Schema();
677
            $newSchema->addSchema($this->getGlobalSchema());
678
        }
679
680 1
        $xml = $this->getDOM(isset($this->knownLocationSchemas[$file]) ? $this->knownLocationSchemas[$file] : $file);
681
682 1
        $callbacks = $this->schemaNode($newSchema, $xml->documentElement, $schema);
683
684 1
        if ($node->getAttribute('namespace')) {
685
            $schema->addSchema($newSchema);
686
        }
687
688 1
        return function () use ($callbacks) {
689 1
            foreach ($callbacks as $callback) {
690 1
                call_user_func($callback);
691 1
            }
692 1
        };
693
    }
694
695
    private $globalSchema;
696
697
    /**
698
     * @return Schema
699
     */
700 47
    public function getGlobalSchema()
701
    {
702 47
        if (!$this->globalSchema) {
703 47
            $callbacks = array();
704 47
            $globalSchemas = array();
705 47
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
706 47
                $this->loadedFiles[$uri] = $globalSchemas[$namespace] = $schema = new Schema();
707 47
                if ($namespace === self::XSD_NS) {
708 47
                    $this->globalSchema = $schema;
709 47
                }
710 47
                $xml = $this->getDOM($this->knownLocationSchemas[$uri]);
711 47
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
712 47
            }
713
714 47
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], 'anySimpleType'));
715 47
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], 'anyType'));
716
717 47
            $globalSchemas[self::XML_NS]->addSchema($globalSchemas[self::XSD_NS], self::XSD_NS);
718 47
            $globalSchemas[self::XSD_NS]->addSchema($globalSchemas[self::XML_NS], self::XML_NS);
719
720 47
            foreach ($callbacks as $callback) {
721 47
                $callback();
722 47
            }
723 47
        }
724
725 47
        return $this->globalSchema;
726
    }
727
728
    /**
729
     * @param DOMNode $node
730
     * @param string  $file
731
     *
732
     * @return Schema
733
     */
734 47
    public function readNode(DOMNode $node, $file = 'schema.xsd')
735
    {
736 47
        $fileKey = $node instanceof DOMElement && $node->hasAttribute('targetNamespace') ? $this->getNamespaceSpecificFileIndex($file, $node->getAttribute('targetNamespace')) : $file;
737 47
        $this->loadedFiles[$fileKey] = $rootSchema = new Schema();
738
739 47
        $rootSchema->addSchema($this->getGlobalSchema());
740 47
        $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...
741
742 47
        foreach ($callbacks as $callback) {
743 41
            call_user_func($callback);
744 47
        }
745
746 47
        return $rootSchema;
747
    }
748
749
    /**
750
     * It is possible that a single file contains multiple <xsd:schema/> nodes, for instance in a WSDL file.
751
     *
752
     * Each of these  <xsd:schema/> nodes typically target a specific namespace. Append the target namespace to the
753
     * file to distinguish between multiple schemas in a single file.
754
     *
755
     * @param string $file
756
     * @param string $targetNamespace
757
     *
758
     * @return string
759
     */
760 47
    private function getNamespaceSpecificFileIndex($file, $targetNamespace)
761
    {
762 47
        return $file.'#'.$targetNamespace;
763
    }
764
765
    /**
766
     * @param string $content
767
     * @param string $file
768
     *
769
     * @return Schema
770
     *
771
     * @throws IOException
772
     */
773 46
    public function readString($content, $file = 'schema.xsd')
774
    {
775 46
        $xml = new DOMDocument('1.0', 'UTF-8');
776 46
        if (!$xml->loadXML($content)) {
777
            throw new IOException("Can't load the schema");
778
        }
779 46
        $xml->documentURI = $file;
780
781 46
        return $this->readNode($xml->documentElement, $file);
782
    }
783
784
    /**
785
     * @param string $file
786
     *
787
     * @return Schema
788
     */
789 1
    public function readFile($file)
790
    {
791 1
        $xml = $this->getDOM($file);
792
793 1
        return $this->readNode($xml->documentElement, $file);
794
    }
795
796
    /**
797
     * @param string $file
798
     *
799
     * @return DOMDocument
800
     *
801
     * @throws IOException
802
     */
803 47
    private function getDOM($file)
804
    {
805 47
        $xml = new DOMDocument('1.0', 'UTF-8');
806 47
        if (!$xml->load($file)) {
807
            throw new IOException("Can't load the file $file");
808
        }
809
810 47
        return $xml;
811
    }
812
}
813