Passed
Pull Request — master (#226)
by Christopher
06:35
created

AssociationStubBase   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 45
eloc 73
c 7
b 0
f 0
dl 0
loc 310
rs 8.8

23 Methods

Rating   Name   Duplication   Size   Complexity  
A compare() 0 18 4
A addAssociation() 0 2 1
B isOk() 0 32 11
A setTargType() 0 3 1
A getKeyFieldName() 0 3 1
A getEntity() 0 3 1
A getThroughFieldChain() 0 3 1
A getAssocations() 0 3 1
A getRelationName() 0 3 1
A setMultiplicity() 0 3 1
A setBaseType() 0 3 2
A setThroughFieldChain() 0 3 1
A setRelationName() 0 3 2
A getTargType() 0 3 1
A getForeignFieldName() 0 3 1
A setForeignFieldName() 0 3 1
A setKeyFieldName() 0 3 2
A getKeyField() 0 4 1
A getBaseType() 0 3 1
A isCompatible() 0 13 4
A getMultiplicity() 0 3 1
A setEntity() 0 3 1
A checkStringInput() 0 6 4

How to fix   Complexity   

Complex Class

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

1
<?php declare(strict_types=1);
2
3
namespace AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\Associations;
4
5
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\EntityField;
6
use AlgoWeb\PODataLaravel\Models\ObjectMap\Entities\EntityGubbins;
7
8
abstract class AssociationStubBase
9
{
10
    /**
11
     * @var AssociationStubRelationType
12
     */
13
    protected $multiplicity;
14
15
    /**
16
     * Foreign key field of this end of relation.
17
     *
18
     * @var string|null
19
     */
20
    protected $keyFieldName;
21
22
    /**
23
     * A list of fields to Traverse between Keyfield and foreignField.
24
     *
25
     * @var string[]
26
     */
27
    protected $throughFieldChain;
28
29
    /**
30
     * Foreign key field of other end of relation.
31
     *
32
     * @var string|null
33
     */
34
    protected $foreignFieldName;
35
36
    /**
37
     * @var string|null
38
     */
39
    protected $relationName;
40
41
    /**
42
     * Target type this relation points to, if known.  Is null for known-side polymorphic relations.
43
     *
44
     * @var string|null
45
     */
46
    protected $targType;
47
48
    /**
49
     * Base type this relation is attached to.
50
     *
51
     * @var string|null
52
     */
53
    protected $baseType;
54
55
    /**
56
     * Any assocations this stub is a member of.
57
     *
58
     * @var Association[]
59
     */
60
    protected $associations = [];
61
62
    /**
63
     * @var EntityGubbins the entity this stub lives on.
64
     */
65
    protected $entity;
66
67
    /**
68
     * Sets the entity owning this AssocationStub
69
     *
70
     * @param EntityGubbins $entity
71
     */
72
    public function setEntity(EntityGubbins $entity): void
73
    {
74
        $this->entity = $entity;
75
    }
76
77
    /**
78
     * Gets the entity owning this AssocationStub
79
     *
80
     * @return EntityGubbins
81
     */
82
    public function getEntity(): EntityGubbins
83
    {
84
        return $this->entity;
85
    }
86
    /**
87
     * Adds this stub as a member of an assocation
88
     *
89
     * @param Association $newAssocation the new assocation to be a member of
90
     */
91
    public function addAssociation(Association $newAssocation): void {
92
        $this->associations[spl_object_hash($newAssocation)] = $newAssocation;
93
    }
94
95
    /**
96
     * Gets all assocations assigned to this stub.
97
     *
98
     * @return Association[] All assocations this stub is a member of
99
     */
100
    public function getAssocations(): array
101
    {
102
       return array_values($this->associations);
103
    }
104
105
    /**
106
     * @return string
107
     */
108
    public function getRelationName()
109
    {
110
        return $this->relationName;
111
    }
112
113
    /**
114
     * @param string $relationName
115
     */
116
    public function setRelationName($relationName)
117
    {
118
        $this->relationName = $this->checkStringInput($relationName) ? $relationName : $this->relationName;
119
    }
120
121
    /**
122
     * @return AssociationStubRelationType
123
     */
124
    public function getMultiplicity()
125
    {
126
        return $this->multiplicity;
127
    }
128
129
    /**
130
     * @param AssociationStubRelationType $multiplicity
131
     */
132
    public function setMultiplicity(AssociationStubRelationType $multiplicity)
133
    {
134
        $this->multiplicity = $multiplicity;
135
    }
136
137
    /**
138
     * @return string
139
     */
140
    public function getKeyFieldName(): string
141
    {
142
        return $this->keyFieldName;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->keyFieldName could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
143
    }
144
145
    public function getKeyField() : ?EntityField
146
    {
147
148
        return $this->entity->getFields()[$this->getKeyFieldName()];
149
    }
150
151
    /**
152
     * @param string $keyFieldName
153
     */
154
    public function setKeyFieldName($keyFieldName)
155
    {
156
        $this->keyFieldName = $this->checkStringInput($keyFieldName) ? $keyFieldName : $this->keyFieldName;
157
    }
158
159
    public function isCompatible(AssociationStubBase $otherStub)
160
    {
161
        if ($this->morphicType() != $otherStub->morphicType()) {
162
            return false;
163
        }
164
165
        if (!$this->isOk()) {
166
            return false;
167
        }
168
        if (!$otherStub->isOk()) {
169
            return false;
170
        }
171
        return count($this->getThroughFieldChain()) === count($otherStub->getThroughFieldChain());
172
    }
173
174
    /**
175
     * Is this AssociationStub sane?
176
     */
177
    public function isOk()
178
    {
179
        if (null === $this->multiplicity) {
180
            return false;
181
        }
182
        if (null === $this->relationName) {
183
            return false;
184
        }
185
        if (null === $this->keyFieldName) {
186
            return false;
187
        }
188
        if (null === $this->baseType) {
189
            return false;
190
        }
191
        $targType = $this->targType;
192
        if ($this instanceof AssociationStubMonomorphic && null === $targType) {
193
            return false;
194
        }
195
        $foreignField = $this->foreignFieldName;
196
        if (null !== $targType) {
197
            if (!$this->checkStringInput($targType)) {
198
                return false;
199
            }
200
            if (!$this->checkStringInput($foreignField)) {
201
                return false;
202
            }
203
        }
204
205
        if(null === $this->throughFieldChain){
206
            return false;
207
        }
208
        return (null === $targType) === (null === $foreignField);
209
    }
210
211
    /**
212
     * @return string
213
     */
214
    public function getTargType()
215
    {
216
        return $this->targType;
217
    }
218
219
    /**
220
     * @param string $targType
221
     */
222
    public function setTargType($targType)
223
    {
224
        $this->targType = $targType;
225
    }
226
227
    /**
228
     * @return string
229
     */
230
    public function getBaseType()
231
    {
232
        return $this->baseType;
233
    }
234
235
    /**
236
     * @param string $baseType
237
     */
238
    public function setBaseType($baseType)
239
    {
240
        $this->baseType = $this->checkStringInput($baseType) ? $baseType : $this->baseType;
241
    }
242
243
    /**
244
     * @return string
245
     */
246
    public function getForeignFieldName()
247
    {
248
        return $this->foreignFieldName;
249
    }
250
251
    /**
252
     * @param string $foreignFieldName
253
     */
254
    public function setForeignFieldName($foreignFieldName)
255
    {
256
        $this->foreignFieldName = $foreignFieldName;
257
    }
258
259
    /**
260
     * @return string[]|null
261
     */
262
    public function getThroughFieldChain(): array
263
    {
264
        return $this->throughFieldChain;
265
    }
266
267
    /**
268
     * @param string[]|null $keyChain
269
     */
270
    public function setThroughFieldChain(?array $keyChain)
271
    {
272
        $this->throughFieldChain = $keyChain;
273
    }
274
    /**
275
     * Supply a canonical sort ordering to determine order in associations.
276
     *
277
     * @param AssociationStubBase $other
278
     *
279
     * @return int
280
     */
281
    public function compare(AssociationStubBase $other)
282
    {
283
        $thisClass  = get_class($this);
284
        $otherClass = get_class($other);
285
        $classComp  = strcmp($thisClass, $otherClass);
286
        if (0 !== $classComp) {
287
            return $classComp / abs($classComp);
288
        }
289
        $thisBase  = $this->getBaseType() ?? '';
290
        $otherBase = $other->getBaseType() ?? '';
291
        $baseComp  = strcmp($thisBase, $otherBase);
292
        if (0 !== $baseComp) {
293
            return $baseComp / abs($baseComp);
294
        }
295
        $thisMethod  = $this->getRelationName() ?? '';
296
        $otherMethod = $other->getRelationName() ?? '';
297
        $methodComp  = strcmp($thisMethod, $otherMethod);
298
        return 0 === $methodComp ? 0 : $methodComp / abs($methodComp);
299
    }
300
301
    /**
302
     * Return what type of stub this is - polymorphic, monomorphic, or something else.
303
     *
304
     * @return string
305
     */
306
    abstract public function morphicType();
307
308
    /**
309
     * @param $input
310
     * @return bool
311
     */
312
    private function checkStringInput($input)
313
    {
314
        if (null === $input || !is_string($input) || empty($input)) {
315
            return false;
316
        }
317
        return true;
318
    }
319
}
320