Passed
Push — php-7.1 ( 280be0...7ba4a5 )
by SignpostMarv
02:07
created

AbstractSchema   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 521
Duplicated Lines 0 %

Test Coverage

Coverage 83.59%

Importance

Changes 0
Metric Value
dl 0
loc 521
ccs 107
cts 128
cp 0.8359
rs 8.6206
c 0
b 0
f 0
wmc 50

36 Methods

Rating   Name   Duplication   Size   Complexity  
A getLoadedFile() 0 9 3
A setSchemaThingsFromNode() 0 14 3
A setAttributesQualification() 0 4 1
A addType() 0 3 1
A findType() 0 8 1
A getGroup() 0 6 2
A getElements() 0 3 1
A findElement() 0 8 1
A hasLoadedFile() 0 9 3
A addSchema() 0 15 3
A findAttribute() 0 8 1
A getDoc() 0 3 1
A addAttributeGroup() 0 3 1
A __toString() 0 3 1
A addGroup() 0 3 1
A getTypes() 0 3 1
A getSchemas() 0 3 1
A loadImport() 0 22 2
A getElementsQualification() 0 3 1
A getAttribute() 0 6 2
A getType() 0 6 2
A getAttributes() 0 3 1
A getGroups() 0 3 1
A findGroup() 0 8 1
A setTargetNamespace() 0 3 1
A getAttributeGroups() 0 3 1
A addAttribute() 0 3 1
A getAttributeGroup() 0 6 2
A findAttributeGroup() 0 8 1
A getAttributesQualification() 0 3 1
A getElement() 0 6 2
A setElementsQualification() 0 4 1
A getTargetNamespace() 0 3 1
A addElement() 0 3 1
A setDoc() 0 3 1
A setLoadedFile() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractSchema 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.

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 AbstractSchema, and based on these observations, apply Extract Interface, too.

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