ModelElementTypeImpl   C
last analyzed

Complexity

Total Complexity 56

Size/Duplication

Total Lines 280
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 115
c 1
b 0
f 0
dl 0
loc 280
rs 5.5199
wmc 56

32 Methods

Rating   Name   Duplication   Size   Complexity  
A isAbstract() 0 3 1
A __construct() 0 5 1
A getInstances() 0 11 2
A getInstanceType() 0 3 1
A createModelElementInstance() 0 12 2
A getTypeName() 0 3 1
A setAbstract() 0 3 1
A isBaseTypeOf() 0 7 2
A setBaseType() 0 11 3
A getBaseType() 0 3 1
A registerChildElementCollection() 0 4 2
A newInstance() 0 11 2
A getChildElementCollections() 0 3 1
A resolveExtendingTypes() 0 6 3
A registerAttribute() 0 4 2
A registerExtendingType() 0 4 2
A getAttribute() 0 8 3
A getChildElementTypes() 0 3 1
A getElementsByNameNs() 0 18 5
A getAllChildElementCollections() 0 11 2
A getAllChildElementTypes() 0 8 2
A getModel() 0 3 1
A setTypeNamespace() 0 3 1
A registerChildElementType() 0 4 2
A getAllAttributes() 0 8 2
A getChildElementCollection() 0 9 3
A getAttributes() 0 3 1
A getExtendingTypes() 0 3 1
A setInstanceProvider() 0 3 1
A getTypeNamespace() 0 3 1
A resolveBaseTypes() 0 5 2
A getAllExtendingTypes() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like ModelElementTypeImpl 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 ModelElementTypeImpl, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Xml\Impl\Type;
4
5
use Xml\{
6
    ModelInterface,
7
    ModelInstanceInterface
8
};
9
use Xml\Exception\{
10
    ModelException,
11
    ModelTypeException
12
};
13
use Xml\Type\Child\ChildElementCollectionInterface;
14
use Xml\Impl\ModelImpl;
15
use Xml\Impl\Instance\ModelTypeInstanceContext;
16
use Xml\Impl\Util\ModelUtil;
17
use Xml\Instance\{
18
    DomDocumentInterface,
19
    DomElementInterface,
20
    ModelElementInstanceInterface
21
};
22
use Xml\Type\{
23
    ModelElementTypeInterface,
24
    ModelTypeInstanceProviderInterface
25
};
26
use Xml\Type\Attribute\AttributeInterface;
27
28
class ModelElementTypeImpl implements ModelElementTypeInterface
29
{
30
    private $model;
31
    private $typeName;
32
    private $instanceType;
33
    private $typeNamespace;
34
    private $baseType;
35
    private $extendingTypes = [];
36
    private $attributes = [];
37
    private $childElementTypes = [];
38
    private $childElementCollections = [];
39
    private $instanceProvider;
40
    private $isAbstract;
41
42
    public function __construct(ModelImpl $model, string $name, string $instanceType)
43
    {
44
        $this->model = $model;
45
        $this->typeName = $name;
46
        $this->instanceType = $instanceType;
47
    }
48
49
    public function newInstance(
50
        ModelInstanceInterface $modelInstance,
51
        ?DomElementInterface $domElement = null
52
    ): ModelElementInstanceInterface {
53
        if ($domElement !== null) {
54
            $modelTypeInstanceContext = new ModelTypeInstanceContext($domElement, $modelInstance, $this);
55
            return $this->createModelElementInstance($modelTypeInstanceContext);
56
        } else {
57
            $document = $modelInstance->getDocument();
58
            $domElement = $document->createElement($this->typeNamespace, $this->typeName);
59
            return $this->newInstance($modelInstance, $domElement);
60
        }
61
    }
62
63
    public function registerAttribute(AttributeInterface $attribute): void
64
    {
65
        if (!in_array($attribute, $this->attributes)) {
66
            $this->attributes[] = $attribute;
67
        }
68
    }
69
70
    public function registerChildElementType(ModelElementTypeInterface $childElementType): void
71
    {
72
        if (!in_array($childElementType, $this->childElementTypes)) {
73
            $this->childElementTypes[] = $childElementType;
74
        }
75
    }
76
77
    public function registerChildElementCollection(ChildElementCollectionInterface $childElementCollection): void
78
    {
79
        if (!in_array($childElementCollection, $this->childElementCollections)) {
80
            $this->childElementCollections[] = $childElementCollection;
81
        }
82
    }
83
84
    public function registerExtendingType(ModelElementTypeInterface $modelType): void
85
    {
86
        if (!in_array($modelType, $this->extendingTypes)) {
87
            $this->extendingTypes[] = $modelType;
88
        }
89
    }
90
91
    protected function createModelElementInstance(
92
        ModelTypeInstanceContext $instanceContext
93
    ): ModelElementInstanceInterface {
94
        if ($this->isAbstract) {
95
            throw new ModelTypeException(
96
                sprintf(
97
                    "Model element type %s is abstract and no instances can be created.",
98
                    $this->getTypeName()
99
                )
100
            );
101
        } else {
102
            return $this->instanceProvider->newInstance($instanceContext);
103
        }
104
    }
105
106
    public function getAttributes(): array
107
    {
108
        return $this->attributes;
109
    }
110
111
    public function getTypeName(): string
112
    {
113
        return $this->typeName;
114
    }
115
116
    public function getInstanceType(): string
117
    {
118
        return $this->instanceType;
119
    }
120
121
    public function setTypeNamespace(?string $typeNamespace): void
122
    {
123
        $this->typeNamespace = $typeNamespace;
124
    }
125
126
    public function getTypeNamespace(): ?string
127
    {
128
        return $this->typeNamespace;
129
    }
130
131
    public function setBaseType(ModelElementTypeImpl $baseType): void
132
    {
133
        if ($this->baseType === null) {
134
            $this->baseType = $baseType;
135
        } elseif ($this->baseType != $baseType) {
136
            throw new ModelException(
137
                sprintf(
138
                    "Type can not have multiple base types. %s already extends type %s and can not also extend type %s",
139
                    get_class($this),
140
                    get_class($this->baseType),
141
                    get_class($this)
142
                )
143
            );
144
        }
145
    }
146
147
    public function setInstanceProvider(ModelTypeInstanceProviderInterface $instanceProvider): void
148
    {
149
        $this->instanceProvider = $instanceProvider;
150
    }
151
152
    public function isAbstract(): bool
153
    {
154
        return $this->isAbstract ?? false;
155
    }
156
157
    public function setAbstract(bool $isAbstract): void
158
    {
159
        $this->isAbstract = $isAbstract;
160
    }
161
162
    public function getExtendingTypes(): array
163
    {
164
        return $this->extendingTypes;
165
    }
166
167
    public function getAllExtendingTypes(): array
168
    {
169
        $extendingTypes = [];
170
        $extendingTypes[] = $this;
171
        $this->resolveExtendingTypes($extendingTypes);
172
        return $extendingTypes;
173
    }
174
175
    public function resolveExtendingTypes(array &$allExtendingTypes): void
176
    {
177
        foreach ($this->extendingTypes as $modelElementTypeImpl) {
178
            if (!in_array($modelElementTypeImpl, $allExtendingTypes)) {
179
                $allExtendingTypes[] = $modelElementTypeImpl;
180
                $modelElementTypeImpl->resolveExtendingTypes($allExtendingTypes);
181
            }
182
        }
183
    }
184
185
    public function resolveBaseTypes(array &$baseTypes): void
186
    {
187
        if ($this->baseType !== null) {
188
            $baseTypes[] = $this->baseType;
189
            $this->baseType->resolveBaseTypes($baseTypes);
190
        }
191
    }
192
193
    public function getBaseType(): ?ModelElementTypeInterface
194
    {
195
        return $this->baseType;
196
    }
197
198
    public function getModel(): ModelInterface
199
    {
200
        return $this->model;
201
    }
202
203
    public function getChildElementTypes(): array
204
    {
205
        return $this->childElementTypes;
206
    }
207
208
    public function getAllChildElementTypes(): array
209
    {
210
        $allChildElementTypes = [];
211
        if ($this->baseType !== null) {
212
            $allChildElementTypes = array_merge($allChildElementTypes, $this->baseType->getAllChildElementTypes());
213
        }
214
        $allChildElementTypes = array_merge($allChildElementTypes, $this->childElementTypes);
215
        return $allChildElementTypes;
216
    }
217
218
    public function getChildElementCollections(): array
219
    {
220
        return $this->childElementCollections;
221
    }
222
223
    public function getAllChildElementCollections(): array
224
    {
225
        $allChildElementCollections = [];
226
        if ($this->baseType !== null) {
227
            $allChildElementCollections = array_merge(
228
                $allChildElementCollections,
229
                $this->baseType->getAllChildElementCollections()
230
            );
231
        }
232
        $allChildElementCollections = array_merge($allChildElementCollections, $this->childElementCollections);
233
        return $allChildElementCollections;
234
    }
235
236
    public function getInstances(ModelInstanceInterface $modelInstanceImpl): array
237
    {
238
        $document = $modelInstanceImpl->getDocument();
239
240
        $elements = $this->getElementsByNameNs($document, $this->typeNamespace);
241
242
        $resultList = [];
243
        foreach ($elements as $element) {
244
            $resultList[] = ModelUtil::getModelElement($element, $modelInstanceImpl, $this);
245
        }
246
        return $resultList;
247
    }
248
249
    protected function getElementsByNameNs(DomDocumentInterface $document, string $namespaceURI): array
250
    {
251
        $elements = $document->getElementsByNameNs($namespaceURI, $this->typeName);
252
253
        if (empty($elements)) {
254
            $alternativeNamespaces = $this->getModel()->getAlternativeNamespaces($namespaceURI);
255
256
            if (!empty($alternativeNamespaces)) {
257
                foreach ($alternativeNamespaces as $namespace) {
258
                    $elements = $this->getElementsByNameNs($document, $namespace);
259
                    if (!empty($elements)) {
260
                        break;
261
                    }
262
                }
263
            }
264
        }
265
266
        return $elements;
267
    }
268
269
    public function isBaseTypeOf(ModelElementTypeInterface $elementType): bool
270
    {
271
        if ($this == $elementType) {
272
            return true;
273
        } else {
274
            $baseTypes = ModelUtil::calculateAllBaseTypes($elementType);
275
            return in_array($this, $baseTypes);
276
        }
277
    }
278
279
    public function getAllAttributes(): array
280
    {
281
        $allAttributes = array_merge([], $this->getAttributes());
282
        $baseTypes = ModelUtil::calculateAllBaseTypes($this);
283
        foreach ($baseTypes as $baseType) {
284
            $allAttributes = array_merge($allAttributes, $baseType->getAttributes());
285
        }
286
        return $allAttributes;
287
    }
288
289
    public function getAttribute(string $attributeName): ?AttributeInterface
290
    {
291
        foreach ($this->getAllAttributes() as $attribute) {
292
            if ($attribute->getAttributeName() == $attributeName) {
293
                return $attribute;
294
            }
295
        }
296
        return null;
297
    }
298
299
    public function getChildElementCollection(
300
        ModelElementTypeInterface $childElementType
301
    ): ChildElementCollectionInterface {
302
        foreach ($this->getChildElementCollections() as $childElementCollection) {
303
            if ($childElementType == $childElementCollection->getChildElementType($this->model)) {
304
                return $childElementCollection;
305
            }
306
        }
307
        return [];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array() returns the type array which is incompatible with the type-hinted return Xml\Type\Child\ChildElementCollectionInterface.
Loading history...
308
    }
309
}
310