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

Property::isNullable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
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
        if (! count($matches)) {
76
            $this->setNullable(true);
77
78
            return;
79
        }
80
81
        $varDocComment = end($matches);
82
83
        $this->types = explode('|', $varDocComment);
84
        $this->arrayTypes = str_replace('[]', '', $this->types);
85
86
        if (in_array('immutable', $this->types) || in_array('Immutable', $this->types)) {
87
            $this->setImmutable(true);
88
            unset($this->types['immutable'], $this->types['Immutable']);
89
90
            if (empty($this->types)) {
91
                return;
92
            }
93
        }
94
95
        $this->hasTypeDeclaration = true;
96
97
        $this->setNullable(strpos($varDocComment, 'null') !== false);
98
    }
99
100
    protected function isValidType($value): bool
101
    {
102
        if (! $this->hasTypeDeclaration) {
103
            return true;
104
        }
105
106
        if ($this->nullable() && $value === null) {
107
            return true;
108
        }
109
110
        foreach ($this->types as $currentType) {
111
            $isValidType = $this->assertTypeEquals($currentType, $value);
112
113
            if ($isValidType) {
114
                return true;
115
            }
116
        }
117
118
        return false;
119
    }
120
121
    protected function cast($value)
122
    {
123
        $castTo = null;
124
125
        foreach ($this->types as $type) {
126
            if (! is_subclass_of($type, DtoContract::class)) {
127
                continue;
128
            }
129
130
            $castTo = $type;
131
132
            break;
133
        }
134
135
        if (! $castTo) {
136
            return $value;
137
        }
138
139
        return new $castTo($value);
140
    }
141
142
    protected function castCollection(array $values)
143
    {
144
        $castTo = null;
145
146
        foreach ($this->arrayTypes as $type) {
147
            if (! is_subclass_of($type, DtoContract::class)) {
148
                continue;
149
            }
150
151
            $castTo = $type;
152
153
            break;
154
        }
155
156
        if (! $castTo) {
157
            return $values;
158
        }
159
160
        $casts = [];
161
162
        foreach ($values as $value) {
163
            $casts[] = new $castTo($value);
164
        }
165
166
        return $casts;
167
    }
168
169
    protected function shouldBeCastToCollection(array $values): bool
170
    {
171
        if (empty($values)) {
172
            return false;
173
        }
174
175
        foreach ($values as $key => $value) {
176
            if (is_string($key)) {
177
                return false;
178
            }
179
180
            if (! is_array($value)) {
181
                return false;
182
            }
183
        }
184
185
        return true;
186
    }
187
188
    protected function assertTypeEquals(string $type, $value): bool
189
    {
190
        if (strpos($type, '[]') !== false) {
191
            return $this->isValidGenericCollection($type, $value);
192
        }
193
194
        if ($type === 'mixed' && $value !== null) {
195
            return true;
196
        }
197
198
        return $value instanceof $type
199
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
200
    }
201
202
    protected function isValidGenericCollection(string $type, $collection): bool
203
    {
204
        if (! is_array($collection)) {
205
            return false;
206
        }
207
208
        $valueType = str_replace('[]', '', $type);
209
210
        foreach ($collection as $value) {
211
            if (! $this->assertTypeEquals($valueType, $value)) {
212
                return false;
213
            }
214
        }
215
216
        return true;
217
    }
218
219
    public function set($value) :void
220
    {
221
        if (is_array($value)) {
222
            $value = $this->shouldBeCastToCollection($value) ? $this->castCollection($value) : $this->cast($value);
223
        }
224
225
        if (! $this->isValidType($value)) {
226
            throw new InvalidTypeDtoException($this, $value);
227
        }
228
229
        $this->setInitialized(true);
230
231
        $this->value = $value;
232
    }
233
234
    public function setInitialized(bool $bool):void
235
    {
236
        $this->initialised = $bool;
237
    }
238
239
    public function isInitialized() :bool
240
    {
241
        return $this->initialised;
242
    }
243
244
    public function getTypes(): array
245
    {
246
        return $this->types;
247
    }
248
249
    public function getFqn(): string
250
    {
251
        return "{$this->reflection->getDeclaringClass()->getName()}::{$this->reflection->getName()}";
252
    }
253
254
    public function nullable(): bool
255
    {
256
        return $this->nullable;
257
    }
258
259
    public function setNullable(bool $bool): void
260
    {
261
        $this->nullable = $bool;
262
    }
263
264
    public function immutable(): bool
265
    {
266
        return $this->immutable;
267
    }
268
269
    public function setImmutable(bool $immutable): void
270
    {
271
        $this->immutable = $immutable;
272
    }
273
274
    public function getDefault()
275
    {
276
        return $this->default;
277
    }
278
279
    public function setDefault($default): void
280
    {
281
        $this->default = $default;
282
    }
283
284
    public function isVisible(): bool
285
    {
286
        return $this->visible;
287
    }
288
289
    public function setVisible(bool $bool): bool
290
    {
291
        return $this->visible = $bool;
292
    }
293
294
    public function getValue()
295
    {
296
        if (! $this->nullable() && $this->value == null) {
297
            return $this->getDefault();
298
        }
299
300
        return $this->value;
301
    }
302
303
    public function getValueFromReflection($object)
304
    {
305
        return $this->reflection->getValue($object);
306
    }
307
308
    public function getName() :string
309
    {
310
        return $this->reflection->getName();
311
    }
312
}
313