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 ( 5acf68...90f6c1 )
by SignpostMarv
01:42
created

AbstractArrayBackedDaftObject   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 333
Duplicated Lines 1.5 %

Test Coverage

Coverage 86.33%

Importance

Changes 0
Metric Value
wmc 56
dl 5
loc 333
ccs 120
cts 139
cp 0.8633
rs 5.5555
c 0
b 0
f 0

12 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
C DaftObjectFromJsonArray() 0 68 14
B jsonSerialize() 0 25 4
A DaftObjectFromJsonString() 0 5 1
A ThrowIfNotDaftJson() 5 5 2
C DaftObjectFromJsonType() 0 60 9
C NudgePropertyValue() 0 35 11
A RetrievePropertyValueFromData() 0 14 4

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 22
    final public static function DaftObjectFromJsonArray(
132
        array $array,
133
        bool $writeAll = false
134
    ) : DaftJson {
135 22
        static::ThrowIfNotDaftJson();
136
137 6
        $in = [];
138
139 6
        $props = static::DaftObjectJsonProperties();
140 6
        $jsonDef = static::DaftObjectJsonProperties();
141 6
        $nullableProps = static::DaftObjectNullableProperties();
142
143 6
        $jsonProps = [];
144
145 6
        foreach ($jsonDef as $k => $v) {
146 6
            if (is_string($k)) {
147 3
                $jsonProps[] = $k;
148
            } else {
149 6
                $jsonProps[] = $v;
150
            }
151
        }
152
153 6
        foreach ($jsonProps as $prop) {
154
            if (
155
                (
156 6
                    false === isset($array[$prop]) ||
157 6
                    is_null($array[$prop])
158
                ) &&
159 2
                false === in_array($prop, $nullableProps, true)
160
            ) {
161
                throw new PropertyNotNullableException(static::class, $prop);
162
            }
163
        }
164
165 6
        foreach (array_keys($array) as $prop) {
166
            if (
167 6
                false === in_array($prop, $props, true) &&
168 3
                false === isset($jsonDef[$prop])
169
            ) {
170
                throw new UndefinedPropertyException(static::class, $prop);
171
            } elseif (
172 6
                false === in_array($prop, $jsonProps, true)
173
            ) {
174
                throw new PropertyNotJsonDecodableException(
175
                    static::class,
176
                    $prop
177
                );
178 6
            } elseif (is_null($array[$prop])) {
179
                continue;
180 6
            } elseif (isset($jsonDef[$prop])) {
181 3
                $in[$prop] = static::DaftObjectFromJsonType(
182 3
                    $prop,
183 3
                    $jsonDef[$prop],
184 3
                    $array[$prop],
185 3
                    $writeAll
186
                );
187
            } else {
188 6
                $in[$prop] = $array[$prop];
189
            }
190
        }
191
192 6
        $out = new static($in, $writeAll);
193
194 6
        if ( ! ($out instanceof DaftJson)) { // here to trick phpstan
195
            exit;
196
        }
197
198 6
        return $out;
199
    }
200
201 22
    public static function DaftObjectFromJsonString(string $string) : DaftJson
202
    {
203 22
        static::ThrowIfNotDaftJson();
204
205 6
        return static::DaftObjectFromJsonArray(json_decode($string, true));
206
    }
207
208
    /**
209
    * @param mixed $propVal
210
    *
211
    * @return DaftJson|DaftJson[]
212
    */
213 3
    protected static function DaftObjectFromJsonType(
214
        string $prop,
215
        string $jsonType,
216
        $propVal,
217
        bool $writeAll
218
    ) {
219 3
        $isArray = false;
220 3
        if ('[]' === mb_substr($jsonType, -2)) {
221 1
            $isArray = true;
222 1
            $jsonType = mb_substr($jsonType, 0, -2);
223
        }
224
225 3
        if ($isArray && false === is_array($propVal)) {
226
            throw new PropertyNotJsonDecodableShouldBeArrayException(
227
                static::class,
228
                $prop
229
            );
230 3
        } elseif (false === is_a($jsonType, DaftJson::class, true)) {
231
            throw new ClassDoesNotImplementClassException(
232
                $jsonType,
233
                DaftJson::class
234
            );
235
        }
236
237
        /**
238
        * @var DaftJson $jsonType
239
        */
240 3
        $jsonType = $jsonType;
241
242 3
        if ($isArray) {
243
            /**
244
            * @var DaftJson[] $out
245
            */
246 1
            $out = [];
247
248 1
            foreach ($propVal as $i => $val) {
249 1
                if (is_array($val)) {
250 1
                    $out[] = $jsonType::DaftObjectFromJsonArray(
251 1
                        $val,
252 1
                        $writeAll
253
                    );
254
                } else {
255
                    throw new PropertyNotJsonDecodableShouldBeArrayException(
256
                        (string) $jsonType,
257
                        ($prop . '[' . $i . ']')
258
                    );
259
                }
260
            }
261
262 1
            return $out;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $out returns the type SignpostMarv\DaftObject\...v\DaftObject\DaftJson[] which is incompatible with the documented return type SignpostMarv\DaftObject\...arv\DaftObject\DaftJson.
Loading history...
263 2
        } elseif (is_array($propVal)) {
264 2
            return $jsonType::DaftObjectFromJsonArray(
0 ignored issues
show
Bug Best Practice introduced by
The expression return $jsonType::DaftOb...ay($propVal, $writeAll) returns the type SignpostMarv\DaftObject\DaftJson which is incompatible with the documented return type SignpostMarv\DaftObject\...arv\DaftObject\DaftJson.
Loading history...
265 2
                $propVal,
266 2
                $writeAll
267
            );
268
        }
269
270
        throw new PropertyNotJsonDecodableShouldBeArrayException(
271
            (string) $jsonType,
272
            $prop
273
        );
274
    }
275
276
    /**
277
    * Retrieve a property from data.
278
    *
279
    * @param string $property the property being retrieved
280
    *
281
    * @throws PropertyNotNullableException if value is not set and $property is not listed as nullabe
282
    *
283
    * @return mixed the property value
284
    */
285 44
    protected function RetrievePropertyValueFromData(string $property)
286
    {
287
        if (
288 44
            false === array_key_exists($property, $this->data) &&
289 5
            false === in_array($property, static::NULLABLE_PROPERTIES, true)
290
        ) {
291 1
            throw new PropertyNotNullableException(static::class, $property);
292
        } elseif (
293 43
            in_array($property, static::NULLABLE_PROPERTIES, true)
294
        ) {
295 33
            return $this->data[$property] ?? null;
296
        }
297
298 43
        return $this->data[$property];
299
    }
300
301
    /**
302
    * {@inheritdoc}
303
    */
304 134
    protected function NudgePropertyValue(string $property, $value) : void
305
    {
306 134
        if (true !== in_array($property, static::PROPERTIES, true)) {
307 1
            throw new UndefinedPropertyException(static::class, $property);
308
        } elseif (
309 133
            true === is_null($value) &&
310 88
            true !== in_array($property, static::NULLABLE_PROPERTIES, true)
311
        ) {
312 58
            throw new PropertyNotNullableException(static::class, $property);
313
        } elseif (
314 75
            $this instanceof DaftObjectWorm &&
315
            (
316 50
                $this->HasPropertyChanged($property) ||
317
                (
318 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...
319 2
                    true === $this->wormProperties[$property]
320
                )
321
            )
322
        ) {
323 50
            throw new PropertyNotRewriteableException(
324 50
                static::class,
325 50
                $property
326
            );
327
        }
328
329
        $isChanged = (
330 75
            false === array_key_exists($property, $this->data) ||
331 75
            $this->data[$property] !== $value
332
        );
333
334 75
        $this->data[$property] = $value;
335
336 75
        if ($isChanged && true !== isset($this->changedProperties[$property])) {
337 75
            $this->changedProperties[$property] = true;
338 75
            $this->wormProperties[$property] = true;
339
        }
340 75
    }
341
342 54 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...
343
    {
344 54
        if (false === is_a(static::class, DaftJson::class, true)) {
345 48
            throw new DaftObjectNotDaftJsonBadMethodCallException(
346 48
                static::class
347
            );
348
        }
349 6
    }
350
}
351