Passed
Push — master ( 44846f...2a05cb )
by Andrea Marco
02:04 queued 14s
created

CasesCollection::sortDesc()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Cerbero\Enum;
4
5
use BackedEnum;
0 ignored issues
show
Bug introduced by
The type BackedEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
This use statement conflicts with another class in this namespace, Cerbero\Enum\BackedEnum. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Countable;
7
use IteratorAggregate;
8
use JsonSerializable;
9
use Stringable;
10
use Traversable;
11
12
/**
13
 * The collection of enum cases.
14
 *
15
 * @template TValue
16
 *
17
 * @implements IteratorAggregate<array-key, TValue>
18
 */
19
class CasesCollection implements Countable, IteratorAggregate, JsonSerializable, Stringable
20
{
21
    /**
22
     * Whether the cases belong to a backed enum.
23
     */
24
    protected readonly bool $enumIsBacked;
25
26
    /**
27
     * Instantiate the class.
28
     *
29
     * @param array<array-key, TValue> $cases
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, TValue> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, TValue>.
Loading history...
30
     */
31 68
    final public function __construct(protected readonly array $cases)
32
    {
33 68
        $this->enumIsBacked = reset($cases) instanceof BackedEnum;
0 ignored issues
show
Bug introduced by
The property enumIsBacked is declared read-only in Cerbero\Enum\CasesCollection.
Loading history...
34
    }
35
36
    /**
37
     * Turn the collection into a string.
38
     */
39 2
    public function __toString(): string
40
    {
41 2
        return (string) json_encode($this->jsonSerialize());
42
    }
43
44
    /**
45
     * Turn the collection into a JSON serializable array.
46
     *
47
     * @return list<string|int>
0 ignored issues
show
Bug introduced by
The type Cerbero\Enum\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
48
     */
49 2
    public function jsonSerialize(): array
50
    {
51 2
        return $this->enumIsBacked ? $this->values() : $this->names();
52
    }
53
54
    /**
55
     * Retrieve the count of cases.
56
     */
57 4
    public function count(): int
58
    {
59 4
        return count($this->cases);
60
    }
61
62
    /**
63
     * Retrieve the iterable cases.
64
     *
65
     * @return Traversable<array-key, TValue>
66
     */
67 10
    public function getIterator(): Traversable
68
    {
69 10
        yield from $this->cases;
70
    }
71
72
    /**
73
     * Retrieve all the cases as a plain array.
74
     *
75
     * @return array<array-key, TValue>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, TValue> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, TValue>.
Loading history...
76
     */
77 73
    public function all(): array
78
    {
79 73
        return $this->cases;
80
    }
81
82
    /**
83
     * Determine whether the collection contains the given case.
84
     */
85 2
    public function has(mixed $case): bool
86
    {
87 2
        foreach ($this->cases as $instance) {
88 2
            if ($instance->is($case)) {
89 2
                return true;
90
            }
91
        }
92
93 2
        return false;
94
    }
95
96
    /**
97
     * Retrieve all the cases as a plain array recursively.
98
     *
99
     * @return array<array-key, mixed>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, mixed> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, mixed>.
Loading history...
100
     */
101 1
    public function toArray(): array
102
    {
103 1
        $array = [];
104
105 1
        foreach ($this->cases as $key => $value) {
106 1
            $array[$key] = $value instanceof static ? $value->toArray() : $value;
107
        }
108
109 1
        return $array;
110
    }
111
112
    /**
113
     * Retrieve the first case.
114
     *
115
     * @param (callable(TValue, array-key): bool)|null $callback
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue, array-key): bool)|null at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
116
     * @return ?TValue
117
     */
118 5
    public function first(callable $callback = null): mixed
119
    {
120 5
        $callback ??= fn() => true;
121
122 5
        foreach ($this->cases as $key => $case) {
123 4
            if ($callback($case, $key)) {
124 4
                return $case;
125
            }
126
        }
127
128 1
        return null;
129
    }
130
131
    /**
132
     * Retrieve all the names of the cases.
133
     *
134
     * @return string[]
135
     */
136 3
    public function names(): array
137
    {
138 3
        return array_column($this->cases, 'name');
139
    }
140
141
    /**
142
     * Retrieve all the values of the backed cases.
143
     *
144
     * @return list<string|int>
145
     */
146 4
    public function values(): array
147
    {
148 4
        return array_column($this->cases, 'value');
149
    }
150
151
    /**
152
     * Retrieve an array of values optionally keyed by the given key.
153
     *
154
     * @template TPluckValue
155
     *
156
     * @param (callable(TValue): TPluckValue)|string $value
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue): TPluckValue)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
157
     * @param (callable(TValue): array-key)|string|null $key
158
     * @return array<array-key, TPluckValue>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, TPluckValue> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, TPluckValue>.
Loading history...
159
     */
160 10
    public function pluck(callable|string $value, callable|string $key = null): array
161
    {
162 10
        $result = [];
163
164 10
        foreach ($this->cases as $case) {
165 10
            if ($key === null) {
166 6
                $result[] = $case->resolveItem($value);
167
            } else {
168 4
                $result[$case->resolveItem($key)] = $case->resolveItem($value);
169
            }
170
        }
171
172 10
        return $result;
173
    }
174
175
    /**
176
     * Retrieve the result of mapping over the cases.
177
     *
178
     * @template TMapValue
179
     *
180
     * @param callable(TValue, array-key): TMapValue $callback
181
     * @return array<array-key, TMapValue>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, TMapValue> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, TMapValue>.
Loading history...
182
     */
183 3
    public function map(callable $callback): array
184
    {
185 3
        $keys = array_keys($this->cases);
186 3
        $values = array_map($callback, $this->cases, $keys);
187
188 3
        return array_combine($keys, $values);
189
    }
190
191
    /**
192
     * Retrieve the cases keyed by their own name.
193
     */
194 1
    public function keyByName(): static
195
    {
196 1
        return $this->keyBy('name');
197
    }
198
199
    /**
200
     * Retrieve the cases keyed by the given key.
201
     *
202
     * @param (callable(TValue): array-key)|string $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue): array-key)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
203
     */
204 4
    public function keyBy(callable|string $key): static
205
    {
206 4
        $keyed = [];
207
208 4
        foreach ($this->cases as $case) {
209 4
            $keyed[$case->resolveItem($key)] = $case;
210
        }
211
212 4
        return new static($keyed);
213
    }
214
215
    /**
216
     * Retrieve the cases keyed by their own value.
217
     */
218 2
    public function keyByValue(): static
219
    {
220 2
        return $this->enumIsBacked ? $this->keyBy('value') : new static([]);
221
    }
222
223
    /**
224
     * Retrieve the cases grouped by the given key.
225
     *
226
     * @param (callable(TValue): array-key)|string $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue): array-key)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
227
     */
228 6
    public function groupBy(callable|string $key): static
229
    {
230 6
        $grouped = [];
231
232 6
        foreach ($this->cases as $case) {
233 6
            $grouped[$case->resolveItem($key)][] = $case;
234
        }
235
236 6
        foreach ($grouped as $key => $cases) {
237 6
            $grouped[$key] = new static($cases);
238
        }
239
240 6
        return new static($grouped);
241
    }
242
243
    /**
244
     * Retrieve a new collection with the filtered cases.
245
     *
246
     * @param (callable(TValue): bool)|string $filter
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue): bool)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
247
     */
248 15
    public function filter(callable|string $filter): static
249
    {
250
        /** @phpstan-ignore method.nonObject */
251 15
        $callback = is_callable($filter) ? $filter : fn(mixed $case) => $case->resolveItem($filter) === true;
252
253 15
        return new static(array_filter($this->cases, $callback));
254
    }
255
256
    /**
257
     * Retrieve a new collection of cases having only the given names.
258
     */
259 2
    public function only(string ...$name): static
260
    {
261 2
        return $this->filter(fn(mixed $case) => in_array($case->name, $name));
262
    }
263
264
    /**
265
     * Retrieve a collection of cases not having the given names.
266
     */
267 2
    public function except(string ...$name): static
268
    {
269 2
        return $this->filter(fn(mixed $case) => !in_array($case->name, $name));
270
    }
271
272
    /**
273
     * Retrieve a new collection of backed cases having only the given values.
274
     */
275 3
    public function onlyValues(string|int ...$value): static
276
    {
277 3
        return $this->filter(fn(mixed $case) => $this->enumIsBacked && in_array($case->value, $value, true));
278
    }
279
280
    /**
281
     * Retrieve a new collection of backed cases not having the given values.
282
     */
283 3
    public function exceptValues(string|int ...$value): static
284
    {
285 3
        return $this->filter(fn(mixed $case) => $this->enumIsBacked && !in_array($case->value, $value, true));
286
    }
287
288
    /**
289
     * Retrieve a new collection of cases sorted by their own name ascending.
290
     */
291 2
    public function sort(): static
292
    {
293 2
        return $this->sortBy('name');
294
    }
295
296
    /**
297
     * Retrieve a new collection of cases sorted by the given key ascending.
298
     *
299
     * @param (callable(TValue): mixed)|string $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue): mixed)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
300
     */
301 6
    public function sortBy(callable|string $key): static
302
    {
303 6
        $cases = $this->cases;
304
305 6
        uasort($cases, fn(mixed $a, mixed $b) => $a->resolveItem($key) <=> $b->resolveItem($key));
306
307 6
        return new static($cases);
308
    }
309
310
    /**
311
     * Retrieve a new collection of cases sorted by their own value ascending.
312
     */
313 2
    public function sortByValue(): static
314
    {
315 2
        return $this->enumIsBacked ? $this->sortBy('value') : new static([]);
316
    }
317
318
    /**
319
     * Retrieve a new collection of cases sorted by their own name descending.
320
     */
321 2
    public function sortDesc(): static
322
    {
323 2
        return $this->sortByDesc('name');
324
    }
325
326
    /**
327
     * Retrieve a new collection of cases sorted by the given key descending.
328
     *
329
     * @param (callable(TValue): mixed)|string $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment (callable(TValue): mixed)|string at position 1 could not be parsed: Expected ')' at position 1, but found 'callable'.
Loading history...
330
     */
331 6
    public function sortByDesc(callable|string $key): static
332
    {
333 6
        $cases = $this->cases;
334
335 6
        uasort($cases, fn(mixed $a, mixed $b) => $b->resolveItem($key) <=> $a->resolveItem($key));
336
337 6
        return new static($cases);
338
    }
339
340
    /**
341
     * Retrieve a new collection of cases sorted by their own value descending.
342
     */
343 2
    public function sortByDescValue(): static
344
    {
345 2
        return $this->enumIsBacked ? $this->sortByDesc('value') : new static([]);
346
    }
347
}
348