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 ( a572b7...e3df15 )
by Brent
17s queued 14s
created

Property   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 48
lcom 1
cbo 1
dl 0
loc 244
rs 8.5599
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A fromReflection() 0 4 1
A __construct() 0 8 1
A set() 0 14 4
A getTypes() 0 4 1
A getFqn() 0 4 1
A isNullable() 0 4 1
A resolveTypeDefinition() 0 31 4
B isValidType() 0 20 6
A cast() 0 20 4
A castCollection() 0 26 5
A shouldBeCastToCollection() 0 18 5
B assertTypeEquals() 0 17 7
A isValidArray() 0 10 2
A isValidIterable() 0 12 3
A isValidGenericCollection() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like Property 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Property, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spatie\DataTransferObject;
6
7
use ReflectionProperty;
8
9
class Property extends ReflectionProperty
10
{
11
    /** @var array */
12
    protected static $typeMapping = [
13
        'int' => 'integer',
14
        'bool' => 'boolean',
15
        'float' => 'double',
16
    ];
17
18
    /** @var \Spatie\DataTransferObject\DataTransferObject */
19
    protected $valueObject;
20
21
    /** @var bool */
22
    protected $hasTypeDeclaration = false;
23
24
    /** @var bool */
25
    protected $isNullable = false;
26
27
    /** @var bool */
28
    protected $isInitialised = false;
29
30
    /** @var array */
31
    protected $types = [];
32
33
    /** @var array */
34
    protected $arrayTypes = [];
35
36
    public static function fromReflection(DataTransferObject $valueObject, ReflectionProperty $reflectionProperty)
37
    {
38
        return new self($valueObject, $reflectionProperty);
39
    }
40
41
    public function __construct(DataTransferObject $valueObject, ReflectionProperty $reflectionProperty)
42
    {
43
        parent::__construct($reflectionProperty->class, $reflectionProperty->getName());
44
45
        $this->valueObject = $valueObject;
46
47
        $this->resolveTypeDefinition();
48
    }
49
50
    public function set($value)
51
    {
52
        if (is_array($value)) {
53
            $value = $this->shouldBeCastToCollection($value) ? $this->castCollection($value) : $this->cast($value);
54
        }
55
56
        if (! $this->isValidType($value)) {
57
            throw DataTransferObjectError::invalidType($this, $value);
58
        }
59
60
        $this->isInitialised = true;
61
62
        $this->valueObject->{$this->getName()} = $value;
63
    }
64
65
    public function getTypes(): array
66
    {
67
        return $this->types;
68
    }
69
70
    public function getFqn(): string
71
    {
72
        return "{$this->getDeclaringClass()->getName()}::{$this->getName()}";
73
    }
74
75
    public function isNullable(): bool
76
    {
77
        return $this->isNullable;
78
    }
79
80
    protected function resolveTypeDefinition()
81
    {
82
        $docComment = $this->getDocComment();
83
84
        if (! $docComment) {
85
            $this->isNullable = true;
86
87
            return;
88
        }
89
90
        preg_match('/\@var ((?:(?:[\w|\\\\<>])+(?:\[\])?)+)/', $docComment, $matches);
91
92
        if (! count($matches)) {
93
            $this->isNullable = true;
94
95
            return;
96
        }
97
98
        $this->hasTypeDeclaration = true;
99
100
        $varDocComment = end($matches);
101
102
        $this->types = explode('|', $varDocComment);
103
        $this->arrayTypes = str_replace('[]', '', $this->types);
104
105
        if (preg_match_all('/iterable<([^|]*)>/', $varDocComment, $matches)) {
106
            $this->arrayTypes = array_merge($this->arrayTypes, $matches[1]);
107
        }
108
109
        $this->isNullable = strpos($varDocComment, 'null') !== false;
110
    }
111
112
    protected function isValidType($value): bool
113
    {
114
        if (! $this->hasTypeDeclaration) {
115
            return true;
116
        }
117
118
        if ($this->isNullable && $value === null) {
119
            return true;
120
        }
121
122
        foreach ($this->types as $currentType) {
123
            $isValidType = $this->assertTypeEquals($currentType, $value);
124
125
            if ($isValidType) {
126
                return true;
127
            }
128
        }
129
130
        return false;
131
    }
132
133
    protected function cast($value)
134
    {
135
        $castTo = null;
136
137
        foreach ($this->types as $type) {
138
            if (! is_subclass_of($type, DataTransferObject::class)) {
139
                continue;
140
            }
141
142
            $castTo = $type;
143
144
            break;
145
        }
146
147
        if (! $castTo) {
148
            return $value;
149
        }
150
151
        return new $castTo($value);
152
    }
153
154
    protected function castCollection(array $values)
155
    {
156
        $castTo = null;
157
158
        foreach ($this->arrayTypes as $type) {
159
            if (! is_subclass_of($type, DataTransferObject::class)) {
160
                continue;
161
            }
162
163
            $castTo = $type;
164
165
            break;
166
        }
167
168
        if (! $castTo) {
169
            return $values;
170
        }
171
172
        $casts = [];
173
174
        foreach ($values as $value) {
175
            $casts[] = new $castTo($value);
176
        }
177
178
        return $casts;
179
    }
180
181
    protected function shouldBeCastToCollection(array $values): bool
182
    {
183
        if (empty($values)) {
184
            return false;
185
        }
186
187
        foreach ($values as $key => $value) {
188
            if (is_string($key)) {
189
                return false;
190
            }
191
192
            if (! is_array($value)) {
193
                return false;
194
            }
195
        }
196
197
        return true;
198
    }
199
200
    protected function assertTypeEquals(string $type, $value): bool
201
    {
202
        if (strpos($type, '[]') !== false) {
203
            return $this->isValidArray($type, $value);
204
        }
205
206
        if ($type === 'iterable' || strpos($type, 'iterable<') === 0) {
207
            return $this->isValidIterable($type, $value);
208
        }
209
210
        if ($type === 'mixed' && $value !== null) {
211
            return true;
212
        }
213
214
        return $value instanceof $type
215
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
216
    }
217
218
    protected function isValidArray(string $type, $collection): bool
219
    {
220
        if (! is_array($collection)) {
221
            return false;
222
        }
223
224
        $valueType = str_replace('[]', '', $type);
225
226
        return $this->isValidGenericCollection($valueType, $collection);
227
    }
228
229
    protected function isValidIterable(string $type, $collection): bool
230
    {
231
        if (! is_iterable($collection)) {
232
            return false;
233
        }
234
235
        if (preg_match('/^iterable<(.*)>$/', $type, $matches)) {
236
            return $this->isValidGenericCollection($matches[1], $collection);
237
        }
238
239
        return true;
240
    }
241
242
    protected function isValidGenericCollection(string $type, $collection): bool
243
    {
244
        foreach ($collection as $value) {
245
            if (! $this->assertTypeEquals($type, $value)) {
246
                return false;
247
            }
248
        }
249
250
        return true;
251
    }
252
}
253