Completed
Push — master ( 842051...bd4e7a )
by Asmir
04:21
created

SchemaReader::loadUnion()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 17
cts 17
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 12
nc 6
nop 2
crap 5
1
<?php
2
namespace GoetasWebservices\XML\XSDReader;
3
4
use DOMDocument;
5
use DOMElement;
6
use GoetasWebservices\XML\XSDReader\Exception\IOException;
7
use GoetasWebservices\XML\XSDReader\Exception\TypeException;
8
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute;
9
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
10
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeRef;
11
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
12
use GoetasWebservices\XML\XSDReader\Schema\Element\Element;
13
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer;
14
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
15
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
16
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef;
17
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
18
use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef;
19
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
20
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension;
21
use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction;
22
use GoetasWebservices\XML\XSDReader\Schema\Item;
23
use GoetasWebservices\XML\XSDReader\Schema\Schema;
24
use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType;
25
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType;
26
use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent;
27
use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType;
28
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
29
use GoetasWebservices\XML\XSDReader\Utils\UrlUtils;
30
31
class SchemaReader
32
{
33
34
    const XSD_NS = "http://www.w3.org/2001/XMLSchema";
35
36
    const XML_NS = "http://www.w3.org/XML/1998/namespace";
37
38
    private $loadedFiles = array();
39
40
    private $knowLocationSchemas = array();
41
42
    private static $globalSchemaInfo = array(
43
        self::XML_NS => 'http://www.w3.org/2001/xml.xsd',
44
        self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd'
45
    );
46
47 52
    public function __construct()
48
    {
49 52
        $this->addKnownSchemaLocation('http://www.w3.org/2001/xml.xsd', __DIR__ . '/Resources/xml.xsd');
50 52
        $this->addKnownSchemaLocation('http://www.w3.org/2001/XMLSchema.xsd', __DIR__ . '/Resources/XMLSchema.xsd');
51 52
        $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');
52 52
        $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');
53 52
        $this->addKnownSchemaLocation('https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__ . '/Resources/xmldsig-core-schema.xsd');
54 52
        $this->addKnownSchemaLocation('http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd', __DIR__ . '/Resources/xmldsig-core-schema.xsd');
55 52
    }
56
57 52
    public function addKnownSchemaLocation($remote, $local)
58
    {
59 52
        $this->knowLocationSchemas[$remote] = $local;
60 52
    }
61
62 43
    private function loadAttributeGroup(Schema $schema, DOMElement $node)
63
    {
64 43
        $attGroup = new AttributeGroup($schema, $node->getAttribute("name"));
65 43
        $attGroup->setDoc($this->getDocumentation($node));
66 43
        $schema->addAttributeGroup($attGroup);
67
68
        return function () use ($schema, $node, $attGroup) {
69 43
            foreach ($node->childNodes as $childNode) {
70 43
                switch ($childNode->localName) {
71 43 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...
72 43
                        if ($childNode->hasAttribute("ref")) {
73 43
                            $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
74 43
                        } else {
75 43
                            $attribute = $this->loadAttribute($schema, $childNode);
76
                        }
77 43
                        $attGroup->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 73 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...
78 43
                        break;
79 43 View Code Duplication
                    case 'attributeGroup':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

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

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

    doSomethingElse(); //wrong
    break;

}

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

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

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

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

Loading history...
80
81 1
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
82 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 81 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...
83 1
                        break;
84 43
                }
85 43
            }
86 43
        };
87
    }
88
89 43
    private function loadAttribute(Schema $schema, DOMElement $node)
90
    {
91 43
        $attribute = new Attribute($schema, $node->getAttribute("name"));
92 43
        $attribute->setDoc($this->getDocumentation($node));
93 43
        $this->fillItem($attribute, $node);
94
95 43
        if ($node->hasAttribute("nillable")) {
96 1
            $attribute->setNil($node->getAttribute("nillable") == "true");
97 1
        }
98 43
        if ($node->hasAttribute("form")) {
99 1
            $attribute->setQualified($node->getAttribute("form") == "qualified");
100 1
        }
101 43
        if ($node->hasAttribute("use")) {
102 43
            $attribute->setUse($node->getAttribute("use"));
103 43
        }
104 43
        return $attribute;
105
    }
106
107
108 43 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...
109
    {
110 43
        $attribute = new AttributeDef($schema, $node->getAttribute("name"));
111
112 43
        $schema->addAttribute($attribute);
113
114
        return function () use ($attribute, $schema, $node) {
115 43
            $this->fillItem($attribute, $node);
116 43
        };
117
    }
118
119
    /**
120
     * @param DOMElement $node
121
     * @return string
122
     */
123 43
    private function getDocumentation(DOMElement $node)
124
    {
125 43
        $doc = '';
126 43
        foreach ($node->childNodes as $childNode) {
127 43
            if ($childNode->localName == "annotation") {
128 43
                foreach ($childNode->childNodes as $subChildNode) {
129 43
                    if ($subChildNode->localName == "documentation") {
130 43
                        $doc .= ($subChildNode->nodeValue);
131 43
                    }
132 43
                }
133 43
            }
134 43
        }
135 43
        $doc = preg_replace('/[\t ]+/', ' ', $doc);
136 43
        return trim($doc);
137
    }
138
139
    /**
140
     *
141
     * @param Schema $schema
142
     * @param DOMElement $node
143
     * @param Schema $parent
144
     * @return array
145
     */
146 43
    private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null)
147
    {
148 43
        $schema->setDoc($this->getDocumentation($node));
149
150 43
        if ($node->hasAttribute("targetNamespace")) {
151 43
            $schema->setTargetNamespace($node->getAttribute("targetNamespace"));
152 43
        } elseif ($parent) {
153
            $schema->setTargetNamespace($parent->getTargetNamespace());
154
        }
155 43
        $schema->setElementsQualification($node->getAttribute("elementFormDefault") == "qualified");
156 43
        $schema->setAttributesQualification($node->getAttribute("attributeFormDefault") == "qualified");
157 43
        $schema->setDoc($this->getDocumentation($node));
158 43
        $functions = array();
159
160 43
        foreach ($node->childNodes as $childNode) {
161 43
            switch ($childNode->localName) {
162 43
                case 'include':
163 43
                case 'import':
164 43
                    $functions[] = $this->loadImport($schema, $childNode);
165 43
                    break;
166 43
                case 'element':
167 43
                    $functions[] = $this->loadElementDef($schema, $childNode);
168 43
                    break;
169 43
                case 'attribute':
170 43
                    $functions[] = $this->loadAttributeDef($schema, $childNode);
171 43
                    break;
172 43
                case 'attributeGroup':
173 43
                    $functions[] = $this->loadAttributeGroup($schema, $childNode);
174 43
                    break;
175 43
                case 'group':
176 43
                    $functions[] = $this->loadGroup($schema, $childNode);
177 43
                    break;
178 43
                case 'complexType':
179 43
                    $functions[] = $this->loadComplexType($schema, $childNode);
180 43
                    break;
181 43
                case 'simpleType':
182 43
                    $functions[] = $this->loadSimpleType($schema, $childNode);
183 43
                    break;
184 43
            }
185 43
        }
186
187 43
        return $functions;
188
    }
189
190 43
    private function loadElement(Schema $schema, DOMElement $node)
191
    {
192 43
        $element = new Element($schema, $node->getAttribute("name"));
193 43
        $element->setDoc($this->getDocumentation($node));
194
195 43
        $this->fillItem($element, $node);
196
197 43
        if ($node->hasAttribute("maxOccurs")) {
198 43
            $element->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
199 43
        }
200 43
        if ($node->hasAttribute("minOccurs")) {
201 43
            $element->setMin((int)$node->getAttribute("minOccurs"));
202 43
        }
203
204 43
        $xp = new \DOMXPath($node->ownerDocument);
205 43
        $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema');
206
        
207 43
        if ($xp->query('ancestor::xs:choice', $node)->length) {
208 43
            $element->setMin(0);
209 43
        }
210
211 43
        if ($node->hasAttribute("nillable")) {
212 3
            $element->setNil($node->getAttribute("nillable") == "true");
213 3
        }
214 43
        if ($node->hasAttribute("form")) {
215 3
            $element->setQualified($node->getAttribute("form") == "qualified");
216 3
        }
217 43
        return $element;
218
    }
219
220 43
    private function loadGroupRef(Group $referenced, DOMElement $node)
221
    {
222 43
        $ref = new GroupRef($referenced);
223 43
        $ref->setDoc($this->getDocumentation($node));
224
225 43 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...
226 43
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
227 43
        }
228 43
        if ($node->hasAttribute("minOccurs")) {
229 43
            $ref->setMin((int)$node->getAttribute("minOccurs"));
230 43
        }
231
232 43
        return $ref;
233
    }
234
235 43
    private function loadElementRef(ElementDef $referenced, DOMElement $node)
236
    {
237 43
        $ref = new ElementRef($referenced);
238 43
        $ref->setDoc($this->getDocumentation($node));
239
240 43 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...
241 43
            $ref->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
242 43
        }
243 43
        if ($node->hasAttribute("minOccurs")) {
244 43
            $ref->setMin((int)$node->getAttribute("minOccurs"));
245 43
        }
246 43
        if ($node->hasAttribute("nillable")) {
247
            $ref->setNil($node->getAttribute("nillable") == "true");
248
        }
249 43
        if ($node->hasAttribute("form")) {
250
            $ref->setQualified($node->getAttribute("form") == "qualified");
251
        }
252
253 43
        return $ref;
254
    }
255
256
257 43
    private function loadAttributeRef(AttributeDef $referencedAttribiute, DOMElement $node)
258
    {
259 43
        $attribute = new AttributeRef($referencedAttribiute);
260 43
        $attribute->setDoc($this->getDocumentation($node));
261
262 43
        if ($node->hasAttribute("nillable")) {
263
            $attribute->setNil($node->getAttribute("nillable") == "true");
264
        }
265 43
        if ($node->hasAttribute("form")) {
266
            $attribute->setQualified($node->getAttribute("form") == "qualified");
267
        }
268 43
        if ($node->hasAttribute("use")) {
269
            $attribute->setUse($node->getAttribute("use"));
270
        }
271 43
        return $attribute;
272
    }
273
274 43
    private function loadSequence(ElementContainer $elementContainer, DOMElement $node, $max = null)
275
    {
276 43
        $max = $max || $node->getAttribute("maxOccurs") == "unbounded" || $node->getAttribute("maxOccurs") > 1 ? 2 : null;
277
278 43
        foreach ($node->childNodes as $childNode) {
279
280 43
            switch ($childNode->localName) {
281 43
                case 'choice':
282 43
                case 'sequence':
283 43
                case 'all':
284 43
                    $this->loadSequence($elementContainer, $childNode, $max);
285 43
                    break;
286 43
                case 'element':
287 43
                    if ($childNode->hasAttribute("ref")) {
288 43
                        $referencedElement = $this->findSomething('findElement', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
289 43
                        $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 288 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...
290 43
                    } else {
291 43
                        $element = $this->loadElement($elementContainer->getSchema(), $childNode);
292
                    }
293 43
                    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...
294 43
                        $element->setMax($max);
295 43
                    }
296 43
                    $elementContainer->addElement($element);
297 43
                    break;
298 43
                case 'group':
299 43
                    $referencedGroup = $this->findSomething('findGroup', $elementContainer->getSchema(), $node, $childNode->getAttribute("ref"));
300
301 43
                    $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 299 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...
302 43
                    $elementContainer->addElement($group);
303 43
                    break;
304 43
            }
305 43
        }
306 43
    }
307
308 43
    private function loadGroup(Schema $schema, DOMElement $node)
309
    {
310 43
        $group = new Group($schema, $node->getAttribute("name"));
311 43
        $group->setDoc($this->getDocumentation($node));
312
313 43 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...
314
            $group->setMax($node->getAttribute("maxOccurs") == "unbounded" ? -1 : (int)$node->getAttribute("maxOccurs"));
315
        }
316 43
        if ($node->hasAttribute("minOccurs")) {
317
            $group->setMin((int)$node->getAttribute("minOccurs"));
318
        }
319
320 43
        $schema->addGroup($group);
321
322
        return function () use ($group, $node) {
323 43
            foreach ($node->childNodes as $childNode) {
324 43
                switch ($childNode->localName) {
325 43
                    case 'sequence':
326 43
                    case 'choice':
327 43
                    case 'all':
328 43
                        $this->loadSequence($group, $childNode);
329 43
                        break;
330 43
                }
331 43
            }
332 43
        };
333
    }
334
335 43
    private function loadComplexType(Schema $schema, DOMElement $node, $callback = null)
336
    {
337 43
        $isSimple = false;
338
339 43
        foreach ($node->childNodes as $childNode) {
340 43
            if ($childNode->localName === "simpleContent") {
341 2
                $isSimple = true;
342 2
                break;
343
            }
344 43
        }
345
346 43
        $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute("name")) : new ComplexType($schema, $node->getAttribute("name"));
347
348 43
        $type->setDoc($this->getDocumentation($node));
349 43
        if ($node->getAttribute("name")) {
350 43
            $schema->addType($type);
351 43
        }
352
353
        return function () use ($type, $node, $schema, $callback) {
354
355 43
            $this->fillTypeNode($type, $node);
356
357 43
            foreach ($node->childNodes as $childNode) {
358 43
                switch ($childNode->localName) {
359 43
                    case 'sequence':
360 43
                    case 'choice':
361 43
                    case 'all':
362 43
                        $this->loadSequence($type, $childNode);
0 ignored issues
show
Bug introduced by
It seems like $type defined by $isSimple ? new \GoetasW...->getAttribute('name')) on line 346 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...
363 43
                        break;
364 43
                    case 'attribute':
365 43
                        if ($childNode->hasAttribute("ref")) {
366 43
                            $referencedAttribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
367 43
                            $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 366 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...
368 43
                        } else {
369 43
                            $attribute = $this->loadAttribute($schema, $childNode);
370
                        }
371
372 43
                        $type->addAttribute($attribute);
373 43
                        break;
374 43 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...
375 2
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
376 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 375 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...
377 2
                        break;
378 43
                }
379 43
            }
380
381 43
            if ($callback) {
382 43
                call_user_func($callback, $type);
383 43
            }
384 43
        };
385
    }
386
387 43
    private function loadSimpleType(Schema $schema, DOMElement $node, $callback = null)
388
    {
389 43
        $type = new SimpleType($schema, $node->getAttribute("name"));
390 43
        $type->setDoc($this->getDocumentation($node));
391 43
        if ($node->getAttribute("name")) {
392 43
            $schema->addType($type);
393 43
        }
394
395
        return function () use ($type, $node, $callback) {
396 43
            $this->fillTypeNode($type, $node);
397
398 43
            foreach ($node->childNodes as $childNode) {
399 43
                switch ($childNode->localName) {
400 43
                    case 'union':
401 43
                        $this->loadUnion($type, $childNode);
402 43
                        break;
403 43
                    case 'list':
404 43
                        $this->loadList($type, $childNode);
405 43
                        break;
406 43
                }
407 43
            }
408
409 43
            if ($callback) {
410 43
                call_user_func($callback, $type);
411 43
            }
412 43
        };
413
    }
414
415 43
    private function loadList(SimpleType $type, DOMElement $node)
416
    {
417 43 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...
418 43
            $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...
419 43
        } else {
420
            $addCallback = function ($list) use ($type) {
421 43
                $type->setList($list);
422 43
            };
423
424 43
            foreach ($node->childNodes as $childNode) {
425 43
                switch ($childNode->localName) {
426 43
                    case 'simpleType':
427 43
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
428 43
                        break;
429 43
                }
430 43
            }
431
        }
432 43
    }
433
434 43
    private function loadUnion(SimpleType $type, DOMElement $node)
435
    {
436 43
        if ($node->hasAttribute("memberTypes")) {
437 43
            $types = preg_split('/\s+/', $node->getAttribute("memberTypes"));
438 43
            foreach ($types as $typeName) {
439 43
                $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...
440 43
            }
441 43
        }
442
        $addCallback = function ($unType) use ($type) {
443 43
            $type->addUnion($unType);
444 43
        };
445
446 43
        foreach ($node->childNodes as $childNode) {
447 43
            switch ($childNode->localName) {
448 43
                case 'simpleType':
449 43
                    call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
450 43
                    break;
451 43
            }
452 43
        }
453 43
    }
454
455 43
    private function fillTypeNode(Type $type, DOMElement $node, $checkAbstract = true)
456
    {
457
458 43
        if ($checkAbstract) {
459 43
            $type->setAbstract($node->getAttribute("abstract") === "true" || $node->getAttribute("abstract") === "1");
460 43
        }
461
462 43
        foreach ($node->childNodes as $childNode) {
463 43
            switch ($childNode->localName) {
464 43
                case 'restriction':
465 43
                    $this->loadRestriction($type, $childNode);
466 43
                    break;
467 43
                case 'extension':
468 43
                    $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...
469 43
                    break;
470 43
                case 'simpleContent':
471 43
                case 'complexContent':
472 43
                    $this->fillTypeNode($type, $childNode, false);
473 43
                    break;
474 43
            }
475 43
        }
476 43
    }
477
478 43
    private function loadExtension(BaseComplexType $type, DOMElement $node)
479
    {
480 43
        $extension = new Extension();
481 43
        $type->setExtension($extension);
482
483 43
        if ($node->hasAttribute("base")) {
484 43
            $parent = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
485 43
            $extension->setBase($parent);
0 ignored issues
show
Bug introduced by
It seems like $parent defined by $this->findSomething('fi...->getAttribute('base')) on line 484 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...
486 43
        }
487
488 43
        foreach ($node->childNodes as $childNode) {
489 43
            switch ($childNode->localName) {
490 43
                case 'sequence':
491 43
                case 'choice':
492 43
                case 'all':
493 43
                    $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...
494 43
                    break;
495 43 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...
496 43
                    if ($childNode->hasAttribute("ref")) {
497 43
                        $attribute = $this->findSomething('findAttribute', $type->getSchema(), $node, $childNode->getAttribute("ref"));
498 43
                    } else {
499 43
                        $attribute = $this->loadAttribute($type->getSchema(), $childNode);
500
                    }
501 43
                    $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 497 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...
502 43
                    break;
503 43
                case 'attributeGroup':
504 43
                    $attribute = $this->findSomething('findAttributeGroup', $type->getSchema(), $node, $childNode->getAttribute("ref"));
505 43
                    $type->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 504 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...lexType::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
506 43
                    break;
507 43
            }
508 43
        }
509 43
    }
510
511 43
    private function loadRestriction(Type $type, DOMElement $node)
512
    {
513 43
        $restriction = new Restriction();
514 43
        $type->setRestriction($restriction);
515 43 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...
516 43
            $restrictedType = $this->findSomething('findType', $type->getSchema(), $node, $node->getAttribute("base"));
517 43
            $restriction->setBase($restrictedType);
0 ignored issues
show
Bug introduced by
It seems like $restrictedType defined by $this->findSomething('fi...->getAttribute('base')) on line 516 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...
518 43
        } else {
519
            $addCallback = function ($restType) use ($restriction) {
520 43
                $restriction->setBase($restType);
521 43
            };
522
523 43
            foreach ($node->childNodes as $childNode) {
524 43
                switch ($childNode->localName) {
525 43
                    case 'simpleType':
526 43
                        call_user_func($this->loadSimpleType($type->getSchema(), $childNode, $addCallback));
527 43
                        break;
528 43
                }
529 43
            }
530
        }
531 43
        foreach ($node->childNodes as $childNode) {
532 43
            if (in_array($childNode->localName,
533
                [
534 43
                    'enumeration',
535 43
                    'pattern',
536 43
                    'length',
537 43
                    'minLength',
538 43
                    'maxLength',
539 43
                    'minInclusive',
540 43
                    'maxInclusive',
541 43
                    'minExclusive',
542 43
                    'maxExclusive',
543 43
                    'fractionDigits',
544 43
                    'totalDigits',
545
                    'whiteSpace'
546 43
                ], true)) {
547 43
                $restriction->addCheck($childNode->localName,
548
                    [
549 43
                        'value' => $childNode->getAttribute("value"),
550 43
                        'doc' => $this->getDocumentation($childNode)
551 43
                    ]);
552 43
            }
553 43
        }
554 43
    }
555
556 43
    private static function splitParts(DOMElement $node, $typeName)
557
    {
558 43
        $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...
559 43
        $prefix = null;
560 43
        $name = $typeName;
561 43
        if (strpos($typeName, ':') !== false) {
562 43
            list ($prefix, $name) = explode(':', $typeName);
563 43
        }
564
565 43
        $namespace = $node->lookupNamespaceURI($prefix ?: null);
566
        return array(
567 43
            $name,
568 43
            $namespace,
569
            $prefix
570 43
        );
571
    }
572
573
    /**
574
     *
575
     * @param string $finder
576
     * @param Schema $schema
577
     * @param DOMElement $node
578
     * @param string $typeName
579
     * @throws TypeException
580
     * @return ElementItem|Group|AttributeItem|AttribiuteGroup|Type
581
     */
582 43
    private function findSomething($finder, Schema $schema, DOMElement $node, $typeName)
583
    {
584 43
        list ($name, $namespace) = self::splitParts($node, $typeName);
585
586 43
        $namespace = $namespace ?: $schema->getTargetNamespace();
587
588
        try {
589 43
            return $schema->$finder($name, $namespace);
590
        } catch (TypeNotFoundException $e) {
591
            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);
592
        }
593
    }
594
595 43 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...
596
    {
597 43
        $element = new ElementDef($schema, $node->getAttribute("name"));
598 43
        $schema->addElement($element);
599
600
        return function () use ($element, $node) {
601 43
            $this->fillItem($element, $node);
602 43
        };
603
    }
604
605 43
    private function fillItem(Item $element, DOMElement $node)
606
    {
607 43
        $localType = null;
608 43
        foreach ($node->childNodes as $childNode) {
609 43
            switch ($childNode->localName) {
610 43
                case 'complexType':
611 43
                case 'simpleType':
612 43
                    $localType = $childNode;
613 43
                    break 2;
614 43
            }
615 43
        }
616
617 43
        if ($localType) {
618
            $addCallback = function ($type) use ($element) {
619 43
                $element->setType($type);
620 43
            };
621 43
            switch ($localType->localName) {
622 43
                case 'complexType':
623 43
                    call_user_func($this->loadComplexType($element->getSchema(), $localType, $addCallback));
624 43
                    break;
625 43
                case 'simpleType':
626 43
                    call_user_func($this->loadSimpleType($element->getSchema(), $localType, $addCallback));
627 43
                    break;
628 43
            }
629 43
        } else {
630
631 43
            if ($node->getAttribute("type")) {
632 43
                $type = $this->findSomething('findType', $element->getSchema(), $node, $node->getAttribute("type"));
633 43
            } else {
634 43
                $type = $this->findSomething('findType', $element->getSchema(), $node, ($node->lookupPrefix(self::XSD_NS) . ":anyType"));
635
            }
636
637 43
            $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...
638
        }
639 43
    }
640
641 43
    private function loadImport(Schema $schema, DOMElement $node)
642
    {
643 43
        $base = urldecode($node->ownerDocument->documentURI);
644 43
        $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute("schemaLocation"));
645 43
        if ($node->hasAttribute("namespace")
646 43
            && isset(self::$globalSchemaInfo[$node->getAttribute("namespace")])
647 43
            && isset($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]])
648 43
        ) {
649
650 43
            $schema->addSchema($this->loadedFiles[self::$globalSchemaInfo[$node->getAttribute("namespace")]]);
651
652
            return function () {
653 43
            };
654 2
        } elseif (isset($this->loadedFiles[$file])) {
655 1
            $schema->addSchema($this->loadedFiles[$file]);
656
            return function () {
657 1
            };
658
        }
659
660 1
        if (!$node->getAttribute("namespace")) {
661 1
            $this->loadedFiles[$file] = $newSchema = $schema;
662 1
        } else {
663
            $this->loadedFiles[$file] = $newSchema = new Schema();
664
            $newSchema->addSchema($this->getGlobalSchema());
665
        }
666
667 1
        $xml = $this->getDOM(isset($this->knowLocationSchemas[$file]) ? $this->knowLocationSchemas[$file] : $file);
668
669 1
        $callbacks = $this->schemaNode($newSchema, $xml->documentElement, $schema);
670
671 1
        if ($node->getAttribute("namespace")) {
672
            $schema->addSchema($newSchema);
673
        }
674
675
676 1
        return function () use ($callbacks) {
677 1
            foreach ($callbacks as $callback) {
678 1
                call_user_func($callback);
679 1
            }
680 1
        };
681
    }
682
683
    private $globalSchema;
684
685
    /**
686
     *
687
     * @return \GoetasWebservices\XML\XSDReader\Schema\Schema
688
     */
689 43
    public function getGlobalSchema()
690
    {
691 43
        if (!$this->globalSchema) {
692 43
            $callbacks = array();
693 43
            $globalSchemas = array();
694 43
            foreach (self::$globalSchemaInfo as $namespace => $uri) {
695 43
                $this->loadedFiles[$uri] = $globalSchemas [$namespace] = $schema = new Schema();
696 43
                if ($namespace === self::XSD_NS) {
697 43
                    $this->globalSchema = $schema;
698 43
                }
699 43
                $xml = $this->getDOM($this->knowLocationSchemas[$uri]);
700 43
                $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement));
701 43
            }
702
703 43
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anySimpleType"));
704 43
            $globalSchemas[self::XSD_NS]->addType(new SimpleType($globalSchemas[self::XSD_NS], "anyType"));
705
706 43
            $globalSchemas[self::XML_NS]->addSchema($globalSchemas[self::XSD_NS], self::XSD_NS);
707 43
            $globalSchemas[self::XSD_NS]->addSchema($globalSchemas[self::XML_NS], self::XML_NS);
708
709 43
            foreach ($callbacks as $callback) {
710 43
                $callback();
711 43
            }
712 43
        }
713 43
        return $this->globalSchema;
714
    }
715
716
    /**
717
     * @return \GoetasWebservices\XML\XSDReader\Schema\Schema
718
     */
719 43
    public function readNode(\DOMNode $node, $file = 'schema.xsd')
720
    {
721 43
        $this->loadedFiles[$file] = $rootSchema = new Schema();
722
723 43
        $rootSchema->addSchema($this->getGlobalSchema());
724 43
        $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...
725
726 43
        foreach ($callbacks as $callback) {
727 37
            call_user_func($callback);
728 43
        }
729
730 43
        return $rootSchema;
731
    }
732
733
734
    /**
735
     * @return \GoetasWebservices\XML\XSDReader\Schema\Schema
736
     */
737 42
    public function readString($content, $file = 'schema.xsd')
738
    {
739 42
        $xml = new DOMDocument('1.0', 'UTF-8');
740 42
        if (!$xml->loadXML($content)) {
741
            throw new IOException("Can't load the schema");
742
        }
743 42
        $xml->documentURI = $file;
744
745 42
        return $this->readNode($xml->documentElement, $file);
746
    }
747
748
    /**
749
     * @return \GoetasWebservices\XML\XSDReader\Schema\Schema
750
     */
751 1
    public function readFile($file)
752
    {
753 1
        $xml = $this->getDOM($file);
754 1
        return $this->readNode($xml->documentElement, $file);
755
    }
756
757
    /**
758
     * @param string $file
759
     * @throws IOException
760
     * @return \DOMDocument
761
     */
762 43
    private function getDOM($file)
763
    {
764 43
        $xml = new DOMDocument('1.0', 'UTF-8');
765 43
        if (!$xml->load($file)) {
766
            throw new IOException("Can't load the file $file");
767
        }
768 43
        return $xml;
769
    }
770
}
771