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

Property::resolveTypeDefinition()   B

Complexity

Conditions 10
Paths 10

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 48
rs 7.2678
c 0
b 0
f 0
cc 10
nc 10
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
            if (ReflectionUtils::isSkipped($type) || strpos($type, '\\') !== false) {
113
                $this->types[] = $type;
114
                continue;
115
            }
116
117
            $array = false;
118
            if ($this->hasBrackets($type)) {
119
                $array = true;
120
                $type = str_replace('[]', '', $type);
121
            }
122
123
            if (isset($uses[$type])) {
124
                $type = $uses[$type];
125
                $this->types[] = $type.($array ? '[]' : '');
126
                continue;
127
            }
128
129
            $this->types[] = implode('\\', [$namespace, $type.($array ? '[]' : '')]);
130
        }
131
132
        $this->arrayTypes = str_replace('[]', '', $this->types);
133
134
        $this->isNullable = strpos($varDocComment, 'null') !== false;
135
    }
136
137
    protected function isValidType($value): bool
138
    {
139
        if (! $this->hasTypeDeclaration) {
140
            return true;
141
        }
142
143
        if ($this->isNullable && $value === null) {
144
            return true;
145
        }
146
147
        foreach ($this->types as $currentType) {
148
            $isValidType = $this->assertTypeEquals($currentType, $value);
149
150
            if ($isValidType) {
151
                return true;
152
            }
153
        }
154
155
        return false;
156
    }
157
158
    protected function cast($value)
159
    {
160
        $castTo = null;
161
162
        foreach ($this->types as $type) {
163
            if (! is_subclass_of($type, DataTransferObject::class)) {
164
                continue;
165
            }
166
167
            $castTo = $type;
168
169
            break;
170
        }
171
172
        if (! $castTo) {
173
            return $value;
174
        }
175
176
        return new $castTo($value);
177
    }
178
179
    protected function castCollection(array $values)
180
    {
181
        $castTo = null;
182
183
        foreach ($this->arrayTypes as $type) {
184
            if (! is_subclass_of($type, DataTransferObject::class)) {
185
                continue;
186
            }
187
188
            $castTo = $type;
189
190
            break;
191
        }
192
193
        if (! $castTo) {
194
            return $values;
195
        }
196
197
        $casts = [];
198
199
        foreach ($values as $value) {
200
            $casts[] = new $castTo($value);
201
        }
202
203
        return $casts;
204
    }
205
206
    protected function shouldBeCastToCollection(array $values): bool
207
    {
208
        if (empty($values)) {
209
            return false;
210
        }
211
212
        foreach ($values as $key => $value) {
213
            if (is_string($key)) {
214
                return false;
215
            }
216
217
            if (! is_array($value)) {
218
                return false;
219
            }
220
        }
221
222
        return true;
223
    }
224
225
    protected function hasBrackets(string $type): bool
226
    {
227
        return strpos($type, '[]') !== false;
228
    }
229
230
    protected function assertTypeEquals(string $type, $value): bool
231
    {
232
        if ($this->hasBrackets($type)) {
233
            return $this->isValidGenericCollection($type, $value);
234
        }
235
236
        if ($type === 'mixed' && $value !== null) {
237
            return true;
238
        }
239
240
        return $value instanceof $type
241
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
242
    }
243
244
    protected function isValidGenericCollection(string $type, $collection): bool
245
    {
246
        if (! is_array($collection)) {
247
            return false;
248
        }
249
250
        $valueType = str_replace('[]', '', $type);
251
252
        foreach ($collection as $value) {
253
            if (! $this->assertTypeEquals($valueType, $value)) {
254
                return false;
255
            }
256
        }
257
258
        return true;
259
    }
260
}
261