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

Property::castCollection()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.1928
c 0
b 0
f 0
cc 5
nc 9
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(DataTransferObject $valueObject, ReflectionProperty $reflectionProperty)
37
    {
38
        return new self($valueObject, $reflectionProperty);
39
    }
40
41
    public function __construct(DataTransferObject $valueObject, ReflectionProperty $reflectionProperty)
42
    {
43
        parent::__construct($reflectionProperty->class, $reflectionProperty->getName());
44
45
        $this->valueObject = $valueObject;
46
47
        $this->resolveTypeDefinition();
48
    }
49
50
    public function set($value)
51
    {
52
        if (is_array($value)) {
53
            $value = $this->shouldBeCastToCollection($value) ? $this->castCollection($value) : $this->cast($value);
54
        }
55
56
        if (! $this->isValidType($value)) {
57
            throw DataTransferObjectError::invalidType($this, $value);
58
        }
59
60
        $this->isInitialised = true;
61
62
        $this->valueObject->{$this->getName()} = $value;
63
    }
64
65
    public function getTypes(): array
66
    {
67
        return $this->types;
68
    }
69
70
    public function getFqn(): string
71
    {
72
        return "{$this->getDeclaringClass()->getName()}::{$this->getName()}";
73
    }
74
75
    public function isNullable(): bool
76
    {
77
        return $this->isNullable;
78
    }
79
80
    protected function resolveTypeDefinition()
81
    {
82
        $docComment = $this->getDocComment();
83
84
        if (! $docComment) {
85
            $this->isNullable = true;
86
87
            return;
88
        }
89
90
        preg_match('/\@var ((?:(?:[\w|\\\\])+(?:\[\])?)+)/', $docComment, $matches);
91
92
        if (! count($matches)) {
93
            $this->isNullable = true;
94
95
            return;
96
        }
97
98
        $this->hasTypeDeclaration = true;
99
100
        $varDocComment = end($matches);
101
102
        $this->types = explode('|', $varDocComment);
103
        $this->arrayTypes = str_replace('[]', '', $this->types);
104
105
        $this->isNullable = strpos($varDocComment, 'null') !== false;
106
    }
107
108
    protected function isValidType($value): bool
109
    {
110
        if (! $this->hasTypeDeclaration) {
111
            return true;
112
        }
113
114
        if ($this->isNullable && $value === null) {
115
            return true;
116
        }
117
118
        foreach ($this->types as $currentType) {
119
            $isValidType = $this->assertTypeEquals($currentType, $value);
120
121
            if ($isValidType) {
122
                return true;
123
            }
124
        }
125
126
        return false;
127
    }
128
129
    protected function cast($value)
130
    {
131
        $castTo = null;
132
133
        foreach ($this->types as $type) {
134
            if (! is_subclass_of($type, DataTransferObject::class)) {
135
                continue;
136
            }
137
138
            $castTo = $type;
139
140
            break;
141
        }
142
143
        if (! $castTo) {
144
            return $value;
145
        }
146
147
        return new $castTo($value);
148
    }
149
150
    protected function castCollection(array $values)
151
    {
152
        $castTo = null;
153
154
        foreach ($this->arrayTypes as $type) {
155
            if (! is_subclass_of($type, DataTransferObject::class)) {
156
                continue;
157
            }
158
159
            $castTo = $type;
160
161
            break;
162
        }
163
164
        if (! $castTo) {
165
            return $values;
166
        }
167
168
        $casts = [];
169
170
        foreach ($values as $value) {
171
            $casts[] = new $castTo($value);
172
        }
173
174
        return $casts;
175
    }
176
177
    protected function shouldBeCastToCollection(array $values): bool
178
    {
179
        foreach ($values as $value) {
180
            if (! is_array($value)) {
181
                return false;
182
            }
183
        }
184
185
        return true;
186
    }
187
188
    protected function assertTypeEquals(string $type, $value): bool
189
    {
190
        if (strpos($type, '[]') !== false) {
191
            return $this->isValidGenericCollection($type, $value);
192
        }
193
194
        if ($type === 'mixed' && $value !== null) {
195
            return true;
196
        }
197
198
        return $value instanceof $type
199
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
200
    }
201
202
    protected function isValidGenericCollection(string $type, $collection): bool
203
    {
204
        if (! is_array($collection)) {
205
            return false;
206
        }
207
208
        $valueType = str_replace('[]', '', $type);
209
210
        foreach ($collection as $value) {
211
            if (! $this->assertTypeEquals($valueType, $value)) {
212
                return false;
213
            }
214
        }
215
216
        return true;
217
    }
218
}
219