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
Pull Request — master (#56)
by Arthur
01:16
created

Property::isValidType()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 8.9777
c 0
b 0
f 0
cc 6
nc 5
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spatie\DataTransferObject;
6
7
use ReflectionProperty;
8
9
class Property
10
{
11
    /** @var array */
12
    protected static $typeMapping = [
13
        'int' => 'integer',
14
        'bool' => 'boolean',
15
        'float' => 'double'
16
    ];
17
18
    /** @var bool */
19
    protected $hasTypeDeclaration = false;
20
21
    /** @var bool */
22
    protected $isNullable = false;
23
24
    /** @var bool */
25
    protected $isInitialised = false;
26
27
    /** @var bool */
28
    protected $isImmutable = false;
29
30
    /** @var array */
31
    protected $types = [];
32
33
    /** @var array */
34
    protected $arrayTypes = [];
35
36
    /** @var mixed */
37
    protected $default;
38
39
    /** @var mixed */
40
    protected $value;
41
42
    /** @var ReflectionProperty */
43
    protected $reflection;
44
45
    public static function fromReflection(ReflectionProperty $reflectionProperty): self
46
    {
47
        return new static($reflectionProperty);
48
    }
49
50
    public function __construct(ReflectionProperty $reflectionProperty)
51
    {
52
        $this->reflection = $reflectionProperty;
53
54
        $this->resolveTypeDefinition();
55
    }
56
57
    public function set($value)
58
    {
59
        if (is_array($value)) {
60
            $value = $this->shouldBeCastToCollection($value) ? $this->castCollection($value) : $this->cast($value);
61
        }
62
63
        if (!$this->isValidType($value)) {
64
            throw DataTransferObjectError::invalidType($this, $value);
65
        }
66
67
        $this->isInitialised = true;
68
69
        $this->value = $value;
70
    }
71
72
    public function setUninitialized()
73
    {
74
        $this->isInitialised = false;
75
    }
76
77
    public function isInitialized()
78
    {
79
        return $this->isInitialised;
80
    }
81
82
    public function getTypes(): array
83
    {
84
        return $this->types;
85
    }
86
87
    public function getFqn(): string
88
    {
89
        return "{$this->reflection->getDeclaringClass()->getName()}::{$this->reflection->getName()}";
90
    }
91
92
    public function isNullable(): bool
93
    {
94
        return $this->isNullable;
95
    }
96
97
    public function setNullable(bool $bool): void
98
    {
99
        $this->isNullable = $bool;
100
    }
101
102
    public function isImmutable(): bool
103
    {
104
        return $this->isImmutable;
105
    }
106
107
    public function setIsImmutable(bool $isImmutable): void
108
    {
109
        $this->isImmutable = $isImmutable;
110
    }
111
112
    protected function resolveTypeDefinition()
113
    {
114
        $docComment = $this->reflection->getDocComment();
115
116
        if (!$docComment) {
117
            $this->setNullable(true);
118
119
            return;
120
        }
121
122
        preg_match('/\@var ((?:(?:[\w|\\\\])+(?:\[\])?)+)/', $docComment, $matches);
123
124
125
        if (!count($matches)) {
126
            $this->setNullable(true);
127
128
            return;
129
        }
130
131
        $varDocComment = end($matches);
132
133
        $this->types = explode('|', $varDocComment);
134
        $this->arrayTypes = str_replace('[]', '', $this->types);
135
136
        if (in_array('immutable', $this->types) || in_array('Immutable', $this->types)) {
137
            $this->setIsImmutable(true);
138
            unset($this->types['immutable'], $this->types['Immutable']);
139
140
            if (empty($this->types)) {
141
                return;
142
            }
143
        }
144
145
        $this->hasTypeDeclaration = true;
146
147
148
        $this->setNullable(strpos($varDocComment, 'null') !== false);
149
    }
150
151
    protected function isValidType($value): bool
152
    {
153
        if (!$this->hasTypeDeclaration) {
154
            return true;
155
        }
156
157
        if ($this->isNullable() && $value === null) {
158
            return true;
159
        }
160
161
        foreach ($this->types as $currentType) {
162
            $isValidType = $this->assertTypeEquals($currentType, $value);
163
164
            if ($isValidType) {
165
                return true;
166
            }
167
        }
168
169
        return false;
170
    }
171
172
    protected function cast($value)
173
    {
174
        $castTo = null;
175
176
        foreach ($this->types as $type) {
177
            if (!is_subclass_of($type, DataTransferObject::class)) {
178
                continue;
179
            }
180
181
            $castTo = $type;
182
183
            break;
184
        }
185
186
        if (!$castTo) {
187
            return $value;
188
        }
189
190
        return new $castTo($value);
191
    }
192
193
    protected function castCollection(array $values)
194
    {
195
        $castTo = null;
196
197
        foreach ($this->arrayTypes as $type) {
198
            if (!is_subclass_of($type, DataTransferObject::class)) {
199
                continue;
200
            }
201
202
            $castTo = $type;
203
204
            break;
205
        }
206
207
        if (!$castTo) {
208
            return $values;
209
        }
210
211
        $casts = [];
212
213
        foreach ($values as $value) {
214
            $casts[] = new $castTo($value);
215
        }
216
217
        return $casts;
218
    }
219
220
    protected function shouldBeCastToCollection(array $values): bool
221
    {
222
        if (empty($values)) {
223
            return false;
224
        }
225
226
        foreach ($values as $key => $value) {
227
            if (is_string($key)) {
228
                return false;
229
            }
230
231
            if (!is_array($value)) {
232
                return false;
233
            }
234
        }
235
236
        return true;
237
    }
238
239
    protected function assertTypeEquals(string $type, $value): bool
240
    {
241
        if (strpos($type, '[]') !== false) {
242
            return $this->isValidGenericCollection($type, $value);
243
        }
244
245
        if ($type === 'mixed' && $value !== null) {
246
            return true;
247
        }
248
249
        return $value instanceof $type
250
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
251
    }
252
253
    protected function isValidGenericCollection(string $type, $collection): bool
254
    {
255
        if (!is_array($collection)) {
256
            return false;
257
        }
258
259
        $valueType = str_replace('[]', '', $type);
260
261
        foreach ($collection as $value) {
262
            if (!$this->assertTypeEquals($valueType, $value)) {
263
                return false;
264
            }
265
        }
266
267
        return true;
268
    }
269
270
    public function getDefault()
271
    {
272
        return $this->default;
273
    }
274
275
    public function setDefault($default): void
276
    {
277
        $this->default = $default;
278
    }
279
280
    public function getValue()
281
    {
282
        if (!$this->isNullable() && $this->value == null) {
283
            return $this->getDefault();
284
        }
285
286
        return $this->value;
287
    }
288
289
    public function getValueFromReflection($object)
290
    {
291
        return $this->reflection->getValue($object);
292
    }
293
294
    public function getName()
295
    {
296
        return $this->reflection->getName();
297
    }
298
299
    public function getReflection(): ReflectionProperty
300
    {
301
        return $this->reflection;
302
    }
303
304
305
}
306