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

Property::isValidGenericCollection()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.7333
c 0
b 0
f 0
cc 4
nc 4
nop 2
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
    public static function fromReflection(DataTransferObject $valueObject, ReflectionProperty $reflectionProperty)
34
    {
35
        return new self($valueObject, $reflectionProperty);
36
    }
37
38
    public function __construct(DataTransferObject $valueObject, ReflectionProperty $reflectionProperty)
39
    {
40
        parent::__construct($reflectionProperty->class, $reflectionProperty->getName());
41
42
        $this->valueObject = $valueObject;
43
44
        $this->resolveTypeDefinition();
45
    }
46
47
    public function set($value)
48
    {
49
        if (is_array($value)) {
50
            $value = Arr::isAssoc($value) ? $this->cast($value) : $this->castArray($value);
51
        }
52
53
        if (! $this->isValidType($value)) {
54
            throw DataTransferObjectError::invalidType($this, $value);
55
        }
56
57
        $this->isInitialised = true;
58
59
        $this->valueObject->{$this->getName()} = $value;
60
    }
61
62
    public function getTypes(): array
63
    {
64
        return $this->types;
65
    }
66
67
    public function getFqn(): string
68
    {
69
        return "{$this->getDeclaringClass()->getName()}::{$this->getName()}";
70
    }
71
72
    public function isNullable(): bool
73
    {
74
        return $this->isNullable;
75
    }
76
77
    protected function resolveTypeDefinition()
78
    {
79
        $docComment = $this->getDocComment();
80
81
        if (! $docComment) {
82
            $this->isNullable = true;
83
84
            return;
85
        }
86
87
        preg_match('/\@var ((?:(?:[\w|\\\\])+(?:\[\])?)+)/', $docComment, $matches);
88
89
        if (! count($matches)) {
90
            $this->isNullable = true;
91
92
            return;
93
        }
94
95
        $this->hasTypeDeclaration = true;
96
97
        $varDocComment = end($matches);
98
99
        $this->types = explode('|', $varDocComment);
100
101
        $this->isNullable = strpos($varDocComment, 'null') !== false;
102
    }
103
104
    protected function isValidType($value): bool
105
    {
106
        if (! $this->hasTypeDeclaration) {
107
            return true;
108
        }
109
110
        if ($this->isNullable && $value === null) {
111
            return true;
112
        }
113
114
        foreach ($this->types as $currentType) {
115
            $isValidType = $this->assertTypeEquals($currentType, $value);
116
117
            if ($isValidType) {
118
                return true;
119
            }
120
        }
121
122
        return false;
123
    }
124
125
    protected function cast($value)
126
    {
127
        $castTo = null;
128
129
        foreach ($this->types as $type) {
130
            if (! is_subclass_of($type, DataTransferObject::class)) {
131
                continue;
132
            }
133
134
            $castTo = $type;
135
136
            break;
137
        }
138
139
        if (! $castTo) {
140
            return $value;
141
        }
142
143
        return new $castTo($value);
144
    }
145
146
    protected function castArray(array $values)
147
    {
148
        if (Arr::containsType($values, DataTransferObject::class)) {
149
            return $values;
150
        }
151
152
        $castTo = null;
153
        $flatTypes = str_replace('[]', '', $this->types);
154
155
        foreach ($flatTypes as $type) {
156
            if (! is_subclass_of($type, DataTransferObject::class)) {
157
                continue;
158
            }
159
160
            $castTo = $type;
161
162
            break;
163
        }
164
165
166
        if (! $castTo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $castTo of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
167
            return $values;
168
        }
169
170
        return array_map(
171
            function ($value) use ($castTo) {
172
                if (is_array($value)) {
173
                    return new $castTo($value);
174
                }
175
            },
176
            $values
177
        );
178
    }
179
180
    protected function assertTypeEquals(string $type, $value): bool
181
    {
182
        if (strpos($type, '[]') !== false) {
183
            return $this->isValidGenericCollection($type, $value);
184
        }
185
186
        if ($type === 'mixed' && $value !== null) {
187
            return true;
188
        }
189
190
        return $value instanceof $type
191
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
192
    }
193
194
    protected function isValidGenericCollection(string $type, $collection): bool
195
    {
196
        if (! is_array($collection)) {
197
            return false;
198
        }
199
200
        $valueType = str_replace('[]', '', $type);
201
202
        foreach ($collection as $value) {
203
            if (! $this->assertTypeEquals($valueType, $value)) {
204
                return false;
205
            }
206
        }
207
208
        return true;
209
    }
210
}
211