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 (#55)
by Arthur
02:02
created

Property::assertTypeEquals()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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