GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 663d76...5e5df8 )
by SignpostMarv
01:40
created

AbstractArrayBackedDaftObject   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 366
Duplicated Lines 1.37 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 56
dl 5
loc 366
ccs 150
cts 150
cp 1
rs 5.5555
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A MakePropertiesUnchanged() 0 4 2
A __isset() 0 5 2
A ChangedProperties() 0 8 1
A __construct() 0 11 4
A HasPropertyChanged() 0 5 2
B jsonSerialize() 0 25 4
A ThrowIfNotDaftJson() 5 5 2
A DaftObjectFromJsonType() 0 8 1
B DaftObjectFromJsonArray() 0 39 4
C NudgePropertyValue() 0 35 11
A DaftObjectFromJsonString() 0 5 1
C ThrowIfJsonDefNotValid() 0 57 12
A ThrowIfNotJsonType() 0 6 2
B DaftObjectFromJsonTypeArray() 0 25 3
A RetrievePropertyValueFromData() 0 14 4
A ArrayToJsonType() 0 13 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
/**
3
* Base daft objects.
4
*
5
* @author SignpostMarv
6
*/
7
declare(strict_types=1);
8
9
namespace SignpostMarv\DaftObject;
10
11
/**
12
* Array-backed daft objects.
13
*/
14
abstract class AbstractArrayBackedDaftObject extends AbstractDaftObject implements DaftObjectCreatedByArray
15
{
16
    /**
17
    * data for this instance.
18
    *
19
    * @var array
20
    */
21
    private $data = [];
22
23
    /**
24
    * List of changed properties.
25
    *
26
    * @var bool[]
27
    */
28
    private $changedProperties = [];
29
30
    /**
31
    * List of changed properties, for write-once read-many.
32
    *
33
    * @var bool[]
34
    */
35
    private $wormProperties = [];
36
37
    /**
38
    * {@inheritdoc}
39
    */
40 189
    public function __construct(array $data = [], bool $writeAll = false)
41
    {
42 189
        parent::__construct();
43
44 187
        if (true === $writeAll) {
45 60
            foreach ($data as $k => $v) {
46 60
                $this->__set($k, $v);
47
            }
48
        } else {
49 129
            foreach ($data as $k => $v) {
50 68
                $this->data[$k] = $v;
51
            }
52
        }
53 185
    }
54
55
    /**
56
    * {@inheritdoc}
57
    */
58 33
    public function __isset(string $property) : bool
59
    {
60
        return
61 33
            in_array($property, static::PROPERTIES, true) &&
62 33
            isset($this->data, $this->data[$property]);
63
    }
64
65
    /**
66
    * {@inheritdoc}
67
    */
68 29
    public function ChangedProperties() : array
69
    {
70
        /**
71
        * @var string[] $out
72
        */
73 29
        $out = array_keys($this->changedProperties);
74
75 29
        return $out;
76
    }
77
78
    /**
79
    * {@inheritdoc}
80
    */
81 33
    public function MakePropertiesUnchanged(string ...$properties) : void
82
    {
83 33
        foreach ($properties as $property) {
84 33
            unset($this->changedProperties[$property]);
85
        }
86 33
    }
87
88
    /**
89
    * {@inheritdoc}
90
    */
91 82
    public function HasPropertyChanged(string $property) : bool
92
    {
93
        return
94 82
            isset($this->changedProperties[$property]) &&
95 82
            true === $this->changedProperties[$property];
96
    }
97
98
    /**
99
    * {@inheritdoc}
100
    */
101 22
    public function jsonSerialize() : array
102
    {
103 22
        static::ThrowIfNotDaftJson();
104
105 6
        $out = [];
106
107 6
        foreach (static::DaftObjectJsonProperties() as $k => $v) {
108 6
            $property = $v;
109 6
            if (is_string($k)) {
110 3
                $property = $k;
111
            }
112
113 6
            $val = $this->DoGetSet(
114 6
                $property,
115 6
                'Get' . ucfirst($property),
116 6
                PropertyNotReadableException::class,
117 6
                NotPublicGetterPropertyException::class
118
            );
119
120 6
            if (false === is_null($val)) {
121 6
                $out[$property] = $val;
122
            }
123
        }
124
125 6
        return $out;
126
    }
127
128
    /**
129
    * {@inheritdoc}
130
    */
131 28
    final public static function DaftObjectFromJsonArray(
132
        array $array,
133
        bool $writeAll = false
134
    ) : DaftJson {
135 28
        static::ThrowIfNotDaftJson();
136 12
        $array = static::ThrowIfJsonDefNotValid($array);
137 8
        $in = [];
138
139 8
        $jsonDef = static::DaftObjectJsonProperties();
140
141 8
        foreach (array_keys($array) as $prop) {
142 8
            if (isset($jsonDef[$prop])) {
143 5
                $jsonType = $jsonDef[$prop];
144
145 5
                if ('[]' === mb_substr($jsonType, -2)) {
146 3
                    $in[$prop] = static::DaftObjectFromJsonTypeArray(
147 3
                        mb_substr($jsonType, 0, -2),
148 3
                        $prop,
149 3
                        $array[$prop],
150 3
                        $writeAll
151
                    );
152
                } else {
153 2
                    $in[$prop] = static::DaftObjectFromJsonType(
154 2
                        $jsonType,
155 2
                        $array[$prop],
156 2
                        $writeAll
157
                    );
158
                }
159
            } else {
160 6
                $in[$prop] = $array[$prop];
161
            }
162
        }
163
164
        /**
165
        * @var DaftJson $out
166
        */
167 6
        $out = new static($in, $writeAll);
168
169 6
        return $out;
170
    }
171
172 22
    public static function DaftObjectFromJsonString(string $string) : DaftJson
173
    {
174 22
        static::ThrowIfNotDaftJson();
175
176 6
        return static::DaftObjectFromJsonArray(json_decode($string, true));
177
    }
178
179
    /**
180
    * @param mixed $propVal
181
    *
182
    * @return DaftJson
183
    */
184 2
    protected static function DaftObjectFromJsonType(
185
        string $jsonType,
186
        array $propVal,
187
        bool $writeAll
188
    ) {
189 2
        static::ThrowIfNotJsonType($jsonType);
190
191 2
        return static::ArrayToJsonType($jsonType, $propVal, $writeAll);
192
    }
193
194
    /**
195
    * @return DaftJson[]
196
    */
197 3
    protected static function DaftObjectFromJsonTypeArray(
198
        string $jsonType,
199
        string $prop,
200
        array $propVal,
201
        bool $writeAll
202
    ) : array {
203 3
        static::ThrowIfNotJsonType($jsonType);
204
205 2
        $out = [];
206
207 2
        foreach ($propVal as $val) {
208 2
            if (false === is_array($val)) {
209 1
                throw new PropertyNotJsonDecodableShouldBeArrayException(
210 1
                    $jsonType,
211 1
                    $prop
212
                );
213
            }
214 1
            $out[] = static::ArrayToJsonType(
215 1
                $jsonType,
216 1
                $val,
217 1
                $writeAll
218
            );
219
        }
220
221 1
        return $out;
222
    }
223
224
    /**
225
    * Retrieve a property from data.
226
    *
227
    * @param string $property the property being retrieved
228
    *
229
    * @throws PropertyNotNullableException if value is not set and $property is not listed as nullabe
230
    *
231
    * @return mixed the property value
232
    */
233 44
    protected function RetrievePropertyValueFromData(string $property)
234
    {
235
        if (
236 44
            false === array_key_exists($property, $this->data) &&
237 5
            false === in_array($property, static::NULLABLE_PROPERTIES, true)
238
        ) {
239 1
            throw new PropertyNotNullableException(static::class, $property);
240
        } elseif (
241 43
            in_array($property, static::NULLABLE_PROPERTIES, true)
242
        ) {
243 33
            return $this->data[$property] ?? null;
244
        }
245
246 43
        return $this->data[$property];
247
    }
248
249
    /**
250
    * {@inheritdoc}
251
    */
252 134
    protected function NudgePropertyValue(string $property, $value) : void
253
    {
254 134
        if (true !== in_array($property, static::PROPERTIES, true)) {
255 1
            throw new UndefinedPropertyException(static::class, $property);
256
        } elseif (
257 133
            true === is_null($value) &&
258 88
            true !== in_array($property, static::NULLABLE_PROPERTIES, true)
259
        ) {
260 58
            throw new PropertyNotNullableException(static::class, $property);
261
        } elseif (
262 75
            $this instanceof DaftObjectWorm &&
263
            (
264 50
                $this->HasPropertyChanged($property) ||
265
                (
266 50
                    isset($this->wormProperties[$property]) &&
0 ignored issues
show
Bug Best Practice introduced by
The property wormProperties does not exist on SignpostMarv\DaftObject\DaftObjectWorm. Since you implemented __get, consider adding a @property annotation.
Loading history...
267 2
                    true === $this->wormProperties[$property]
268
                )
269
            )
270
        ) {
271 50
            throw new PropertyNotRewriteableException(
272 50
                static::class,
273 50
                $property
274
            );
275
        }
276
277
        $isChanged = (
278 75
            false === array_key_exists($property, $this->data) ||
279 75
            $this->data[$property] !== $value
280
        );
281
282 75
        $this->data[$property] = $value;
283
284 75
        if ($isChanged && true !== isset($this->changedProperties[$property])) {
285 75
            $this->changedProperties[$property] = true;
286 75
            $this->wormProperties[$property] = true;
287
        }
288 75
    }
289
290 12
    private static function ThrowIfJsonDefNotValid(array $array) : array
291
    {
292 12
        $jsonProps = [];
293
294 12
        $jsonDef = static::DaftObjectJsonProperties();
295 12
        $nullableProps = static::DaftObjectNullableProperties();
296
297 12
        foreach ($jsonDef as $k => $v) {
298 12
            $prop = $v;
299 12
            if (is_string($k)) {
300 9
                $prop = $k;
301
            }
302
            if (
303
                (
304 12
                    false === isset($array[$prop]) ||
305 11
                    is_null($array[$prop])
306
                ) &&
307 3
                false === in_array($prop, $nullableProps, true)
308
            ) {
309 1
                throw new PropertyNotNullableException(static::class, $prop);
310
            }
311
312 11
            $jsonProps[] = $prop;
313
        }
314
315 11
        $out = [];
316
317 11
        foreach ($array as $prop => $propVal) {
318
            if (
319 11
                false === in_array($prop, $jsonProps, true)
320
            ) {
321 1
                throw new PropertyNotJsonDecodableException(
322 1
                    static::class,
323 1
                    $prop
324
                );
325 11
            } elseif (false === is_null($propVal)) {
326 11
                if (isset($jsonDef[$prop])) {
327 8
                    $jsonType = $jsonDef[$prop];
328
329 8
                    if (false === is_array($propVal)) {
330 2
                        if ('[]' === mb_substr($jsonType, -2)) {
331 1
                            throw new PropertyNotJsonDecodableShouldBeArrayException(
332 1
                                static::class,
333 1
                                $prop
334
                            );
335
                        }
336 1
                        throw new PropertyNotJsonDecodableShouldBeArrayException(
337 1
                            $jsonType,
338 1
                            $prop
339
                        );
340
                    }
341
                }
342 9
                $out[$prop] = $propVal;
343
            }
344
        }
345
346 8
        return $out;
347
    }
348
349 5
    private static function ThrowIfNotJsonType(string $jsonType) : void
350
    {
351 5
        if (false === is_a($jsonType, DaftJson::class, true)) {
352 1
            throw new ClassDoesNotImplementClassException(
353 1
                $jsonType,
354 1
                DaftJson::class
355
            );
356
        }
357 4
    }
358
359 3
    private static function ArrayToJsonType(
360
        string $jsonType,
361
        array $propVal,
362
        bool $writeAll
363
    ) : DaftJson {
364
        /**
365
        * @var DaftJson $jsonType
366
        */
367 3
        $jsonType = $jsonType;
368
369 3
        return $jsonType::DaftObjectFromJsonArray(
370 3
            $propVal,
371 3
            $writeAll
372
        );
373
    }
374
375 60 View Code Duplication
    private static function ThrowIfNotDaftJson() : void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
376
    {
377 60
        if (false === is_a(static::class, DaftJson::class, true)) {
378 48
            throw new DaftObjectNotDaftJsonBadMethodCallException(
379 48
                static::class
380
            );
381
        }
382 12
    }
383
}
384