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 (#25)
by Gaël
10:14 queued 09:06
created

HasEnums::isNullableEnum()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 8
cts 8
cp 1
rs 9.4222
c 0
b 0
f 0
cc 5
nc 4
nop 2
crap 5
1
<?php
2
3
namespace Spatie\Enum\Laravel;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Model;
7
use InvalidArgumentException;
8
use Spatie\Enum\Enumerable;
9
use Spatie\Enum\Laravel\Exceptions\InvalidEnumError;
10
use Spatie\Enum\Laravel\Exceptions\NoSuchEnumField;
11
12
/**
13
 * @mixin Model
14
 */
15
trait HasEnums
16
{
17 92
    public function setAttribute($key, $value)
18
    {
19 92
        return $this->isEnumAttribute($key)
20 92
            ? $this->setEnumAttribute($key, $value)
21 80
            : parent::setAttribute($key, $value);
22
    }
23
24 36
    public function getAttribute($key)
25
    {
26 36
        $value = parent::getAttribute($key);
27
28 36
        return $this->isEnumAttribute($key)
29 36
            ? $this->getEnumAttribute($key, $value)
30 36
            : $value;
31
    }
32
33
    /**
34
     * @param \Illuminate\Database\Eloquent\Builder $builder
35
     * @param string $key
36
     * @param int|string|\Spatie\Enum\Enumerable|int[]|string[]|\Spatie\Enum\Enumerable[] $enumerables
37
     *
38
     * @see \Illuminate\Database\Eloquent\Builder::whereIn()
39
     */
40 32
    public function scopeWhereEnum(
41
        Builder $builder,
42
        string $key,
43
        $enumerables
44
    ): void {
45 32
        $this->buildEnumScope(
46 32
            $builder,
47 32
            'whereIn',
48 16
            $key,
49 16
            $enumerables
50
        );
51 28
    }
52
53
    /**
54
     * @param \Illuminate\Database\Eloquent\Builder $builder
55
     * @param string $key
56
     * @param int|string|\Spatie\Enum\Enumerable|int[]|string[]|\Spatie\Enum\Enumerable[] $enumerables
57
     *
58
     * @see \Illuminate\Database\Eloquent\Builder::orWhereIn()
59
     */
60 12
    public function scopeOrWhereEnum(
61
        Builder $builder,
62
        string $key,
63
        $enumerables
64
    ): void {
65 12
        $this->buildEnumScope(
66 12
            $builder,
67 12
            'orWhereIn',
68 6
            $key,
69 6
            $enumerables
70
        );
71 8
    }
72
73
    /**
74
     * @param \Illuminate\Database\Eloquent\Builder $builder
75
     * @param string $key
76
     * @param int|string|\Spatie\Enum\Enumerable|int[]|string[]|\Spatie\Enum\Enumerable[] $enumerables
77
     *
78
     * @see \Illuminate\Database\Eloquent\Builder::whereNotIn()
79
     */
80 20
    public function scopeWhereNotEnum(
81
        Builder $builder,
82
        string $key,
83
        $enumerables
84
    ): void {
85 20
        $this->buildEnumScope(
86 20
            $builder,
87 20
            'whereNotIn',
88 10
            $key,
89 10
            $enumerables
90
        );
91 16
    }
92
93
    /**
94
     * @param \Illuminate\Database\Eloquent\Builder $builder
95
     * @param string $key
96
     * @param int|string|\Spatie\Enum\Enumerable|int[]|string[]|\Spatie\Enum\Enumerable[] $enumerables
97
     *
98
     * @see \Illuminate\Database\Eloquent\Builder::orWhereNotIn()
99
     */
100 12
    public function scopeOrWhereNotEnum(
101
        Builder $builder,
102
        string $key,
103
        $enumerables
104
    ): void {
105 12
        $this->buildEnumScope(
106 12
            $builder,
107 12
            'orWhereNotIn',
108 6
            $key,
109 6
            $enumerables
110
        );
111 8
    }
112
113
    /**
114
     * @param string $key
115
     * @param int|string|\Spatie\Enum\Enumerable $value
116
     *
117
     * @return $this
118
     */
119 92
    protected function setEnumAttribute(string $key, $value)
120
    {
121 92
        $enumClass = $this->getEnumClass($key);
122
123 88
        if ($this->isNullableEnum($key, $value)) {
124 4
            return $this;
125
        }
126
127 88
        if (is_string($value) || is_int($value)) {
128 16
            $value = $this->asEnum($enumClass, $value);
129
        }
130
131 88
        if (is_null($value)) {
132 4
            $enumInterface = Enumerable::class;
133 4
            throw new InvalidArgumentException("{$enumInterface} {$enumClass} is not nullable");
134
        }
135
136 84
        if (! is_a($value, $enumClass)) {
137 4
            throw InvalidEnumError::make(static::class, $key, $enumClass, get_class($value));
138
        }
139
140 80
        $this->attributes[$key] = $this->getStoredValue($key, $value);
0 ignored issues
show
Bug introduced by
The property attributes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
141
142 80
        return $this;
143
    }
144
145
    /**
146
     * @param string $key
147
     * @param \Spatie\Enum\Enumerable $enum
148
     *
149
     * @return int|string
150
     */
151 80
    protected function getStoredValue(string $key, Enumerable $enum)
152
    {
153 80
        return $this->hasCast($key, ['int', 'integer'])
0 ignored issues
show
Bug introduced by
It seems like hasCast() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
154 4
            ? $enum->getIndex()
155 80
            : $enum->getValue();
156
    }
157
158
    /**
159
     * @param string $key
160
     * @param int|string|null $value
161
     *
162
     * @return \Spatie\Enum\Enumerable|int|string|null
163
     */
164 80
    protected function getEnumAttribute(string $key, $value)
165
    {
166 80
        if ($this->isNullableEnum($key, $value)) {
167 4
            return $value;
168
        }
169
170 80
        return $this->asEnum($this->getEnumClass($key), $value);
171
    }
172
173 108
    protected function isEnumAttribute(string $key): bool
174
    {
175 108
        return isset($this->enums[$key]);
0 ignored issues
show
Bug introduced by
The property enums does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
176
    }
177
178 88
    protected function isNullableEnum(string $key, $value): bool
179
    {
180 88
        $enumClass = $this->enums[$key];
181
182 88
        if (! strpos($enumClass, ':')) {
183 84
            return false;
184
        }
185
186 12
        $nullable = explode(':', $enumClass, 2)[1];
187
188 12
        if (! $nullable || $nullable !== 'nullable') {
189 4
            return false;
190
        }
191
192 8
        return $nullable && is_null($value);
193
    }
194
195 92
    protected function getEnumClass(string $key): string
196
    {
197 92
        $enumClass = $this->enums[$key];
198
199 92
        if (strpos($enumClass, ':')) {
200 12
            $enumClass = explode(':', $enumClass, 2)[0];
201
        }
202
203 92
        $enumInterface = Enumerable::class;
204
205 92
        $classImplementsEnumerable = class_implements($enumClass)[$enumInterface] ?? false;
206
207 92
        if (! $classImplementsEnumerable) {
208 4
            throw new InvalidArgumentException("Expected {$enumClass} to implement {$enumInterface}");
209
        }
210
211 88
        return $enumClass;
212
    }
213
214
    /**
215
     * @param string $class
216
     * @param int|string $value
217
     *
218
     * @return \Spatie\Enum\Enumerable
219
     */
220 80
    protected function asEnum(string $class, $value): Enumerable
221
    {
222 80
        if ($value instanceof Enumerable) {
223 36
            return $value;
224
        }
225
226 48
        return forward_static_call(
227 48
            $class.'::make',
228 24
            $value
229
        );
230
    }
231
232
    /**
233
     * @param \Illuminate\Database\Eloquent\Builder $builder
234
     * @param string $method
235
     * @param string $key
236
     * @param int|string|\Spatie\Enum\Enumerable|int[]|string[]|\Spatie\Enum\Enumerable[] $enumerables
237
     */
238 60
    protected function buildEnumScope(
239
        Builder $builder,
240
        string $method,
241
        string $key,
242
        $enumerables
243
    ): void {
244 60
        if (! $this->isEnumAttribute($key)) {
245 16
            throw NoSuchEnumField::make($key, get_class($this));
246
        }
247
248 44
        $enumerables = is_array($enumerables) ? $enumerables : [$enumerables];
249
250 44
        $builder->$method(
251 44
            $key,
252
            array_map(function ($value) use ($key) {
253 44
                return $this->getStoredValue($key, $this->getEnumAttribute($key, $value));
254 44
            }, $enumerables)
255
        );
256 44
    }
257
}
258