Passed
Push — static-analysis ( 309dd4...661417 )
by SignpostMarv
03:28
created

AbstractSchema   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 571
Duplicated Lines 0 %

Test Coverage

Coverage 82.84%

Importance

Changes 0
Metric Value
dl 0
loc 571
ccs 111
cts 134
cp 0.8284
rs 8.6206
c 0
b 0
f 0
wmc 50

36 Methods

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