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.
Passed
Push — master ( c6dd52...112aaa )
by SignpostMarv
04:35
created

AbstractDaftObject   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 374
Duplicated Lines 0 %

Test Coverage

Coverage 97.67%

Importance

Changes 0
Metric Value
dl 0
loc 374
ccs 126
cts 129
cp 0.9767
rs 8.2769
c 0
b 0
f 0
wmc 41

18 Methods

Rating   Name   Duplication   Size   Complexity  
B DoGetSet() 0 52 5
A DaftObjectProperties() 0 3 1
A DaftObjectJsonPropertyNames() 0 13 3
A ThrowIfNotDaftJson() 0 5 2
A HasPublicMethod() 0 18 3
A DaftObjectPublicGetters() 0 5 1
A __debugInfo() 0 15 4
A DaftObjectExportableProperties() 0 3 1
A DaftObjectPublicSetters() 0 5 1
B CheckTypeDefinesOwnIdProperties() 0 28 6
A __set() 0 7 1
A __unset() 0 3 1
B CachePublicGettersAndSetters() 0 38 6
A __get() 0 6 1
A __construct() 0 5 1
A DaftObjectNullableProperties() 0 3 1
A DaftObjectJsonProperties() 0 5 1
A DaftObjectMethodNameFromProperty() 0 5 2

How to fix   Complexity   

Complex Class

Complex classes like AbstractDaftObject 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 AbstractDaftObject, 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
use BadMethodCallException;
12
use ReflectionClass;
13
use ReflectionMethod;
14
use Throwable;
15
16
/**
17
* Base daft object.
18
*/
19
abstract class AbstractDaftObject implements DaftObject
20
{
21
    /**
22
    * List of properties that can be defined on an implementation.
23
    *
24
    * @var string[]
25
    */
26
    const PROPERTIES = [];
27
28
    /**
29
    * List of nullable properties that can be defined on an implementation.
30
    *
31
    * @var string[]
32
    */
33
    const NULLABLE_PROPERTIES = [];
34
35
    /**
36
    * List of exportable properties that can be defined on an implementation.
37
    *
38
    * @var string[]
39
    */
40
    const EXPORTABLE_PROPERTIES = [];
41
42
    /**
43
    * import/export definition for DaftJson.
44
    */
45
    const JSON_PROPERTIES = [];
46
47
    /**
48
    * @var string[][]
49
    */
50
    private static $publicGetters = [];
51
52
    /**
53
    * @var string[][]
54
    */
55
    private static $publicSetters = [];
56
57
    /**
58
    * Does some sanity checking.
59
    *
60
    * @see DefinesOwnIdPropertiesInterface
61
    * @see self::CheckTypeDefinesOwnIdProperties()
62
    */
63 188
    public function __construct()
64
    {
65 188
        self::CheckTypeDefinesOwnIdProperties(
66 188
            static::class,
67 188
            ($this instanceof DefinesOwnIdPropertiesInterface)
68
        );
69 186
    }
70
71
    /**
72
    * {@inheritdoc}
73
    */
74 41
    public function __get(string $property)
75
    {
76 41
        return $this->DoGetSet(
77 41
            $property,
78 41
            false,
79 41
            NotPublicGetterPropertyException::class
80
        );
81
    }
82
83
    /**
84
    * {@inheritdoc}
85
    */
86 79
    public function __set(string $property, $v)
87
    {
88 79
        return $this->DoGetSet(
89 79
            $property,
90 79
            true,
91 79
            NotPublicSetterPropertyException::class,
92 79
            $v
93
        );
94
    }
95
96
    /**
97
    * {@inheritdoc}
98
    *
99
    * @see static::NudgePropertyValue()
100
    */
101 20
    public function __unset(string $property) : void
102
    {
103 20
        $this->NudgePropertyValue($property, null);
104 18
    }
105
106
    /**
107
    * {@inheritdoc}
108
    */
109 31
    public function __debugInfo() : array
110
    {
111 31
        $out = [];
112 31
        $publicGetters = static::DaftObjectPublicGetters();
113 31
        foreach (static::DaftObjectExportableProperties() as $prop) {
114 30
            $expectedMethod = 'Get' . ucfirst($prop);
115
            if (
116 30
                $this->__isset($prop) &&
117 30
                in_array($prop, $publicGetters, true)
118
            ) {
119 30
                $out[$prop] = $this->$expectedMethod();
120
            }
121
        }
122
123 31
        return $out;
124
    }
125
126
    /**
127
    * List of properties that can be defined on an implementation.
128
    *
129
    * @return string[]
130
    */
131 135
    final public static function DaftObjectProperties() : array
132
    {
133 135
        return static::PROPERTIES;
134
    }
135
136
    /**
137
    * {@inheritdoc}
138
    */
139 53
    final public static function DaftObjectNullableProperties() : array
140
    {
141 53
        return static::NULLABLE_PROPERTIES;
142
    }
143
144
    /**
145
    * {@inheritdoc}
146
    */
147 65
    final public static function DaftObjectExportableProperties() : array
148
    {
149 65
        return static::EXPORTABLE_PROPERTIES;
150
    }
151
152
    /**
153
    * {@inheritdoc}
154
    */
155 108
    final public static function DaftObjectPublicGetters() : array
156
    {
157 108
        static::CachePublicGettersAndSetters();
158
159 108
        return self::$publicGetters[static::class];
160
    }
161
162
    /**
163
    * {@inheritdoc}
164
    */
165 79
    final public static function DaftObjectPublicSetters() : array
166
    {
167 79
        static::CachePublicGettersAndSetters();
168
169 79
        return self::$publicSetters[static::class];
170
    }
171
172
    /**
173
    * {@inheritdoc}
174
    */
175 34
    final public static function DaftObjectJsonProperties() : array
176
    {
177 34
        static::ThrowIfNotDaftJson();
178
179 18
        return static::JSON_PROPERTIES;
180
    }
181
182
    /**
183
    * {@inheritdoc}
184
    */
185 18
    final public static function DaftObjectJsonPropertyNames() : array
186
    {
187 18
        $out = [];
188
189 18
        foreach (static::DaftObjectJsonProperties() as $k => $prop) {
190 18
            if (is_string($k)) {
191 12
                $prop = $k;
192
            }
193
194 18
            $out[] = $prop;
195
        }
196
197 18
        return $out;
198
    }
199
200 82
    protected static function ThrowIfNotDaftJson() : void
201
    {
202 82
        if (false === is_a(static::class, DaftJson::class, true)) {
203 64
            throw new DaftObjectNotDaftJsonBadMethodCallException(
204 64
                static::class
205
            );
206
        }
207 18
    }
208
209 13
    final protected static function HasPublicMethod(
210
        ReflectionClass $classReflection,
211
        string $method
212
    ) : bool {
213
        if (
214 13
            $classReflection->hasMethod($method)
215
        ) {
216 13
            $methodReflection = new ReflectionMethod(
217 13
                static::class,
218 13
                $method
219
            );
220
221
            return
222 13
                $methodReflection->isPublic() &&
223 13
                false === $methodReflection->isStatic();
224
        }
225
226 4
        return false;
227
    }
228
229 108
    final protected static function CachePublicGettersAndSetters() : void
230
    {
231 108
        if (false === isset(self::$publicGetters[static::class])) {
232 13
            self::$publicGetters[static::class] = [];
233 13
            self::$publicSetters[static::class] = [];
234
235
            if (
236 13
                is_a(
237 13
                    static::class,
238 13
                    DefinesOwnIdPropertiesInterface::class,
239 13
                    true
240
                )
241
            ) {
242 7
                self::$publicGetters[static::class][] = 'id';
243
            }
244
245 13
            $classReflection = new ReflectionClass(static::class);
246
247 13
            foreach (static::DaftObjectProperties() as $property) {
248
                if (
249 13
                    static::HasPublicMethod(
250 13
                        $classReflection,
251 13
                        static::DaftObjectMethodNameFromProperty($property)
252
                    )
253
                ) {
254 11
                    self::$publicGetters[static::class][] = $property;
255
                }
256
257
                if (
258 13
                    static::HasPublicMethod(
259 13
                        $classReflection,
260 13
                        static::DaftObjectMethodNameFromProperty(
261 13
                            $property,
262 13
                            true
263
                        )
264
                    )
265
                ) {
266 13
                    self::$publicSetters[static::class][] = $property;
267
                }
268
            }
269
        }
270 108
    }
271
272
    /**
273
    * Nudge the state of a given property, marking it as dirty.
274
    *
275
    * @param string $property property being nudged
276
    * @param mixed $value value to nudge property with
277
    *
278
    * @throws UndefinedPropertyException if $property is not in static::DaftObjectProperties()
279
    * @throws PropertyNotNullableException if $property is not in static::DaftObjectNullableProperties()
280
    * @throws PropertyNotRewriteableException if class is write-once read-many and $property was already changed
281
    */
282
    abstract protected function NudgePropertyValue(
283
        string $property,
284
        $value
285
    ) : void;
286
287
    /**
288
    * Checks if a type correctly defines it's own id.
289
    *
290
    * @throws ClassDoesNotImplementClassException if $class is not an implementation of DefinesOwnIdPropertiesInterface
291
    * @throws ClassMethodReturnHasZeroArrayCountException if $class::DaftObjectIdProperties() does not contain at least one property
292
    * @throws ClassMethodReturnIsNotArrayOfStringsException if $class::DaftObjectIdProperties() is not string[]
293
    * @throws UndefinedPropertyException if an id property is not in $class::DaftObjectIdProperties()
294
    */
295 188
    final protected static function CheckTypeDefinesOwnIdProperties(
296
        string $class,
297
        bool $throwIfNotImplementation = false
298
    ) : void {
299 188
        $interfaceCheck = $class;
300
301 188
        if (is_a($interfaceCheck, DefinesOwnIdPropertiesInterface::class, true)) {
302 116
            $properties = $class::DaftObjectIdProperties();
303
304 116
            if (count($properties) < 1) {
305 1
                throw new ClassMethodReturnHasZeroArrayCountException(
306 1
                    $class,
307 1
                    'DaftObjectIdProperties'
308
                );
309
            }
310
311 115
            foreach ($properties as $property) {
312 115
                if (false === is_string($property)) {
313 1
                    throw new ClassMethodReturnIsNotArrayOfStringsException(
314 1
                        $class,
315 115
                        'DaftObjectIdProperties'
316
                    );
317
                }
318
            }
319 75
        } elseif ($throwIfNotImplementation) {
320 1
            throw new ClassDoesNotImplementClassException(
321 1
                $class,
322 1
                DefinesOwnIdPropertiesInterface::class
323
            );
324
        }
325 186
    }
326
327 108
    protected static function DaftObjectMethodNameFromProperty(
328
        string $property,
329
        bool $SetNotGet = false
330
    ) : string {
331 108
        return ($SetNotGet ? 'Set' : 'Get') . ucfirst($property);
332
    }
333
334
    /**
335
    * @param mixed $v
336
    *
337
    * @return mixed
338
    *
339
    * @psalm-suppress InvalidThrow
340
    */
341 108
    protected function DoGetSet(
342
        string $property,
343
        bool $SetNotGet,
344
        string $notPublic,
345
        $v = null
346
    ) {
347 108
        $expectedMethod = static::DaftObjectMethodNameFromProperty(
348 108
            $property,
349 108
            $SetNotGet
350
        );
351 108
        $thingers = static::DaftObjectPublicGetters();
352
353 108
        if ($SetNotGet) {
354 79
            $thingers = static::DaftObjectPublicSetters();
355
        }
356
357
        if (
358
            false === (
359 108
                in_array(
360 108
                    $property,
361 108
                    $thingers,
362 108
                    true
363
                )
364
            )
365
        ) {
366
            if (
367 5
                false === in_array(
368 5
                    $property,
369 5
                    static::DaftObjectProperties(),
370 5
                    true
371
                )
372
            ) {
373 3
                throw new UndefinedPropertyException(static::class, $property);
374 2
            } elseif ( ! is_a($notPublic, Throwable::class, true)) {
375
                throw new BadMethodCallException(
376
                    'Argument 3 passed to ' .
377
                    __METHOD__ .
378
                    ' must be an implementation of ' .
379
                    Throwable::class .
380
                    ', "' .
381
                    $notPublic .
382
                    '" given.'
383
                );
384
            }
385
386 2
            throw new $notPublic(
387 2
                static::class,
388 2
                $property
389
            );
390
        }
391
392 103
        return $this->$expectedMethod($v);
393
    }
394
}
395