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

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