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

Property::resolveTypeDefinition()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.504
c 0
b 0
f 0
cc 3
nc 3
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 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
        foreach ($values as $value) {
149
            if (! is_array($value)) {
150
                return $this->cast($values);
151
            }
152
        }
153
154
        $castTo = null;
155
        $flatTypes = str_replace('[]', '', $this->types);
156
157
        foreach ($flatTypes as $type) {
158
            if (! is_subclass_of($type, DataTransferObject::class)) {
159
                continue;
160
            }
161
162
            $castTo = $type;
163
164
            break;
165
        }
166
167
        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...
168
            return $values;
169
        }
170
171
        $casts = array_map(
172
            function ($value) use ($castTo) {
173
                return new $castTo($value);
174
            },
175
            $values
176
        );
177
178
        return !empty($casts) ? $casts : null;
179
    }
180
181
    protected function assertTypeEquals(string $type, $value): bool
182
    {
183
        if (strpos($type, '[]') !== false) {
184
            return $this->isValidGenericCollection($type, $value);
185
        }
186
187
        if ($type === 'mixed' && $value !== null) {
188
            return true;
189
        }
190
191
        return $value instanceof $type
192
            || gettype($value) === (self::$typeMapping[$type] ?? $type);
193
    }
194
195
    protected function isValidGenericCollection(string $type, $collection): bool
196
    {
197
        if (! is_array($collection)) {
198
            return false;
199
        }
200
201
        $valueType = str_replace('[]', '', $type);
202
203
        foreach ($collection as $value) {
204
            if (! $this->assertTypeEquals($valueType, $value)) {
205
                return false;
206
            }
207
        }
208
209
        return true;
210
    }
211
}
212