Passed
Push — static-analysis ( f539d2...7025cd )
by SignpostMarv
03:14
created

AbstractSchema   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 567
Duplicated Lines 0 %

Test Coverage

Coverage 82.22%

Importance

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