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 ( 3386dd...e3c8c6 )
by SignpostMarv
02:46
created

AbstractDaftObject   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 279
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 279
ccs 100
cts 100
cp 1
rs 8.295
c 0
b 0
f 0
wmc 42

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A __set() 0 3 1
A __unset() 0 3 1
A __get() 0 3 1
A DaftObjectProperties() 0 3 1
A DaftObjectJsonPropertyNames() 0 13 3
A ThrowIfNotDaftJson() 0 4 2
A HasPublicMethod() 0 15 3
A DaftObjectPublicGetters() 0 5 1
A __debugInfo() 0 12 4
A DaftObjectExportableProperties() 0 3 1
A DaftObjectPublicSetters() 0 5 1
A DaftObjectNullableProperties() 0 3 1
A DaftObjectJsonProperties() 0 5 1
B CheckTypeDefinesOwnIdProperties() 0 24 5
A DaftObjectMethodNameFromProperty() 0 5 2
A DoGetSet() 0 7 2
A CachePublicGettersAndSettersProperties() 0 12 4
A MaybeThrowOnDoGetSet() 0 10 4
A CachePublicGettersAndSetters() 0 11 3

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 ReflectionClass;
12
use ReflectionMethod;
13
14
/**
15
* Base daft object.
16
*/
17
abstract class AbstractDaftObject implements DaftObject
18
{
19
    /**
20
    * List of properties that can be defined on an implementation.
21
    *
22
    * @var array<int, string>
23
    */
24
    const PROPERTIES = [];
25
26
    /**
27
    * List of nullable properties that can be defined on an implementation.
28
    *
29
    * @var array<int, string>
30
    */
31
    const NULLABLE_PROPERTIES = [];
32
33
    /**
34
    * List of exportable properties that can be defined on an implementation.
35
    *
36
    * @var array<int, string>
37
    */
38
    const EXPORTABLE_PROPERTIES = [];
39
40
    /**
41
    * import/export definition for DaftJson.
42
    *
43
    * @var array<int, string>
44
    */
45
    const JSON_PROPERTIES = [];
46
47
    /**
48
    * @var array<string, array<int, string>>
49
    */
50
    private static $publicGetters = [];
51
52
    /**
53
    * @var array<string, array<int, string>>
54
    */
55
    private static $publicSetters = [];
56
57
    /**
58
    * Does some sanity checking.
59
    *
60
    * @see DefinesOwnIdPropertiesInterface
61
    * @see self::CheckTypeDefinesOwnIdProperties()
62
    */
63 376
    public function __construct()
64
    {
65 376
        self::CheckTypeDefinesOwnIdProperties(
66 376
            static::class,
67 376
            ($this instanceof DefinesOwnIdPropertiesInterface)
68
        );
69 372
    }
70
71 82
    public function __get(string $property)
72
    {
73 82
        return $this->DoGetSet($property, false);
74
    }
75
76 158
    public function __set(string $property, $v)
77
    {
78 158
        return $this->DoGetSet($property, true, $v);
79
    }
80
81
    /**
82
    * @see static::NudgePropertyValue()
83
    */
84 40
    public function __unset(string $property) : void
85
    {
86 40
        $this->NudgePropertyValue($property, null);
87 36
    }
88
89
    /**
90
    * @return array<string, mixed>
91
    */
92 62
    public function __debugInfo() : array
93
    {
94 62
        $out = [];
95 62
        $publicGetters = static::DaftObjectPublicGetters();
96 62
        foreach (static::DaftObjectExportableProperties() as $prop) {
97 60
            $expectedMethod = 'Get' . ucfirst($prop);
98 60
            if ($this->__isset($prop) && in_array($prop, $publicGetters, true)) {
99 60
                $out[(string) $prop] = $this->$expectedMethod();
100
            }
101
        }
102
103 62
        return $out;
104
    }
105
106
    /**
107
    * List of properties that can be defined on an implementation.
108
    *
109
    * @return array<int, string>
110
    */
111 266
    final public static function DaftObjectProperties() : array
112
    {
113 266
        return static::PROPERTIES;
114
    }
115
116 92
    final public static function DaftObjectNullableProperties() : array
117
    {
118 92
        return static::NULLABLE_PROPERTIES;
119
    }
120
121 124
    final public static function DaftObjectExportableProperties() : array
122
    {
123 124
        return static::EXPORTABLE_PROPERTIES;
124
    }
125
126 108
    final public static function DaftObjectPublicGetters() : array
127
    {
128 108
        static::CachePublicGettersAndSetters();
129
130 108
        return self::$publicGetters[static::class];
131
    }
132
133 158
    final public static function DaftObjectPublicSetters() : array
134
    {
135 158
        static::CachePublicGettersAndSetters();
136
137 158
        return self::$publicSetters[static::class];
138
    }
139
140 68
    final public static function DaftObjectJsonProperties() : array
141
    {
142 68
        static::ThrowIfNotDaftJson();
143
144 36
        return static::JSON_PROPERTIES;
145
    }
146
147 36
    final public static function DaftObjectJsonPropertyNames() : array
148
    {
149 36
        $out = [];
150
151 36
        foreach (static::DaftObjectJsonProperties() as $k => $prop) {
152 36
            if (is_string($k)) {
153 24
                $prop = $k;
154
            }
155
156 36
            $out[] = $prop;
157
        }
158
159 36
        return $out;
160
    }
161
162 164
    protected static function ThrowIfNotDaftJson() : void
163
    {
164 164
        if (false === is_a(static::class, DaftJson::class, true)) {
165 128
            throw new DaftObjectNotDaftJsonBadMethodCallException(static::class);
166
        }
167 36
    }
168
169 26
    final protected static function HasPublicMethod(
170
        ReflectionClass $classReflection,
171
        string $method
172
    ) : bool {
173
        if (
174 26
            $classReflection->hasMethod($method)
175
        ) {
176 26
            $methodReflection = new ReflectionMethod(static::class, $method);
177
178
            return
179 26
                $methodReflection->isPublic() &&
180 26
                false === $methodReflection->isStatic();
181
        }
182
183 8
        return false;
184
    }
185
186 216
    final protected static function CachePublicGettersAndSetters() : void
187
    {
188 216
        if (false === isset(self::$publicGetters[static::class])) {
189 26
            self::$publicGetters[static::class] = [];
190 26
            self::$publicSetters[static::class] = [];
191
192 26
            if (is_a(static::class, DefinesOwnIdPropertiesInterface::class, true)) {
193 14
                self::$publicGetters[static::class][] = 'id';
194
            }
195
196 26
            self::CachePublicGettersAndSettersProperties(new ReflectionClass(static::class));
197
        }
198 216
    }
199
200 26
    final protected static function CachePublicGettersAndSettersProperties(
201
        ReflectionClass $classReflection
202
    ) : void {
203 26
        foreach (static::DaftObjectProperties() as $property) {
204 26
            $getter = static::DaftObjectMethodNameFromProperty($property);
205 26
            $setter = static::DaftObjectMethodNameFromProperty($property, true);
206 26
            if (static::HasPublicMethod($classReflection, $getter)) {
207 22
                self::$publicGetters[static::class][] = $property;
208
            }
209
210 26
            if (static::HasPublicMethod($classReflection, $setter)) {
211 26
                self::$publicSetters[static::class][] = $property;
212
            }
213
        }
214 26
    }
215
216
    /**
217
    * Nudge the state of a given property, marking it as dirty.
218
    *
219
    * @param string $property property being nudged
220
    * @param mixed $value value to nudge property with
221
    *
222
    * @throws UndefinedPropertyException if $property is not in static::DaftObjectProperties()
223
    * @throws PropertyNotNullableException if $property is not in static::DaftObjectNullableProperties()
224
    * @throws PropertyNotRewriteableException if class is write-once read-many and $property was already changed
225
    */
226
    abstract protected function NudgePropertyValue(string $property, $value) : void;
227
228
    /**
229
    * Checks if a type correctly defines it's own id.
230
    *
231
    * @throws ClassDoesNotImplementClassException if $class is not an implementation of DefinesOwnIdPropertiesInterface
232
    * @throws ClassMethodReturnHasZeroArrayCountException if $class::DaftObjectIdProperties() does not contain at least one property
233
    * @throws ClassMethodReturnIsNotArrayOfStringsException if $class::DaftObjectIdProperties() is not string[]
234
    * @throws UndefinedPropertyException if an id property is not in $class::DaftObjectIdProperties()
235
    */
236 376
    final protected static function CheckTypeDefinesOwnIdProperties(
237
        string $class,
238
        bool $throwIfNotImplementation = false
239
    ) : void {
240 376
        $interfaceCheck = $class;
241
242 376
        if (is_a($interfaceCheck, DefinesOwnIdPropertiesInterface::class, true)) {
243 232
            $properties = $class::DaftObjectIdProperties();
244
245 232
            if (count($properties) < 1) {
246 2
                throw new ClassMethodReturnHasZeroArrayCountException(
247 2
                    $class,
248 2
                    'DaftObjectIdProperties'
249
                );
250 230
            } elseif (count($properties) !== count(array_filter($properties, 'is_string'))) {
251 2
                throw new ClassMethodReturnIsNotArrayOfStringsException(
252 2
                    $class,
253 230
                    'DaftObjectIdProperties'
254
                );
255
            }
256 150
        } elseif ($throwIfNotImplementation) {
257 2
            throw new ClassDoesNotImplementClassException(
258 2
                $class,
259 2
                DefinesOwnIdPropertiesInterface::class
260
            );
261
        }
262 372
    }
263
264 206
    protected static function DaftObjectMethodNameFromProperty(
265
        string $property,
266
        bool $SetNotGet = false
267
    ) : string {
268 206
        return ($SetNotGet ? 'Set' : 'Get') . ucfirst($property);
269
    }
270
271 216
    protected function MaybeThrowOnDoGetSet(string $property, bool $setter, array $props) : void
272
    {
273 216
        if (false === in_array($property, $props, true)) {
274 10
            if (false === in_array($property, static::DaftObjectProperties(), true)) {
275 6
                throw new UndefinedPropertyException(static::class, $property);
276 4
            } elseif ($setter) {
277 2
                throw new NotPublicSetterPropertyException(static::class, $property);
278
            }
279
280 2
            throw new NotPublicGetterPropertyException(static::class, $property);
281
        }
282 206
    }
283
284
    /**
285
    * @param mixed $v
286
    *
287
    * @return mixed
288
    */
289 216
    protected function DoGetSet(string $property, bool $setter, $v = null)
290
    {
291 216
        $props = $setter ? static::DaftObjectPublicSetters() : static::DaftObjectPublicGetters();
292
293 216
        $this->MaybeThrowOnDoGetSet($property, $setter, $props);
294
295 206
        return $this->{static::DaftObjectMethodNameFromProperty($property, $setter)}($v);
296
    }
297
}
298