These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace GoetasWebservices\XML\XSDReader; |
||
6 | |||
7 | use Closure; |
||
8 | use DOMDocument; |
||
9 | use DOMElement; |
||
10 | use DOMNode; |
||
11 | use GoetasWebservices\XML\XSDReader\Documentation\DocumentationReader; |
||
12 | use GoetasWebservices\XML\XSDReader\Documentation\StandardDocumentationReader; |
||
13 | use GoetasWebservices\XML\XSDReader\Exception\IOException; |
||
14 | use GoetasWebservices\XML\XSDReader\Exception\TypeException; |
||
15 | use GoetasWebservices\XML\XSDReader\Schema\Attribute\Attribute; |
||
16 | use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeContainer; |
||
17 | use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef; |
||
18 | use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem; |
||
19 | use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup; |
||
20 | use GoetasWebservices\XML\XSDReader\Schema\Element\Element; |
||
21 | use GoetasWebservices\XML\XSDReader\Schema\Element\ElementContainer; |
||
22 | use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef; |
||
23 | use GoetasWebservices\XML\XSDReader\Schema\Element\ElementRef; |
||
24 | use GoetasWebservices\XML\XSDReader\Schema\Element\Group; |
||
25 | use GoetasWebservices\XML\XSDReader\Schema\Element\InterfaceSetMinMax; |
||
26 | use GoetasWebservices\XML\XSDReader\Schema\Element\GroupRef; |
||
27 | use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException; |
||
28 | use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Base; |
||
29 | use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Extension; |
||
30 | use GoetasWebservices\XML\XSDReader\Schema\Inheritance\Restriction; |
||
31 | use GoetasWebservices\XML\XSDReader\Schema\Item; |
||
32 | use GoetasWebservices\XML\XSDReader\Schema\Schema; |
||
33 | use GoetasWebservices\XML\XSDReader\Schema\SchemaItem; |
||
34 | use GoetasWebservices\XML\XSDReader\Schema\Type\BaseComplexType; |
||
35 | use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexType; |
||
36 | use GoetasWebservices\XML\XSDReader\Schema\Type\ComplexTypeSimpleContent; |
||
37 | use GoetasWebservices\XML\XSDReader\Schema\Type\SimpleType; |
||
38 | use GoetasWebservices\XML\XSDReader\Schema\Type\Type; |
||
39 | use GoetasWebservices\XML\XSDReader\Utils\UrlUtils; |
||
40 | |||
41 | class SchemaReader |
||
42 | { |
||
43 | public const XSD_NS = 'http://www.w3.org/2001/XMLSchema'; |
||
44 | |||
45 | public const XML_NS = 'http://www.w3.org/XML/1998/namespace'; |
||
46 | |||
47 | /** |
||
48 | * @var DocumentationReader |
||
49 | */ |
||
50 | private $documentationReader; |
||
51 | |||
52 | /** |
||
53 | * @var Schema[] |
||
54 | */ |
||
55 | private $loadedFiles = array(); |
||
56 | |||
57 | /** |
||
58 | * @var Schema[][] |
||
59 | */ |
||
60 | private $loadedSchemas = array(); |
||
61 | |||
62 | /** |
||
63 | * @var string[] |
||
64 | */ |
||
65 | protected $knownLocationSchemas = [ |
||
66 | 'http://www.w3.org/2001/xml.xsd' => ( |
||
67 | __DIR__.'/Resources/xml.xsd' |
||
68 | ), |
||
69 | 'http://www.w3.org/2001/XMLSchema.xsd' => ( |
||
70 | __DIR__.'/Resources/XMLSchema.xsd' |
||
71 | ), |
||
72 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' => ( |
||
73 | __DIR__.'/Resources/oasis-200401-wss-wssecurity-secext-1.0.xsd' |
||
74 | ), |
||
75 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' => ( |
||
76 | __DIR__.'/Resources/oasis-200401-wss-wssecurity-utility-1.0.xsd' |
||
77 | ), |
||
78 | 'https://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => ( |
||
79 | __DIR__.'/Resources/xmldsig-core-schema.xsd' |
||
80 | ), |
||
81 | 'http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd' => ( |
||
82 | __DIR__.'/Resources/xmldsig-core-schema.xsd' |
||
83 | ), |
||
84 | ]; |
||
85 | |||
86 | /** |
||
87 | * @var string[] |
||
88 | */ |
||
89 | protected static $globalSchemaInfo = array( |
||
90 | self::XML_NS => 'http://www.w3.org/2001/xml.xsd', |
||
91 | self::XSD_NS => 'http://www.w3.org/2001/XMLSchema.xsd', |
||
92 | ); |
||
93 | |||
94 | 58 | public function __construct(DocumentationReader $documentationReader = null) |
|
95 | { |
||
96 | 58 | if (null === $documentationReader) { |
|
97 | 58 | $documentationReader = new StandardDocumentationReader(); |
|
98 | } |
||
99 | 58 | $this->documentationReader = $documentationReader; |
|
100 | 58 | } |
|
101 | |||
102 | public function addKnownSchemaLocation(string $remote, string $local): void |
||
103 | { |
||
104 | $this->knownLocationSchemas[$remote] = $local; |
||
105 | } |
||
106 | |||
107 | 49 | private function loadAttributeGroup( |
|
108 | Schema $schema, |
||
109 | DOMElement $node |
||
110 | ): Closure { |
||
111 | 49 | $attGroup = new AttributeGroup($schema, $node->getAttribute('name')); |
|
112 | 49 | $attGroup->setDoc($this->getDocumentation($node)); |
|
113 | 49 | $schema->addAttributeGroup($attGroup); |
|
114 | |||
115 | 49 | return function () use ($schema, $node, $attGroup) { |
|
116 | 49 | SchemaReader::againstDOMNodeList( |
|
117 | 49 | $node, |
|
118 | 49 | function ( |
|
119 | DOMElement $node, |
||
120 | DOMElement $childNode |
||
121 | ) use ( |
||
122 | 49 | $schema, |
|
123 | 49 | $attGroup |
|
124 | ) { |
||
125 | 49 | switch ($childNode->localName) { |
|
126 | 49 | case 'attribute': |
|
127 | 49 | $attribute = $this->getAttributeFromAttributeOrRef( |
|
128 | 49 | $childNode, |
|
129 | 49 | $schema, |
|
130 | 49 | $node |
|
131 | ); |
||
132 | 49 | $attGroup->addAttribute($attribute); |
|
133 | 49 | break; |
|
134 | 49 | case 'attributeGroup': |
|
135 | 1 | $this->findSomethingLikeAttributeGroup( |
|
136 | 1 | $schema, |
|
137 | 1 | $node, |
|
138 | 1 | $childNode, |
|
139 | 1 | $attGroup |
|
140 | ); |
||
141 | 1 | break; |
|
142 | } |
||
143 | 49 | } |
|
144 | ); |
||
145 | 49 | }; |
|
146 | } |
||
147 | |||
148 | 49 | private function getAttributeFromAttributeOrRef( |
|
149 | DOMElement $childNode, |
||
150 | Schema $schema, |
||
151 | DOMElement $node |
||
152 | ): AttributeItem { |
||
153 | 49 | if ($childNode->hasAttribute('ref')) { |
|
154 | 49 | $attribute = $this->findAttributeItem($schema, $node, $childNode->getAttribute('ref')); |
|
155 | } else { |
||
156 | /** |
||
157 | * @var Attribute |
||
158 | */ |
||
159 | 49 | $attribute = $this->loadAttribute($schema, $childNode); |
|
160 | } |
||
161 | |||
162 | 49 | return $attribute; |
|
163 | } |
||
164 | |||
165 | 49 | private function loadAttribute( |
|
166 | Schema $schema, |
||
167 | DOMElement $node |
||
168 | ): Attribute { |
||
169 | 49 | $attribute = new Attribute($schema, $node->getAttribute('name')); |
|
170 | 49 | $attribute->setDoc($this->getDocumentation($node)); |
|
171 | 49 | $this->fillItem($attribute, $node); |
|
172 | |||
173 | 49 | if ($node->hasAttribute('nillable')) { |
|
174 | 1 | $attribute->setNil($node->getAttribute('nillable') == 'true'); |
|
175 | } |
||
176 | 49 | if ($node->hasAttribute('form')) { |
|
177 | 1 | $attribute->setQualified($node->getAttribute('form') == 'qualified'); |
|
178 | } |
||
179 | 49 | if ($node->hasAttribute('use')) { |
|
180 | 49 | $attribute->setUse($node->getAttribute('use')); |
|
181 | } |
||
182 | |||
183 | 49 | return $attribute; |
|
184 | } |
||
185 | |||
186 | 49 | private function loadAttributeOrElementDef( |
|
187 | Schema $schema, |
||
188 | DOMElement $node, |
||
189 | bool $attributeDef |
||
190 | ): Closure { |
||
191 | 49 | $name = $node->getAttribute('name'); |
|
192 | 49 | if ($attributeDef) { |
|
193 | 49 | $attribute = new AttributeDef($schema, $name); |
|
194 | 49 | $schema->addAttribute($attribute); |
|
195 | } else { |
||
196 | 49 | $attribute = new ElementDef($schema, $name); |
|
197 | 49 | $schema->addElement($attribute); |
|
198 | } |
||
199 | |||
200 | 49 | return function () use ($attribute, $node) { |
|
201 | 49 | $this->fillItem($attribute, $node); |
|
202 | 49 | }; |
|
203 | } |
||
204 | |||
205 | 49 | private function loadAttributeDef(Schema $schema, DOMElement $node): Closure |
|
206 | { |
||
207 | 49 | return $this->loadAttributeOrElementDef($schema, $node, true); |
|
208 | } |
||
209 | |||
210 | 49 | private function getDocumentation(DOMElement $node): string |
|
211 | { |
||
212 | 49 | return $this->documentationReader->get($node); |
|
213 | } |
||
214 | |||
215 | /** |
||
216 | * @return Closure[] |
||
217 | */ |
||
218 | 49 | private function schemaNode(Schema $schema, DOMElement $node, Schema $parent = null): array |
|
219 | { |
||
220 | 49 | $this->setSchemaThingsFromNode($schema, $node, $parent); |
|
221 | 49 | $functions = array(); |
|
222 | |||
223 | 49 | static::againstDOMNodeList( |
|
224 | 49 | $node, |
|
225 | 49 | function ( |
|
226 | DOMElement $node, |
||
227 | DOMElement $childNode |
||
228 | ) use ( |
||
229 | 49 | $schema, |
|
230 | 49 | &$functions |
|
231 | ) { |
||
232 | 49 | $callback = null; |
|
233 | |||
234 | 49 | switch ($childNode->localName) { |
|
235 | 49 | case 'attributeGroup': |
|
236 | 49 | $callback = $this->loadAttributeGroup($schema, $childNode); |
|
237 | 49 | break; |
|
238 | 49 | case 'include': |
|
239 | 49 | case 'import': |
|
240 | 49 | $callback = $this->loadImport($schema, $childNode); |
|
241 | 49 | break; |
|
242 | 49 | case 'element': |
|
243 | 49 | $callback = $this->loadElementDef($schema, $childNode); |
|
244 | 49 | break; |
|
245 | 49 | case 'attribute': |
|
246 | 49 | $callback = $this->loadAttributeDef($schema, $childNode); |
|
247 | 49 | break; |
|
248 | 49 | case 'group': |
|
249 | 49 | $callback = $this->loadGroup($schema, $childNode); |
|
250 | 49 | break; |
|
251 | 49 | case 'complexType': |
|
252 | 49 | $callback = $this->loadComplexType($schema, $childNode); |
|
253 | 49 | break; |
|
254 | 49 | case 'simpleType': |
|
255 | 49 | $callback = $this->loadSimpleType($schema, $childNode); |
|
256 | 49 | break; |
|
257 | } |
||
258 | |||
259 | 49 | if ($callback instanceof Closure) { |
|
260 | 49 | $functions[] = $callback; |
|
261 | } |
||
262 | 49 | } |
|
263 | ); |
||
264 | |||
265 | 49 | return $functions; |
|
266 | } |
||
267 | |||
268 | 49 | private function loadGroupRef(Group $referenced, DOMElement $node): GroupRef |
|
269 | { |
||
270 | 49 | $ref = new GroupRef($referenced); |
|
271 | 49 | $ref->setDoc($this->getDocumentation($node)); |
|
272 | |||
273 | 49 | self::maybeSetMax($ref, $node); |
|
274 | 49 | self::maybeSetMin($ref, $node); |
|
275 | |||
276 | 49 | return $ref; |
|
277 | } |
||
278 | |||
279 | 49 | private static function maybeSetMax(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax |
|
280 | { |
||
281 | if ( |
||
282 | 49 | $node->hasAttribute('maxOccurs') |
|
283 | ) { |
||
284 | 49 | $ref->setMax($node->getAttribute('maxOccurs') == 'unbounded' ? -1 : (int) $node->getAttribute('maxOccurs')); |
|
285 | } |
||
286 | |||
287 | 49 | return $ref; |
|
288 | } |
||
289 | |||
290 | 49 | private static function maybeSetMin(InterfaceSetMinMax $ref, DOMElement $node): InterfaceSetMinMax |
|
291 | { |
||
292 | 49 | if ($node->hasAttribute('minOccurs')) { |
|
293 | 49 | $ref->setMin((int) $node->getAttribute('minOccurs')); |
|
294 | } |
||
295 | |||
296 | 49 | return $ref; |
|
297 | } |
||
298 | |||
299 | 49 | private function loadSequence(ElementContainer $elementContainer, DOMElement $node, int $max = null): void |
|
300 | { |
||
301 | $max = |
||
302 | ( |
||
303 | 49 | (is_int($max) && (bool) $max) || |
|
304 | 49 | $node->getAttribute('maxOccurs') == 'unbounded' || |
|
305 | 49 | $node->getAttribute('maxOccurs') > 1 |
|
306 | ) |
||
307 | 49 | ? 2 |
|
308 | 49 | : null; |
|
309 | |||
310 | 49 | static::againstDOMNodeList( |
|
311 | 49 | $node, |
|
312 | 49 | function ( |
|
313 | DOMElement $node, |
||
314 | DOMElement $childNode |
||
315 | ) use ( |
||
316 | 49 | $elementContainer, |
|
317 | 49 | $max |
|
318 | ) { |
||
319 | 49 | $this->loadSequenceChildNode( |
|
320 | 49 | $elementContainer, |
|
321 | 49 | $node, |
|
322 | 49 | $childNode, |
|
323 | 49 | $max |
|
324 | ); |
||
325 | 49 | } |
|
326 | ); |
||
327 | 49 | } |
|
328 | |||
329 | /** |
||
330 | * @param int|null $max |
||
331 | */ |
||
332 | 49 | private function loadSequenceChildNode( |
|
333 | ElementContainer $elementContainer, |
||
334 | DOMElement $node, |
||
335 | DOMElement $childNode, |
||
336 | $max |
||
337 | ): void { |
||
338 | 49 | switch ($childNode->localName) { |
|
339 | 49 | case 'sequence': |
|
340 | 49 | case 'choice': |
|
341 | 49 | case 'all': |
|
342 | 49 | $this->loadSequence( |
|
343 | 49 | $elementContainer, |
|
344 | 49 | $childNode, |
|
345 | 49 | $max |
|
346 | ); |
||
347 | 49 | break; |
|
348 | 49 | case 'element': |
|
349 | 49 | $this->loadSequenceChildNodeLoadElement( |
|
350 | 49 | $elementContainer, |
|
351 | 49 | $node, |
|
352 | 49 | $childNode, |
|
353 | 49 | $max |
|
354 | ); |
||
355 | 49 | break; |
|
356 | 49 | case 'group': |
|
357 | 49 | $this->addGroupAsElement( |
|
358 | 49 | $elementContainer->getSchema(), |
|
359 | 49 | $node, |
|
360 | 49 | $childNode, |
|
361 | 49 | $elementContainer |
|
362 | ); |
||
363 | 49 | break; |
|
364 | } |
||
365 | 49 | } |
|
366 | |||
367 | /** |
||
368 | * @param int|null $max |
||
369 | */ |
||
370 | 49 | private function loadSequenceChildNodeLoadElement( |
|
371 | ElementContainer $elementContainer, |
||
372 | DOMElement $node, |
||
373 | DOMElement $childNode, |
||
374 | $max |
||
375 | ): void { |
||
376 | 49 | if ($childNode->hasAttribute('ref')) { |
|
377 | 49 | $element = new ElementRef( |
|
378 | 49 | $this->findElement($elementContainer->getSchema(), $node, $childNode->getAttribute('ref')) |
|
379 | ); |
||
380 | 49 | $element->setDoc($this->getDocumentation($childNode)); |
|
381 | |||
382 | 49 | self::maybeSetMax($element, $childNode); |
|
383 | 49 | self::maybeSetMin($element, $childNode); |
|
384 | 49 | if ($childNode->hasAttribute('nillable')) { |
|
385 | $element->setNil($childNode->getAttribute('nillable') == 'true'); |
||
386 | } |
||
387 | 49 | if ($childNode->hasAttribute('form')) { |
|
388 | 49 | $element->setQualified($childNode->getAttribute('form') == 'qualified'); |
|
389 | } |
||
390 | } else { |
||
391 | 49 | $element = $this->loadElement( |
|
392 | 49 | $elementContainer->getSchema(), |
|
393 | 49 | $childNode |
|
394 | ); |
||
395 | } |
||
396 | 49 | if ($max > 1) { |
|
397 | /* |
||
398 | * although one might think the typecast is not needed with $max being `? int $max` after passing > 1, |
||
399 | * phpstan@a4f89fa still thinks it's possibly null. |
||
400 | * see https://github.com/phpstan/phpstan/issues/577 for related issue |
||
401 | */ |
||
402 | 49 | $element->setMax((int) $max); |
|
403 | } |
||
404 | 49 | $elementContainer->addElement($element); |
|
405 | 49 | } |
|
406 | |||
407 | 49 | private function addGroupAsElement( |
|
408 | Schema $schema, |
||
409 | DOMElement $node, |
||
410 | DOMElement $childNode, |
||
411 | ElementContainer $elementContainer |
||
412 | ): void { |
||
413 | 49 | $referencedGroup = $this->findGroup( |
|
414 | 49 | $schema, |
|
415 | 49 | $node, |
|
416 | 49 | $childNode->getAttribute('ref') |
|
417 | ); |
||
418 | |||
419 | 49 | $group = $this->loadGroupRef($referencedGroup, $childNode); |
|
420 | 49 | $elementContainer->addElement($group); |
|
421 | 49 | } |
|
422 | |||
423 | 49 | private function loadGroup(Schema $schema, DOMElement $node): Closure |
|
424 | { |
||
425 | 49 | $group = new Group($schema, $node->getAttribute('name')); |
|
426 | 49 | $group->setDoc($this->getDocumentation($node)); |
|
427 | |||
428 | 49 | if ($node->hasAttribute('maxOccurs')) { |
|
429 | /** |
||
430 | * @var GroupRef |
||
431 | */ |
||
432 | $group = self::maybeSetMax(new GroupRef($group), $node); |
||
433 | } |
||
434 | 49 | if ($node->hasAttribute('minOccurs')) { |
|
435 | /** |
||
436 | * @var GroupRef |
||
437 | */ |
||
438 | $group = self::maybeSetMin( |
||
439 | $group instanceof GroupRef ? $group : new GroupRef($group), |
||
440 | $node |
||
441 | ); |
||
442 | } |
||
443 | |||
444 | 49 | $schema->addGroup($group); |
|
445 | |||
446 | 49 | return function () use ($group, $node) { |
|
447 | 49 | static::againstDOMNodeList( |
|
448 | 49 | $node, |
|
449 | 49 | function (DOMelement $node, DOMElement $childNode) use ($group) { |
|
450 | 49 | switch ($childNode->localName) { |
|
451 | 49 | case 'sequence': |
|
452 | 49 | case 'choice': |
|
453 | 49 | case 'all': |
|
454 | 49 | $this->loadSequence($group, $childNode); |
|
455 | 49 | break; |
|
456 | } |
||
457 | 49 | } |
|
458 | ); |
||
459 | 49 | }; |
|
460 | } |
||
461 | |||
462 | 49 | private function loadComplexType(Schema $schema, DOMElement $node, Closure $callback = null): Closure |
|
463 | { |
||
464 | /** |
||
465 | * @var bool |
||
466 | */ |
||
467 | 49 | $isSimple = false; |
|
468 | |||
469 | 49 | static::againstDOMNodeList( |
|
470 | 49 | $node, |
|
471 | 49 | function ( |
|
472 | DOMElement $node, |
||
473 | DOMElement $childNode |
||
474 | ) use ( |
||
475 | 49 | &$isSimple |
|
476 | ) { |
||
477 | 49 | if ($isSimple) { |
|
478 | 1 | return; |
|
479 | } |
||
480 | 49 | if ($childNode->localName === 'simpleContent') { |
|
481 | 2 | $isSimple = true; |
|
482 | } |
||
483 | 49 | } |
|
484 | ); |
||
485 | |||
486 | 49 | $type = $isSimple ? new ComplexTypeSimpleContent($schema, $node->getAttribute('name')) : new ComplexType($schema, $node->getAttribute('name')); |
|
487 | |||
488 | 49 | $type->setDoc($this->getDocumentation($node)); |
|
489 | 49 | if ($node->getAttribute('name')) { |
|
490 | 49 | $schema->addType($type); |
|
491 | } |
||
492 | |||
493 | 49 | return function () use ($type, $node, $schema, $callback) { |
|
494 | 49 | $this->fillTypeNode($type, $node, true); |
|
495 | |||
496 | 49 | static::againstDOMNodeList( |
|
497 | 49 | $node, |
|
498 | 49 | function ( |
|
499 | DOMElement $node, |
||
500 | DOMElement $childNode |
||
501 | ) use ( |
||
502 | 49 | $schema, |
|
503 | 49 | $type |
|
504 | ) { |
||
505 | 49 | $this->loadComplexTypeFromChildNode( |
|
506 | 49 | $type, |
|
507 | 49 | $node, |
|
508 | 49 | $childNode, |
|
509 | 49 | $schema |
|
510 | ); |
||
511 | 49 | } |
|
512 | ); |
||
513 | |||
514 | 49 | if ($callback instanceof Closure) { |
|
515 | 49 | call_user_func($callback, $type); |
|
516 | } |
||
517 | 49 | }; |
|
518 | } |
||
519 | |||
520 | 49 | private function loadComplexTypeFromChildNode( |
|
521 | BaseComplexType $type, |
||
522 | DOMElement $node, |
||
523 | DOMElement $childNode, |
||
524 | Schema $schema |
||
525 | ): void { |
||
526 | 49 | switch ($childNode->localName) { |
|
527 | 49 | case 'sequence': |
|
528 | 49 | case 'choice': |
|
529 | 49 | case 'all': |
|
530 | 49 | if ($type instanceof ElementContainer) { |
|
531 | 49 | $this->loadSequence( |
|
532 | 49 | $type, |
|
533 | 49 | $childNode |
|
534 | ); |
||
535 | } |
||
536 | 49 | break; |
|
537 | 49 | case 'attribute': |
|
538 | 49 | $this->addAttributeFromAttributeOrRef( |
|
539 | 49 | $type, |
|
540 | 49 | $childNode, |
|
541 | 49 | $schema, |
|
542 | 49 | $node |
|
543 | ); |
||
544 | 49 | break; |
|
545 | 49 | case 'attributeGroup': |
|
546 | 2 | $this->findSomethingLikeAttributeGroup( |
|
547 | 2 | $schema, |
|
548 | 2 | $node, |
|
549 | 2 | $childNode, |
|
550 | 2 | $type |
|
551 | ); |
||
552 | 2 | break; |
|
553 | 49 | case 'group': |
|
554 | if ( |
||
555 | 1 | $type instanceof ComplexType |
|
556 | ) { |
||
557 | 1 | $this->addGroupAsElement( |
|
558 | 1 | $schema, |
|
559 | 1 | $node, |
|
560 | 1 | $childNode, |
|
561 | 1 | $type |
|
562 | ); |
||
563 | } |
||
564 | 1 | break; |
|
565 | } |
||
566 | 49 | } |
|
567 | |||
568 | 49 | private function loadSimpleType(Schema $schema, DOMElement $node, Closure $callback = null): Closure |
|
569 | { |
||
570 | 49 | $type = new SimpleType($schema, $node->getAttribute('name')); |
|
571 | 49 | $type->setDoc($this->getDocumentation($node)); |
|
572 | 49 | if ($node->getAttribute('name')) { |
|
573 | 49 | $schema->addType($type); |
|
574 | } |
||
575 | |||
576 | 49 | return function () use ($type, $node, $callback) { |
|
577 | 49 | $this->fillTypeNode($type, $node, true); |
|
578 | |||
579 | 49 | static::againstDOMNodeList( |
|
580 | 49 | $node, |
|
581 | 49 | function (DOMElement $node, DOMElement $childNode) use ($type) { |
|
582 | 49 | switch ($childNode->localName) { |
|
583 | 49 | case 'union': |
|
584 | 49 | $this->loadUnion($type, $childNode); |
|
585 | 49 | break; |
|
586 | 49 | case 'list': |
|
587 | 49 | $this->loadList($type, $childNode); |
|
588 | 49 | break; |
|
589 | } |
||
590 | 49 | } |
|
591 | ); |
||
592 | |||
593 | 49 | if ($callback instanceof Closure) { |
|
594 | 49 | call_user_func($callback, $type); |
|
595 | } |
||
596 | 49 | }; |
|
597 | } |
||
598 | |||
599 | 49 | private function loadList(SimpleType $type, DOMElement $node): void |
|
600 | { |
||
601 | 49 | if ($node->hasAttribute('itemType')) { |
|
602 | /** |
||
603 | * @var SimpleType |
||
604 | */ |
||
605 | 49 | $listType = $this->findSomeType($type, $node, 'itemType'); |
|
606 | 49 | $type->setList($listType); |
|
607 | } else { |
||
608 | 49 | self::againstDOMNodeList( |
|
609 | 49 | $node, |
|
610 | 49 | function ( |
|
611 | DOMElement $node, |
||
612 | DOMElement $childNode |
||
613 | ) use ( |
||
614 | 49 | $type |
|
615 | ) { |
||
616 | 49 | $this->loadTypeWithCallback( |
|
617 | 49 | $type->getSchema(), |
|
618 | 49 | $childNode, |
|
619 | 49 | function (SimpleType $list) use ($type) { |
|
620 | 49 | $type->setList($list); |
|
621 | 49 | } |
|
622 | ); |
||
623 | 49 | } |
|
624 | ); |
||
625 | } |
||
626 | 49 | } |
|
627 | |||
628 | 49 | private function findSomeType( |
|
629 | SchemaItem $fromThis, |
||
630 | DOMElement $node, |
||
631 | string $attributeName |
||
632 | ): SchemaItem { |
||
633 | 49 | return $this->findSomeTypeFromAttribute( |
|
634 | 49 | $fromThis, |
|
635 | 49 | $node, |
|
636 | 49 | $node->getAttribute($attributeName) |
|
637 | ); |
||
638 | } |
||
639 | |||
640 | 49 | private function findSomeTypeFromAttribute( |
|
641 | SchemaItem $fromThis, |
||
642 | DOMElement $node, |
||
643 | string $attributeName |
||
644 | ): SchemaItem { |
||
645 | 49 | $out = $this->findType( |
|
646 | 49 | $fromThis->getSchema(), |
|
647 | 49 | $node, |
|
648 | 49 | $attributeName |
|
649 | ); |
||
650 | |||
651 | 49 | return $out; |
|
652 | } |
||
653 | |||
654 | 49 | private function loadUnion(SimpleType $type, DOMElement $node): void |
|
655 | { |
||
656 | 49 | if ($node->hasAttribute('memberTypes')) { |
|
657 | 49 | $types = preg_split('/\s+/', $node->getAttribute('memberTypes')); |
|
658 | 49 | foreach ($types as $typeName) { |
|
659 | /** |
||
660 | * @var SimpleType |
||
661 | */ |
||
662 | 49 | $unionType = $this->findSomeTypeFromAttribute( |
|
663 | 49 | $type, |
|
664 | 49 | $node, |
|
665 | 49 | $typeName |
|
666 | ); |
||
667 | 49 | $type->addUnion($unionType); |
|
668 | } |
||
669 | } |
||
670 | 49 | self::againstDOMNodeList( |
|
671 | 49 | $node, |
|
672 | 49 | function ( |
|
673 | DOMElement $node, |
||
674 | DOMElement $childNode |
||
675 | ) use ( |
||
676 | 49 | $type |
|
677 | ) { |
||
678 | 49 | $this->loadTypeWithCallback( |
|
679 | 49 | $type->getSchema(), |
|
680 | 49 | $childNode, |
|
681 | 49 | function (SimpleType $unType) use ($type) { |
|
682 | 49 | $type->addUnion($unType); |
|
683 | 49 | } |
|
684 | ); |
||
685 | 49 | } |
|
686 | ); |
||
687 | 49 | } |
|
688 | |||
689 | 49 | private function fillTypeNode(Type $type, DOMElement $node, bool $checkAbstract = false): void |
|
690 | { |
||
691 | 49 | if ($checkAbstract) { |
|
692 | 49 | $type->setAbstract($node->getAttribute('abstract') === 'true' || $node->getAttribute('abstract') === '1'); |
|
693 | } |
||
694 | |||
695 | 49 | static::againstDOMNodeList( |
|
696 | 49 | $node, |
|
697 | 49 | function (DOMElement $node, DOMElement $childNode) use ($type) { |
|
698 | 49 | switch ($childNode->localName) { |
|
699 | 49 | case 'restriction': |
|
700 | 49 | $this->loadRestriction($type, $childNode); |
|
701 | 49 | break; |
|
702 | 49 | case 'extension': |
|
703 | 49 | if ($type instanceof BaseComplexType) { |
|
704 | 49 | $this->loadExtension($type, $childNode); |
|
705 | } |
||
706 | 49 | break; |
|
707 | 49 | case 'simpleContent': |
|
708 | 49 | case 'complexContent': |
|
709 | 49 | $this->fillTypeNode($type, $childNode); |
|
710 | 49 | break; |
|
711 | } |
||
712 | 49 | } |
|
713 | ); |
||
714 | 49 | } |
|
715 | |||
716 | 49 | private function loadExtension(BaseComplexType $type, DOMElement $node): void |
|
717 | { |
||
718 | 49 | $extension = new Extension(); |
|
719 | 49 | $type->setExtension($extension); |
|
720 | |||
721 | 49 | if ($node->hasAttribute('base')) { |
|
722 | 49 | $this->findAndSetSomeBase( |
|
723 | 49 | $type, |
|
724 | 49 | $extension, |
|
725 | 49 | $node |
|
726 | ); |
||
727 | } |
||
728 | 49 | $this->loadExtensionChildNodes($type, $node); |
|
729 | 49 | } |
|
730 | |||
731 | 49 | private function findAndSetSomeBase( |
|
732 | Type $type, |
||
733 | Base $setBaseOnThis, |
||
734 | DOMElement $node |
||
735 | ): void { |
||
736 | /** |
||
737 | * @var Type |
||
738 | */ |
||
739 | 49 | $parent = $this->findSomeType($type, $node, 'base'); |
|
740 | 49 | $setBaseOnThis->setBase($parent); |
|
741 | 49 | } |
|
742 | |||
743 | 49 | private function loadExtensionChildNodes( |
|
744 | BaseComplexType $type, |
||
745 | DOMElement $node |
||
746 | ) { |
||
747 | 49 | static::againstDOMNodeList( |
|
748 | 49 | $node, |
|
749 | 49 | function ( |
|
750 | DOMElement $node, |
||
751 | DOMElement $childNode |
||
752 | ) use ( |
||
753 | 49 | $type |
|
754 | ) { |
||
755 | 49 | switch ($childNode->localName) { |
|
756 | 49 | case 'sequence': |
|
757 | 49 | case 'choice': |
|
758 | 49 | case 'all': |
|
759 | 49 | if ($type instanceof ElementContainer) { |
|
760 | 49 | $this->loadSequence( |
|
761 | 49 | $type, |
|
762 | 49 | $childNode |
|
763 | ); |
||
764 | } |
||
765 | 49 | break; |
|
766 | 49 | case 'attribute': |
|
767 | 49 | $this->addAttributeFromAttributeOrRef( |
|
768 | 49 | $type, |
|
769 | 49 | $childNode, |
|
770 | 49 | $type->getSchema(), |
|
771 | 49 | $node |
|
772 | ); |
||
773 | 49 | break; |
|
774 | 49 | case 'attributeGroup': |
|
775 | 49 | $this->findSomethingLikeAttributeGroup( |
|
776 | 49 | $type->getSchema(), |
|
777 | 49 | $node, |
|
778 | 49 | $childNode, |
|
779 | 49 | $type |
|
780 | ); |
||
781 | 49 | break; |
|
782 | } |
||
783 | 49 | } |
|
784 | ); |
||
785 | 49 | } |
|
786 | |||
787 | 49 | private function loadRestriction(Type $type, DOMElement $node): void |
|
788 | { |
||
789 | 49 | $restriction = new Restriction(); |
|
790 | 49 | $type->setRestriction($restriction); |
|
791 | 49 | if ($node->hasAttribute('base')) { |
|
792 | 49 | $this->findAndSetSomeBase($type, $restriction, $node); |
|
793 | } else { |
||
794 | 49 | self::againstDOMNodeList( |
|
795 | 49 | $node, |
|
796 | 49 | function ( |
|
797 | DOMElement $node, |
||
798 | DOMElement $childNode |
||
799 | ) use ( |
||
800 | 49 | $type, |
|
801 | 49 | $restriction |
|
802 | ) { |
||
803 | 49 | $this->loadTypeWithCallback( |
|
804 | 49 | $type->getSchema(), |
|
805 | 49 | $childNode, |
|
806 | 49 | function (Type $restType) use ($restriction) { |
|
807 | 49 | $restriction->setBase($restType); |
|
808 | 49 | } |
|
809 | ); |
||
810 | 49 | } |
|
811 | ); |
||
812 | } |
||
813 | 49 | self::againstDOMNodeList( |
|
814 | 49 | $node, |
|
815 | 49 | function ( |
|
816 | DOMElement $node, |
||
817 | DOMElement $childNode |
||
818 | ) use ( |
||
819 | 49 | $restriction |
|
820 | ) { |
||
821 | if ( |
||
822 | 49 | in_array( |
|
823 | 49 | $childNode->localName, |
|
824 | [ |
||
825 | 49 | 'enumeration', |
|
826 | 'pattern', |
||
827 | 'length', |
||
828 | 'minLength', |
||
829 | 'maxLength', |
||
830 | 'minInclusive', |
||
831 | 'maxInclusive', |
||
832 | 'minExclusive', |
||
833 | 'maxExclusive', |
||
834 | 'fractionDigits', |
||
835 | 'totalDigits', |
||
836 | 'whiteSpace', |
||
837 | ], |
||
838 | 49 | true |
|
839 | ) |
||
840 | ) { |
||
841 | 49 | $restriction->addCheck( |
|
842 | 49 | $childNode->localName, |
|
843 | [ |
||
844 | 49 | 'value' => $childNode->getAttribute('value'), |
|
845 | 49 | 'doc' => $this->getDocumentation($childNode), |
|
846 | ] |
||
847 | ); |
||
848 | } |
||
849 | 49 | } |
|
850 | ); |
||
851 | 49 | } |
|
852 | |||
853 | /** |
||
854 | * @return mixed[] |
||
855 | */ |
||
856 | 49 | private static function splitParts(DOMElement $node, string $typeName): array |
|
857 | { |
||
858 | 49 | $prefix = null; |
|
859 | 49 | $name = $typeName; |
|
860 | 49 | if (strpos($typeName, ':') !== false) { |
|
861 | 49 | list($prefix, $name) = explode(':', $typeName); |
|
862 | } |
||
863 | |||
864 | 49 | $namespace = $node->lookupNamespaceUri($prefix ?: ''); |
|
865 | |||
866 | return array( |
||
867 | 49 | $name, |
|
868 | 49 | $namespace, |
|
869 | 49 | $prefix, |
|
870 | ); |
||
871 | } |
||
872 | |||
873 | 49 | private function findAttributeItem(Schema $schema, DOMElement $node, string $typeName): AttributeItem |
|
874 | { |
||
875 | 49 | list($name, $namespace) = static::splitParts($node, $typeName); |
|
876 | |||
877 | 49 | $namespace = $namespace ?: $schema->getTargetNamespace(); |
|
878 | |||
879 | try { |
||
880 | 49 | return $schema->findAttribute($name, $namespace); |
|
881 | } catch (TypeNotFoundException $e) { |
||
882 | throw new TypeException( |
||
883 | sprintf( |
||
884 | "Can't find %s named {%s}#%s, at line %d in %s ", |
||
885 | 'attribute', |
||
886 | $namespace, |
||
887 | $name, |
||
888 | $node->getLineNo(), |
||
889 | $node->ownerDocument->documentURI |
||
890 | ), |
||
891 | 0, |
||
892 | $e |
||
893 | ); |
||
894 | } |
||
895 | } |
||
896 | |||
897 | 49 | private function findAttributeGroup(Schema $schema, DOMElement $node, string $typeName): AttributeGroup |
|
898 | { |
||
899 | 49 | list($name, $namespace) = static::splitParts($node, $typeName); |
|
900 | |||
901 | 49 | $namespace = $namespace ?: $schema->getTargetNamespace(); |
|
902 | |||
903 | try { |
||
904 | 49 | return $schema->findAttributeGroup($name, $namespace); |
|
905 | } catch (TypeNotFoundException $e) { |
||
906 | throw new TypeException( |
||
907 | sprintf( |
||
908 | "Can't find %s named {%s}#%s, at line %d in %s ", |
||
909 | 'attributegroup', |
||
910 | $namespace, |
||
911 | $name, |
||
912 | $node->getLineNo(), |
||
913 | $node->ownerDocument->documentURI |
||
914 | ), |
||
915 | 0, |
||
916 | $e |
||
917 | ); |
||
918 | } |
||
919 | } |
||
920 | |||
921 | 49 | private function findElement(Schema $schema, DOMElement $node, string $typeName): ElementDef |
|
922 | { |
||
923 | 49 | list($name, $namespace) = static::splitParts($node, $typeName); |
|
924 | |||
925 | 49 | $namespace = $namespace ?: $schema->getTargetNamespace(); |
|
926 | |||
927 | try { |
||
928 | 49 | return $schema->findElement($name, $namespace); |
|
929 | } catch (TypeNotFoundException $e) { |
||
930 | throw new TypeException( |
||
931 | sprintf( |
||
932 | "Can't find %s named {%s}#%s, at line %d in %s ", |
||
933 | 'element', |
||
934 | $namespace, |
||
935 | $name, |
||
936 | $node->getLineNo(), |
||
937 | $node->ownerDocument->documentURI |
||
938 | ), |
||
939 | 0, |
||
940 | $e |
||
941 | ); |
||
942 | } |
||
943 | } |
||
944 | |||
945 | 49 | private function findGroup(Schema $schema, DOMElement $node, string $typeName): Group |
|
946 | { |
||
947 | 49 | list($name, $namespace) = static::splitParts($node, $typeName); |
|
948 | |||
949 | 49 | $namespace = $namespace ?: $schema->getTargetNamespace(); |
|
950 | |||
951 | try { |
||
952 | 49 | return $schema->findGroup($name, $namespace); |
|
953 | } catch (TypeNotFoundException $e) { |
||
954 | throw new TypeException( |
||
955 | sprintf( |
||
956 | "Can't find %s named {%s}#%s, at line %d in %s ", |
||
957 | 'group', |
||
958 | $namespace, |
||
959 | $name, |
||
960 | $node->getLineNo(), |
||
961 | $node->ownerDocument->documentURI |
||
962 | ), |
||
963 | 0, |
||
964 | $e |
||
965 | ); |
||
966 | } |
||
967 | } |
||
968 | |||
969 | 49 | private function findType(Schema $schema, DOMElement $node, string $typeName): SchemaItem |
|
970 | { |
||
971 | 49 | list($name, $namespace) = static::splitParts($node, $typeName); |
|
972 | |||
973 | 49 | $namespace = $namespace ?: $schema->getTargetNamespace(); |
|
974 | |||
975 | try { |
||
976 | 49 | return $schema->findType($name, $namespace); |
|
977 | } catch (TypeNotFoundException $e) { |
||
978 | throw new TypeException( |
||
979 | sprintf( |
||
980 | "Can't find %s named {%s}#%s, at line %d in %s ", |
||
981 | 'type', |
||
982 | $namespace, |
||
983 | $name, |
||
984 | $node->getLineNo(), |
||
985 | $node->ownerDocument->documentURI |
||
986 | ), |
||
987 | 0, |
||
988 | $e |
||
989 | ); |
||
990 | } |
||
991 | } |
||
992 | |||
993 | /** |
||
994 | * @return Closure |
||
995 | */ |
||
996 | 49 | private function loadElementDef(Schema $schema, DOMElement $node): Closure |
|
997 | { |
||
998 | 49 | return $this->loadAttributeOrElementDef($schema, $node, false); |
|
999 | } |
||
1000 | |||
1001 | 49 | private function fillItem(Item $element, DOMElement $node) |
|
1002 | { |
||
1003 | /** |
||
1004 | * @var bool |
||
1005 | */ |
||
1006 | 49 | $skip = false; |
|
1007 | 49 | static::againstDOMNodeList( |
|
1008 | 49 | $node, |
|
1009 | 49 | function ( |
|
1010 | DOMElement $node, |
||
1011 | DOMElement $childNode |
||
1012 | ) use ( |
||
1013 | 49 | $element, |
|
1014 | 49 | &$skip |
|
1015 | ) { |
||
1016 | if ( |
||
1017 | 49 | !$skip && |
|
1018 | 49 | in_array( |
|
1019 | 49 | $childNode->localName, |
|
1020 | [ |
||
1021 | 49 | 'complexType', |
|
1022 | 'simpleType', |
||
1023 | ], |
||
1024 | 49 | true |
|
1025 | ) |
||
1026 | ) { |
||
1027 | 49 | $this->loadTypeWithCallback( |
|
1028 | 49 | $element->getSchema(), |
|
1029 | 49 | $childNode, |
|
1030 | 49 | function (Type $type) use ($element) { |
|
1031 | 49 | $element->setType($type); |
|
1032 | 49 | } |
|
1033 | ); |
||
1034 | 49 | $skip = true; |
|
1035 | } |
||
1036 | 49 | } |
|
1037 | ); |
||
1038 | 49 | if ($skip) { |
|
1039 | 49 | return; |
|
1040 | } |
||
1041 | 49 | $this->fillItemNonLocalType($element, $node); |
|
1042 | 49 | } |
|
1043 | |||
1044 | 49 | private function fillItemNonLocalType(Item $element, DOMElement $node): void |
|
1045 | { |
||
1046 | 49 | if ($node->getAttribute('type')) { |
|
1047 | /** |
||
1048 | * @var Type |
||
1049 | */ |
||
1050 | 49 | $type = $this->findSomeType($element, $node, 'type'); |
|
1051 | } else { |
||
1052 | /** |
||
1053 | * @var Type |
||
1054 | */ |
||
1055 | 49 | $type = $this->findSomeTypeFromAttribute( |
|
1056 | 49 | $element, |
|
1057 | 49 | $node, |
|
1058 | 49 | ($node->lookupPrefix(self::XSD_NS).':anyType') |
|
1059 | ); |
||
1060 | } |
||
1061 | |||
1062 | 49 | $element->setType($type); |
|
1063 | 49 | } |
|
1064 | |||
1065 | 49 | private function loadImport( |
|
1066 | Schema $schema, |
||
1067 | DOMElement $node |
||
1068 | ): Closure { |
||
1069 | 49 | $namespace = $node->getAttribute('namespace'); |
|
1070 | 49 | $schemaLocation = $node->getAttribute('schemaLocation'); |
|
1071 | |||
1072 | // postpone schema loading |
||
1073 | 49 | if ($namespace && !$schemaLocation && !isset(self::$globalSchemaInfo[$namespace])) { |
|
1074 | 2 | return function () use ($schema, $namespace) { |
|
1075 | 2 | if (!empty($this->loadedSchemas[$namespace])) { |
|
1076 | 2 | foreach ($this->loadedSchemas[$namespace] as $s) { |
|
1077 | 2 | $schema->addSchema($s, $namespace); |
|
0 ignored issues
–
show
|
|||
1078 | } |
||
1079 | } |
||
1080 | 2 | }; |
|
1081 | 49 | } elseif ($namespace && !$schemaLocation && isset($this->globalSchema[$namespace])) { |
|
1082 | $schema->addSchema($this->globalSchema[$namespace]); |
||
1083 | } |
||
1084 | |||
1085 | 49 | $base = urldecode($node->ownerDocument->documentURI); |
|
1086 | 49 | $file = UrlUtils::resolveRelativeUrl($base, $node->getAttribute('schemaLocation')); |
|
1087 | |||
1088 | 49 | if (isset($this->loadedFiles[$file])) { |
|
1089 | 49 | $schema->addSchema($this->loadedFiles[$file]); |
|
0 ignored issues
–
show
$this->loadedFiles[$file] is of type object<GoetasWebservices...SDReader\Schema\Schema> , but the function expects a object<self> .
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...
|
|||
1090 | |||
1091 | 49 | return function () { |
|
1092 | 49 | }; |
|
1093 | } |
||
1094 | |||
1095 | 1 | return $this->loadImportFresh($namespace, $schema, $file); |
|
1096 | } |
||
1097 | |||
1098 | 1 | private function createOrUseSchemaForNs( |
|
1099 | Schema $schema, |
||
1100 | string $namespace |
||
1101 | ): Schema { |
||
1102 | 1 | if (('' !== trim($namespace))) { |
|
1103 | $newSchema = new Schema(); |
||
1104 | $newSchema->addSchema($this->getGlobalSchema()); |
||
1105 | $schema->addSchema($newSchema); |
||
1106 | } else { |
||
1107 | 1 | $newSchema = $schema; |
|
1108 | } |
||
1109 | |||
1110 | 1 | return $newSchema; |
|
1111 | } |
||
1112 | |||
1113 | private function loadImportFresh( |
||
1114 | string $namespace, |
||
1115 | Schema $schema, |
||
1116 | string $file |
||
1117 | ): Closure { |
||
1118 | 1 | return function () use ($namespace, $schema, $file) { |
|
1119 | 1 | $dom = $this->getDOM( |
|
1120 | 1 | isset($this->knownLocationSchemas[$file]) |
|
1121 | ? $this->knownLocationSchemas[$file] |
||
1122 | 1 | : $file |
|
1123 | ); |
||
1124 | |||
1125 | 1 | $schemaNew = $this->createOrUseSchemaForNs($schema, $namespace); |
|
1126 | |||
1127 | 1 | $this->setLoadedFile($file, $schemaNew); |
|
1128 | |||
1129 | 1 | $callbacks = $this->schemaNode($schemaNew, $dom->documentElement, $schema); |
|
1130 | |||
1131 | 1 | foreach ($callbacks as $callback) { |
|
1132 | 1 | $callback(); |
|
1133 | } |
||
1134 | 1 | }; |
|
1135 | } |
||
1136 | |||
1137 | /** |
||
1138 | * @var Schema|null |
||
1139 | */ |
||
1140 | protected $globalSchema; |
||
1141 | |||
1142 | /** |
||
1143 | * @return Schema |
||
1144 | */ |
||
1145 | 49 | public function getGlobalSchema(): Schema |
|
1146 | { |
||
1147 | 49 | if (!($this->globalSchema instanceof Schema)) { |
|
1148 | 49 | $callbacks = array(); |
|
1149 | 49 | $globalSchemas = array(); |
|
1150 | /** |
||
1151 | * @var string $namespace |
||
1152 | */ |
||
1153 | 49 | foreach (self::$globalSchemaInfo as $namespace => $uri) { |
|
1154 | 49 | $this->setLoadedFile( |
|
1155 | 49 | $uri, |
|
1156 | 49 | $globalSchemas[$namespace] = $schema = new Schema() |
|
1157 | ); |
||
1158 | 49 | if ($namespace === self::XSD_NS) { |
|
1159 | 49 | $this->globalSchema = $schema; |
|
1160 | } |
||
1161 | 49 | $xml = $this->getDOM($this->knownLocationSchemas[$uri]); |
|
1162 | 49 | $callbacks = array_merge($callbacks, $this->schemaNode($schema, $xml->documentElement)); |
|
1163 | } |
||
1164 | |||
1165 | 49 | $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anySimpleType')); |
|
1166 | 49 | $globalSchemas[(string) static::XSD_NS]->addType(new SimpleType($globalSchemas[(string) static::XSD_NS], 'anyType')); |
|
1167 | |||
1168 | 49 | $globalSchemas[(string) static::XML_NS]->addSchema( |
|
1169 | 49 | $globalSchemas[(string) static::XSD_NS], |
|
1170 | 49 | (string) static::XSD_NS |
|
1171 | ); |
||
1172 | 49 | $globalSchemas[(string) static::XSD_NS]->addSchema( |
|
1173 | 49 | $globalSchemas[(string) static::XML_NS], |
|
1174 | 49 | (string) static::XML_NS |
|
1175 | ); |
||
1176 | |||
1177 | /** |
||
1178 | * @var Closure |
||
1179 | */ |
||
1180 | 49 | foreach ($callbacks as $callback) { |
|
1181 | 49 | $callback(); |
|
1182 | } |
||
1183 | } |
||
1184 | |||
1185 | /** |
||
1186 | * @var Schema |
||
1187 | */ |
||
1188 | 49 | $out = $this->globalSchema; |
|
1189 | |||
1190 | 49 | if (!($out instanceof Schema)) { |
|
1191 | throw new TypeException('Globa schema not discoverd'); |
||
1192 | } |
||
1193 | |||
1194 | 49 | return $out; |
|
1195 | } |
||
1196 | |||
1197 | 1 | public function readNodes(array $nodes, string $file = null) |
|
1198 | { |
||
1199 | 1 | $rootSchema = new Schema(); |
|
1200 | 1 | $rootSchema->addSchema($this->getGlobalSchema()); |
|
0 ignored issues
–
show
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema> , but the function expects a object<self> .
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...
|
|||
1201 | |||
1202 | 1 | if ($file !== null) { |
|
1203 | $this->setLoadedFile($file, $rootSchema); |
||
1204 | } |
||
1205 | |||
1206 | 1 | $all = array(); |
|
1207 | 1 | foreach ($nodes as $k => $node) { |
|
1208 | 1 | if (($node instanceof \DOMElement) && $node->namespaceURI === self::XSD_NS && $node->localName == 'schema') { |
|
1209 | 1 | $holderSchema = new Schema(); |
|
1210 | 1 | $holderSchema->addSchema($this->getGlobalSchema()); |
|
0 ignored issues
–
show
$this->getGlobalSchema() is of type object<GoetasWebservices...SDReader\Schema\Schema> , but the function expects a object<self> .
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...
|
|||
1211 | |||
1212 | 1 | $this->setLoadedSchema($node, $holderSchema); |
|
1213 | |||
1214 | 1 | $rootSchema->addSchema($holderSchema); |
|
0 ignored issues
–
show
$holderSchema is of type object<GoetasWebservices...SDReader\Schema\Schema> , but the function expects a object<self> .
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...
|
|||
1215 | |||
1216 | 1 | $callbacks = $this->schemaNode($holderSchema, $node); |
|
1217 | 1 | $all = array_merge($callbacks, $all); |
|
1218 | } |
||
1219 | } |
||
1220 | |||
1221 | 1 | foreach ($all as $callback) { |
|
1222 | 1 | call_user_func($callback); |
|
1223 | } |
||
1224 | |||
1225 | 1 | return $rootSchema; |
|
1226 | } |
||
1227 | |||
1228 | 48 | public function readNode(DOMElement $node, string $file = null): Schema |
|
1229 | { |
||
1230 | 48 | $rootSchema = new Schema(); |
|
1231 | 48 | $rootSchema->addSchema($this->getGlobalSchema()); |
|
1232 | |||
1233 | 48 | if ($file !== null) { |
|
1234 | 47 | $this->setLoadedFile($file, $rootSchema); |
|
1235 | } |
||
1236 | |||
1237 | 48 | $this->setLoadedSchema($node, $rootSchema); |
|
1238 | |||
1239 | 48 | $callbacks = $this->schemaNode($rootSchema, $node); |
|
1240 | |||
1241 | 48 | foreach ($callbacks as $callback) { |
|
1242 | 42 | call_user_func($callback); |
|
1243 | } |
||
1244 | |||
1245 | 48 | return $rootSchema; |
|
1246 | } |
||
1247 | |||
1248 | /** |
||
1249 | * @throws IOException |
||
1250 | */ |
||
1251 | 46 | public function readString(string $content, string $file = 'schema.xsd'): Schema |
|
1252 | { |
||
1253 | 46 | $xml = new DOMDocument('1.0', 'UTF-8'); |
|
1254 | 46 | if (!$xml->loadXML($content)) { |
|
1255 | throw new IOException("Can't load the schema"); |
||
1256 | } |
||
1257 | 46 | $xml->documentURI = $file; |
|
1258 | |||
1259 | 46 | return $this->readNode($xml->documentElement, $file); |
|
1260 | } |
||
1261 | |||
1262 | 1 | public function readFile(string $file): Schema |
|
1263 | { |
||
1264 | 1 | $xml = $this->getDOM($file); |
|
1265 | |||
1266 | 1 | return $this->readNode($xml->documentElement, $file); |
|
1267 | } |
||
1268 | |||
1269 | /** |
||
1270 | * @throws IOException |
||
1271 | */ |
||
1272 | 49 | private function getDOM(string $file): DOMDocument |
|
1273 | { |
||
1274 | 49 | $xml = new DOMDocument('1.0', 'UTF-8'); |
|
1275 | 49 | if (!$xml->load($file)) { |
|
1276 | throw new IOException("Can't load the file $file"); |
||
1277 | } |
||
1278 | |||
1279 | 49 | return $xml; |
|
1280 | } |
||
1281 | |||
1282 | 49 | private static function againstDOMNodeList( |
|
1283 | DOMElement $node, |
||
1284 | Closure $againstNodeList |
||
1285 | ) { |
||
1286 | 49 | $limit = $node->childNodes->length; |
|
1287 | 49 | for ($i = 0; $i < $limit; $i += 1) { |
|
1288 | /** |
||
1289 | * @var DOMNode |
||
1290 | */ |
||
1291 | 49 | $childNode = $node->childNodes->item($i); |
|
1292 | |||
1293 | 49 | if ($childNode instanceof DOMElement) { |
|
1294 | 49 | $againstNodeList( |
|
1295 | 49 | $node, |
|
1296 | 49 | $childNode |
|
1297 | ); |
||
1298 | } |
||
1299 | } |
||
1300 | 49 | } |
|
1301 | |||
1302 | 49 | private function loadTypeWithCallback( |
|
1303 | Schema $schema, |
||
1304 | DOMElement $childNode, |
||
1305 | Closure $callback |
||
1306 | ) { |
||
1307 | /** |
||
1308 | * @var Closure|null $func |
||
1309 | */ |
||
1310 | 49 | $func = null; |
|
1311 | |||
1312 | 49 | switch ($childNode->localName) { |
|
1313 | 49 | case 'complexType': |
|
1314 | 49 | $func = $this->loadComplexType($schema, $childNode, $callback); |
|
1315 | 49 | break; |
|
1316 | 49 | case 'simpleType': |
|
1317 | 49 | $func = $this->loadSimpleType($schema, $childNode, $callback); |
|
1318 | 49 | break; |
|
1319 | } |
||
1320 | |||
1321 | 49 | if ($func instanceof Closure) { |
|
1322 | 49 | call_user_func($func); |
|
1323 | } |
||
1324 | 49 | } |
|
1325 | |||
1326 | 49 | private function loadElement( |
|
1327 | Schema $schema, |
||
1328 | DOMElement $node |
||
1329 | ): Element { |
||
1330 | 49 | $element = new Element($schema, $node->getAttribute('name')); |
|
1331 | 49 | $element->setDoc($this->getDocumentation($node)); |
|
1332 | |||
1333 | 49 | $this->fillItem($element, $node); |
|
1334 | |||
1335 | 49 | self::maybeSetMax($element, $node); |
|
1336 | 49 | self::maybeSetMin($element, $node); |
|
1337 | |||
1338 | 49 | $xp = new \DOMXPath($node->ownerDocument); |
|
1339 | 49 | $xp->registerNamespace('xs', 'http://www.w3.org/2001/XMLSchema'); |
|
1340 | |||
1341 | 49 | if ($xp->query('ancestor::xs:choice', $node)->length) { |
|
1342 | 49 | $element->setMin(0); |
|
1343 | } |
||
1344 | |||
1345 | 49 | if ($node->hasAttribute('nillable')) { |
|
1346 | 3 | $element->setNil($node->getAttribute('nillable') == 'true'); |
|
1347 | } |
||
1348 | 49 | if ($node->hasAttribute('form')) { |
|
1349 | 3 | $element->setQualified($node->getAttribute('form') == 'qualified'); |
|
1350 | } |
||
1351 | |||
1352 | 49 | return $element; |
|
1353 | } |
||
1354 | |||
1355 | 49 | private function addAttributeFromAttributeOrRef( |
|
1356 | BaseComplexType $type, |
||
1357 | DOMElement $childNode, |
||
1358 | Schema $schema, |
||
1359 | DOMElement $node |
||
1360 | ): void { |
||
1361 | 49 | $attribute = $this->getAttributeFromAttributeOrRef( |
|
1362 | 49 | $childNode, |
|
1363 | 49 | $schema, |
|
1364 | 49 | $node |
|
1365 | ); |
||
1366 | |||
1367 | 49 | $type->addAttribute($attribute); |
|
1368 | 49 | } |
|
1369 | |||
1370 | 49 | private function findSomethingLikeAttributeGroup( |
|
1371 | Schema $schema, |
||
1372 | DOMElement $node, |
||
1373 | DOMElement $childNode, |
||
1374 | AttributeContainer $addToThis |
||
1375 | ): void { |
||
1376 | 49 | $attribute = $this->findAttributeGroup($schema, $node, $childNode->getAttribute('ref')); |
|
1377 | 49 | $addToThis->addAttribute($attribute); |
|
1378 | 49 | } |
|
1379 | |||
1380 | 49 | private function setLoadedFile(string $key, Schema $schema): void |
|
1381 | { |
||
1382 | 49 | $this->loadedFiles[$key] = $schema; |
|
1383 | 49 | } |
|
1384 | |||
1385 | 49 | private function setLoadedSchema(DOMElement $node, Schema $schema): void |
|
1386 | { |
||
1387 | 49 | if ($node->hasAttribute('targetNamespace')) { |
|
1388 | 49 | $this->loadedSchemas[$node->getAttribute('targetNamespace')][] = $schema; |
|
1389 | } |
||
1390 | 49 | } |
|
1391 | |||
1392 | 49 | private function setSchemaThingsFromNode( |
|
1393 | Schema $schema, |
||
1394 | DOMElement $node, |
||
1395 | Schema $parent = null |
||
1396 | ): void { |
||
1397 | 49 | $schema->setDoc($this->getDocumentation($node)); |
|
1398 | |||
1399 | 49 | if ($node->hasAttribute('targetNamespace')) { |
|
1400 | 49 | $schema->setTargetNamespace($node->getAttribute('targetNamespace')); |
|
1401 | } elseif ($parent instanceof Schema) { |
||
1402 | $schema->setTargetNamespace($parent->getTargetNamespace()); |
||
1403 | } |
||
1404 | 49 | $schema->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified'); |
|
1405 | 49 | $schema->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified'); |
|
1406 | 49 | $schema->setDoc($this->getDocumentation($node)); |
|
1407 | 49 | } |
|
1408 | } |
||
1409 |
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: