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 (#77)
by
unknown
01:32
created

Property::resolveTypeDefinition()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 31
rs 9.424
c 0
b 0
f 0
cc 4
nc 4
nop 0
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
    protected static array
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

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