Completed
Push — master ( da8fcc...d64df6 )
by Asmir
02:56
created

SchemaReader   F

Complexity

Total Complexity 158

Size/Duplication

Total Lines 725
Duplicated Lines 11.59 %

Coupling/Cohesion

Components 1
Dependencies 22

Test Coverage

Coverage 95.12%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 158
lcom 1
cbo 22
dl 84
loc 725
ccs 468
cts 492
cp 0.9512
rs 1.0434
c 3
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A addKnownSchemaLocation() 0 4 1
B loadAttributeGroup() 13 26 5
A loadAttribute() 0 17 4
A loadAttributeDef() 10 10 1
B getDocumentation() 0 15 5
C schemaNode() 0 43 14
B loadElement() 0 21 6
A loadGroupRef() 3 14 4
B loadElementRef() 3 20 6
A loadAttributeRef() 0 16 4
C loadSequence() 0 33 12
C loadGroup() 3 26 8
C loadComplexType() 4 51 13
B loadSimpleType() 0 27 6
A loadList() 15 18 4
B loadUnion() 0 20 5
C fillTypeNode() 0 22 8
D loadExtension() 8 32 9
B loadRestriction() 16 41 6
A splitParts() 0 16 3
A findSomething() 0 12 3
A loadElementDef() 9 9 1
C fillItem() 0 35 8
D loadImport() 0 41 9
B getGlobalSchema() 0 26 5
A readNode() 0 13 2
A readString() 0 10 2
A readFile() 0 5 1
A getDOM() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like SchemaReader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SchemaReader, and based on these observations, apply Extract Interface, too.

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 48
    public function __construct()
48
    {
49 48
        $this->addKnownSchemaLocation('http://www.w3.org/2001/xml.xsd', __DIR__ . '/Resources/xml.xsd');
50 48
        $this->addKnownSchemaLocation('http://www.w3.org/2001/XMLSchema.xsd', __DIR__ . '/Resources/XMLSchema.xsd');
51 48
    }
52
53 48
    public function addKnownSchemaLocation($remote, $local)
54
    {
55 48
        $this->knowLocationSchemas[$remote] = $local;
56 48
    }
57
58 39
    private function loadAttributeGroup(Schema $schema, DOMElement $node)
59
    {
60 39
        $attGroup = new AttributeGroup($schema, $node->getAttribute("name"));
61 39
        $attGroup->setDoc($this->getDocumentation($node));
62 39
        $schema->addAttributeGroup($attGroup);
63
64
        return function () use ($schema, $node, $attGroup) {
65 39
            foreach ($node->childNodes as $childNode) {
66 39
                switch ($childNode->localName) {
67 39 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...
68 39
                        if ($childNode->hasAttribute("ref")) {
69 39
                            $attribute = $this->findSomething('findAttribute', $schema, $node, $childNode->getAttribute("ref"));
70 39
                        } else {
71 39
                            $attribute = $this->loadAttribute($schema, $childNode);
72
                        }
73 39
                        $attGroup->addAttribute($attribute);
0 ignored issues
show
Bug introduced by
It seems like $attribute defined by $this->findSomething('fi...e->getAttribute('ref')) on line 69 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...
74 39
                        break;
75 39 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...
76
77 1
                        $attribute = $this->findSomething('findAttributeGroup', $schema, $node, $childNode->getAttribute("ref"));
78 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 77 can also be of type object<GoetasWebservices...ma\Element\ElementItem> or object<GoetasWebservices...eader\Schema\Type\Type>; however, GoetasWebservices\XML\XS...e\Group::addAttribute() does only seem to accept object<GoetasWebservices...ttribute\AttributeItem>, maybe add an additional type check?

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

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

    return array();
}

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

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

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