Test Failed
Push — php-7.1 ( d00c2a...d2218e )
by SignpostMarv
10:23
created

Schema::getLoadedFile()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 1
nop 1
dl 0
loc 9
ccs 0
cts 0
cp 0
crap 12
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GoetasWebservices\XML\XSDReader\Schema;
6
7
use DOMElement;
8
use RuntimeException;
9
use GoetasWebservices\XML\XSDReader\SchemaReader;
10
use GoetasWebservices\XML\XSDReader\Schema\Type\Type;
11
use GoetasWebservices\XML\XSDReader\Schema\Attribute\Group as AttributeGroup;
12
use GoetasWebservices\XML\XSDReader\Schema\Element\Group;
13
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementDef;
14
use GoetasWebservices\XML\XSDReader\Schema\Element\ElementItem;
15 45
use GoetasWebservices\XML\XSDReader\Schema\Exception\TypeNotFoundException;
16
use GoetasWebservices\XML\XSDReader\Schema\Exception\SchemaException;
17
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeItem;
18
use GoetasWebservices\XML\XSDReader\Schema\Attribute\AttributeDef;
19
20
class Schema
21 45
{
22 45
    /**
23
     * @param bool[] $calling
24 45
     */
25 45
    protected function findSomethingNoThrow(
26
        string $getter,
27 45
        string $name,
28
        string $namespace = null,
29
        array &$calling = array()
30
    ): ? SchemaItem {
31
        $calling[spl_object_hash($this)] = true;
32 45
        $cid = "$getter, $name, $namespace";
33
34 45
        if (isset($this->typeCache[$cid])) {
35 45
            return $this->typeCache[$cid];
36
        } elseif (
37
            $this->getTargetNamespace() === $namespace
38
        ) {
39 45
            /**
40 45
             * @var SchemaItem|null
41 45
             */
42 45
            $item = $this->$getter($name);
43 45
44 45
            if ($item instanceof SchemaItem) {
45 45
                return $this->typeCache[$cid] = $item;
46
            }
47
        }
48
49
        return $this->findSomethingNoThrowSchemas(
50
            $this->getSchemas(),
51
            $cid,
52
            $getter,
53 45
            $name,
54
            $namespace,
55
            $calling
56
        );
57
    }
58
59
    /**
60
     * @param Schema[] $schemas
61 45
     * @param bool[]   $calling
62 45
     */
63
    protected function findSomethingNoThrowSchemas(
64
        array $schemas,
65
        string $cid,
66 45
        string $getter,
67
        string $name,
68 45
        string $namespace = null,
69 45
        array &$calling = array()
70
    ): ? SchemaItem {
71
        foreach ($schemas as $childSchema) {
72
            if (!isset($calling[spl_object_hash($childSchema)])) {
73
                /**
74 7
                 * @var SchemaItem|null
75
                 */
76
                $in = $childSchema->findSomethingNoThrow($getter, $name, $namespace, $calling);
77
78
                if ($in instanceof SchemaItem) {
79
                    return $this->typeCache[$cid] = $in;
80
                }
81 45
            }
82
        }
83
84
        return null;
85
    }
86
87 45
    /**
88 45
     * @param bool[] $calling
89 45
     *
90 45
     * @throws TypeNotFoundException
91 45
     */
92
    protected function findSomething(
93
        string $getter,
94 45
        string $name,
95 45
        string $namespace = null,
96
        array &$calling = array()
97
    ): SchemaItem {
98 5
        $in = $this->findSomethingNoThrow(
99
            $getter,
100
            $name,
101
            $namespace,
102
            $calling
103
        );
104
105
        if ($in instanceof SchemaItem) {
106 45
            return $in;
107
        }
108
109
        throw new TypeNotFoundException(
110
            sprintf("Can't find the %s named {%s}#%s.", substr($getter, 3), (string) $namespace, $name)
111 45
        );
112
    }
113 45
114
    /**
115 45
     * @var bool
116 45
     */
117
    protected $elementsQualification = false;
118
119 45
    /**
120 45
     * @var bool
121 45
     */
122
    protected $attributesQualification = false;
123
124 45
    /**
125
     * @var null|string
126 45
     */
127
    protected $targetNamespace;
128
129
    /**
130
     * @var Schema[]
131
     */
132 1
    protected $schemas = array();
133
134
    /**
135
     * @var Type[]
136
     */
137
    protected $types = array();
138
139
    /**
140
     * @var ElementDef[]
141 1
     */
142 1
    protected $elements = array();
143 1
144
    /**
145
     * @var Group[]
146 1
     */
147
    protected $groups = array();
148
149
    /**
150
     * @var AttributeGroup[]
151 1
     */
152
    protected $attributeGroups = array();
153
154
    /**
155
     * @var AttributeDef[]
156
     */
157 1
    protected $attributes = array();
158
159
    /**
160
     * @var string|null
161
     */
162
    protected $doc;
163
164
    /**
165
     * @var \GoetasWebservices\XML\XSDReader\Schema\SchemaItem[]
166 1
     */
167
    protected $typeCache = array();
168 1
169 1
    public function getElementsQualification(): bool
170 1
    {
171 1
        return $this->elementsQualification;
172 1
    }
173 1
174
    public function setElementsQualification(
175 1
        bool $elementsQualification
176 1
    ): void {
177
        $this->elementsQualification = $elementsQualification;
178 1
    }
179 1
180 1
    public function getAttributesQualification(): bool
181
    {
182
        return $this->attributesQualification;
183
    }
184
185
    public function setAttributesQualification(
186
        bool $attributesQualification
187
    ): void {
188
        $this->attributesQualification = $attributesQualification;
189
    }
190
191
    public function getTargetNamespace(): ? string
192
    {
193 1
        return $this->targetNamespace;
194
    }
195 1
196 1
    public function setTargetNamespace(? string $targetNamespace): void
197 1
    {
198 1
        $this->targetNamespace = $targetNamespace;
199 1
    }
200
201
    /**
202 1
     * @return Type[]
203
     */
204 1
    public function getTypes(): array
205
    {
206
        return $this->types;
207
    }
208
209
    /**
210
     * @return ElementDef[]
211
     */
212
    public function getElements(): array
213
    {
214
        return $this->elements;
215
    }
216
217
    /**
218
     * @return Schema[]
219
     */
220
    public function getSchemas(): array
221
    {
222
        return $this->schemas;
223
    }
224
225
    /**
226
     * @return AttributeDef[]
227
     */
228
    public function getAttributes(): array
229
    {
230
        return $this->attributes;
231
    }
232
233
    /**
234
     * @return Group[]
235
     */
236
    public function getGroups(): array
237
    {
238
        return $this->groups;
239
    }
240
241
    public function getDoc(): ? string
242
    {
243
        return $this->doc;
244
    }
245
246
    public function setDoc(string $doc): void
247
    {
248
        $this->doc = $doc;
249
    }
250
251
    public function addType(Type $type): void
252
    {
253
        $this->types[$type->getName()] = $type;
254
    }
255
256
    public function addElement(ElementDef $element): void
257
    {
258
        $this->elements[$element->getName()] = $element;
259
    }
260
261
    public function addSchema(Schema $schema, string $namespace = null): void
262
    {
263
        if ($namespace !== null) {
264
            if ($schema->getTargetNamespace() !== $namespace) {
265
                throw new SchemaException(
266
                    sprintf(
267
                        "The target namespace ('%s') for schema, does not match the declared namespace '%s'",
268
                        (string) $schema->getTargetNamespace(),
269
                        $namespace
270
                    )
271
                );
272
            }
273
            $this->schemas[$namespace] = $schema;
274
        } else {
275
            $this->schemas[] = $schema;
276
        }
277
    }
278
279
    public function addAttribute(AttributeDef $attribute): void
280
    {
281
        $this->attributes[$attribute->getName()] = $attribute;
282
    }
283
284
    public function addGroup(Group $group): void
285
    {
286
        $this->groups[$group->getName()] = $group;
287
    }
288
289
    public function addAttributeGroup(AttributeGroup $group): void
290
    {
291
        $this->attributeGroups[$group->getName()] = $group;
292
    }
293
294
    /**
295
     * @return AttributeGroup[]
296
     */
297
    public function getAttributeGroups(): array
298
    {
299
        return $this->attributeGroups;
300
    }
301
302
    public function getGroup(string $name): ? Group
303
    {
304
        if (isset($this->groups[$name])) {
305
            return $this->groups[$name];
306
        }
307
308
        return null;
309
    }
310
311
    /**
312
     * @param string $name
313
     *
314
     * @return ElementItem|false
315
     */
316
    public function getElement($name)
317
    {
318
        if (isset($this->elements[$name])) {
319
            return $this->elements[$name];
320
        }
321
322
        return false;
323
    }
324
325
    /**
326
     * @param string $name
327
     *
328
     * @return Type|false
329
     */
330
    public function getType($name)
331
    {
332
        if (isset($this->types[$name])) {
333
            return $this->types[$name];
334
        }
335
336
        return false;
337
    }
338
339
    /**
340
     * @param string $name
341
     *
342
     * @return AttributeItem|false
343
     */
344
    public function getAttribute($name)
345
    {
346
        if (isset($this->attributes[$name])) {
347
            return $this->attributes[$name];
348
        }
349
350
        return false;
351
    }
352
353
    /**
354
     * @param string $name
355
     *
356
     * @return AttributeGroup|false
357
     */
358
    public function getAttributeGroup($name)
359
    {
360
        if (isset($this->attributeGroups[$name])) {
361
            return $this->attributeGroups[$name];
362
        }
363
364
        return false;
365
    }
366
367
    public function __toString()
368
    {
369
        return sprintf('Target namespace %s', (string) $this->getTargetNamespace());
370
    }
371
372
    public function findType(string $name, string $namespace = null): Type
373
    {
374
        /**
375
         * @var Type
376
         */
377
        $out = $this->findSomething('getType', $name, $namespace);
378
379
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type GoetasWebservices\XML\XSDReader\Schema\SchemaItem which includes types incompatible with the type-hinted return GoetasWebservices\XML\XSDReader\Schema\Type\Type.
Loading history...
380
    }
381
382
    public function findGroup(string $name, string $namespace = null): Group
383
    {
384
        /**
385
         * @var Group
386
         */
387
        $out = $this->findSomething('getGroup', $name, $namespace);
388
389
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type GoetasWebservices\XML\XSDReader\Schema\SchemaItem which includes types incompatible with the type-hinted return GoetasWebservices\XML\XS...er\Schema\Element\Group.
Loading history...
390
    }
391
392
    public function findElement(string $name, string $namespace = null): ElementDef
393
    {
394
        /**
395
         * @var ElementDef
396
         */
397
        $out = $this->findSomething('getElement', $name, $namespace);
398
399
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type GoetasWebservices\XML\XSDReader\Schema\SchemaItem which includes types incompatible with the type-hinted return GoetasWebservices\XML\XS...hema\Element\ElementDef.
Loading history...
400
    }
401
402
    public function findAttribute(string $name, string $namespace = null): AttributeItem
403
    {
404
        /**
405
         * @var AttributeItem
406
         */
407
        $out = $this->findSomething('getAttribute', $name, $namespace);
408
409
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type GoetasWebservices\XML\XSDReader\Schema\SchemaItem which includes types incompatible with the type-hinted return GoetasWebservices\XML\XS...Attribute\AttributeItem.
Loading history...
410
    }
411
412
    public function findAttributeGroup(string $name, string $namespace = null): AttributeGroup
413
    {
414
        /**
415
         * @var AttributeGroup
416
         */
417
        $out = $this->findSomething('getAttributeGroup', $name, $namespace);
418
419
        return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type GoetasWebservices\XML\XSDReader\Schema\SchemaItem which includes types incompatible with the type-hinted return GoetasWebservices\XML\XS...\Schema\Attribute\Group.
Loading history...
420
    }
421
422
    /**
423
     * @var Schema[]
424
     */
425
    protected static $loadedFiles = array();
426
427
    public static function hasLoadedFile(string ...$keys): bool
428
    {
429
        foreach ($keys as $key) {
430
            if (isset(self::$loadedFiles[$key])) {
431
                return true;
432
            }
433
        }
434
435
        return false;
436
    }
437
438
    /**
439
     * @throws RuntimeException if loaded file not found
440
     */
441
    public static function getLoadedFile(string ...$keys): Schema
442
    {
443
        foreach ($keys as $key) {
444
            if (isset(self::$loadedFiles[$key])) {
445
                return self::$loadedFiles[$key];
446
            }
447
        }
448
449
        throw new RuntimeException('Loaded file was not found!');
450
    }
451
452
    public static function setLoadedFile(string $key, Schema $schema): Schema
453
    {
454
        self::$loadedFiles[$key] = $schema;
455
456
        return $schema;
457
    }
458
459
    public function setSchemaThingsFromNode(
460
        DOMElement $node,
461
        Schema $parent = null
462
    ): void {
463
        $this->setDoc(SchemaReader::getDocumentation($node));
464
465
        if ($node->hasAttribute('targetNamespace')) {
466
            $this->setTargetNamespace($node->getAttribute('targetNamespace'));
467
        } elseif ($parent) {
468
            $this->setTargetNamespace($parent->getTargetNamespace());
469
        }
470
        $this->setElementsQualification($node->getAttribute('elementFormDefault') == 'qualified');
471
        $this->setAttributesQualification($node->getAttribute('attributeFormDefault') == 'qualified');
472
        $this->setDoc(SchemaReader::getDocumentation($node));
473
    }
474
}
475