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:30
created

Property::nullable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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