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 (#57)
by Brent
01:31
created

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