Passed
Branch feature/first-release (dd5f38)
by Andrea Marco
01:50
created

CasesCollection::groupBy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 9
ccs 5
cts 5
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
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 Traversable;
9
use UnitEnum;
0 ignored issues
show
Bug introduced by
The type UnitEnum 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...
10
11
/**
12
 * The collection of enum cases.
13
 *
14
 */
15
class CasesCollection implements Countable, IteratorAggregate
16
{
17
    /**
18
     * Whether the cases belong to a backed enum
19
     *
20
     * @var bool
21
     */
22
    protected bool $enumIsBacked;
23
24
    /**
25
     * Instantiate the class
26
     *
27
     * @param array $cases
28
     */
29 58
    public function __construct(protected array $cases)
30
    {
31 58
        $this->enumIsBacked = $this->first() instanceof BackedEnum;
32
    }
33
34
    /**
35
     * Retrieve the iterable cases
36
     *
37
     * @return Traversable
38
     */
39 2
    public function getIterator(): Traversable
40
    {
41 2
        return (function () {
42 1
            foreach ($this->cases as $case) {
43 1
                yield $case;
44
            }
45
        })();
46
    }
47
48
    /**
49
     * Retrieve the cases
50
     *
51
     * @return array
52
     */
53 61
    public function cases(): array
54
    {
55 61
        return $this->cases;
56
    }
57
58
    /**
59
     * Retrieve the count of cases
60
     *
61
     * @return int
62
     */
63 2
    public function count(): int
64
    {
65 2
        return count($this->cases);
66
    }
67
68
    /**
69
     * Retrieve the first case
70
     *
71
     * @param callable|null $callback
72
     * @param mixed $default
73
     * @return mixed
74
     */
75 62
    public function first(callable $callback = null, mixed $default = null): mixed
76
    {
77 62
        $callback ??= fn () => true;
78
79 62
        foreach ($this->cases as $case) {
80 60
            if ($callback($case)) {
81 60
                return $case;
82
            }
83
        }
84
85 8
        return $default;
86
    }
87
88
    /**
89
     * Retrieve the cases keyed by name
90
     *
91
     * @return array<string, mixed>
92
     */
93 2
    public function keyByName(): array
94
    {
95 2
        return $this->keyBy('name');
96
    }
97
98
    /**
99
     * Retrieve the cases keyed by the given key
100
     *
101
     * @param callable|string $key
102
     * @return array<string, mixed>
103
     */
104 7
    public function keyBy(callable|string $key): array
105
    {
106 7
        $result = [];
107
108 7
        foreach ($this->cases as $case) {
109 7
            $result[$case->get($key)] = $case;
110
        }
111
112 7
        return $result;
113
    }
114
115
    /**
116
     * Retrieve the cases keyed by value
117
     *
118
     * @return array<string, mixed>
119
     */
120 3
    public function keyByValue(): array
121
    {
122 3
        return $this->enumIsBacked ? $this->keyBy('value') : [];
123
    }
124
125
    /**
126
     * Retrieve the cases grouped by the given key
127
     *
128
     * @param callable|string $key
129
     * @return array<string, mixed>
130
     */
131 6
    public function groupBy(callable|string $key): array
132
    {
133 6
        $result = [];
134
135 6
        foreach ($this->cases as $case) {
136 6
            $result[$case->get($key)][] = $case;
137
        }
138
139 6
        return $result;
140
    }
141
142
    /**
143
     * Retrieve all the names of the cases
144
     *
145
     * @return array<int, string>
146
     */
147 2
    public function names(): array
148
    {
149 2
        return array_column($this->cases, 'name');
150
    }
151
152
    /**
153
     * Retrieve all the values of the backed cases
154
     *
155
     * @return array<int, string|int>
156
     */
157 3
    public function values(): array
158
    {
159 3
        return array_column($this->cases, 'value');
160
    }
161
162
    /**
163
     * Retrieve an array of values optionally keyed by the given key
164
     *
165
     * @param callable|string|null $value
166
     * @param callable|string|null $key
167
     * @return array
168
     */
169 10
    public function pluck(callable|string $value = null, callable|string $key = null): array
170
    {
171 10
        $result = [];
172 10
        $value ??= $this->enumIsBacked ? 'value' : 'name';
173
174 10
        foreach ($this->cases as $case) {
175 10
            if ($key === null) {
176 6
                $result[] = $case->get($value);
177
            } else {
178 4
                $result[$case->get($key)] = $case->get($value);
179
            }
180
        }
181
182 10
        return $result;
183
    }
184
185
    /**
186
     * Retrieve a collection with the filtered cases
187
     *
188
     * @param callable|string $filter
189
     * @return static
190
     */
191 15
    public function filter(callable|string $filter): static
192
    {
193 15
        $callback = is_callable($filter) ? $filter : fn (mixed $case) => $case->get($filter) === true;
194 15
        $cases = array_filter($this->cases, $callback);
195
196 15
        return new static(array_values($cases));
197
    }
198
199
    /**
200
     * Retrieve a collection of cases having the given names
201
     *
202
     * @param string ...$name
203
     * @return static
204
     */
205 2
    public function only(string ...$name): static
206
    {
207 2
        return $this->filter(fn (UnitEnum $case) => in_array($case->name, $name));
208
    }
209
210
    /**
211
     * Retrieve a collection of cases not having the given names
212
     *
213
     * @param string ...$name
214
     * @return static
215
     */
216 2
    public function except(string ...$name): static
217
    {
218 2
        return $this->filter(fn (UnitEnum $case) => !in_array($case->name, $name));
219
    }
220
221
    /**
222
     * Retrieve a collection of backed cases having the given values
223
     *
224
     * @param string|int ...$value
225
     * @return static
226
     */
227 3
    public function onlyValues(string|int ...$value): static
228
    {
229 3
        return $this->filter(fn (UnitEnum $case) => $this->enumIsBacked && in_array($case->value, $value, true));
230
    }
231
232
    /**
233
     * Retrieve a collection of backed cases not having the given values
234
     *
235
     * @param string|int ...$value
236
     * @return static
237
     */
238 3
    public function exceptValues(string|int ...$value): static
239
    {
240 3
        return $this->filter(fn (UnitEnum $case) => $this->enumIsBacked && !in_array($case->value, $value, true));
241
    }
242
243
    /**
244
     * Retrieve a collection of cases sorted by name ascending
245
     *
246
     * @return static
247
     */
248 2
    public function sort(): static
249
    {
250 2
        return $this->sortBy('name');
251
    }
252
253
    /**
254
     * Retrieve a collection of cases sorted by name descending
255
     *
256
     * @return static
257
     */
258 2
    public function sortDesc(): static
259
    {
260 2
        return $this->sortDescBy('name');
261
    }
262
263
    /**
264
     * Retrieve a collection of cases sorted by the given key ascending
265
     *
266
     * @param callable|string $key
267
     * @return static
268
     */
269 6
    public function sortBy(callable|string $key): static
270
    {
271 6
        $cases = $this->cases;
272
273 6
        usort($cases, fn ($a, $b) => $a->get($key) <=> $b->get($key));
274
275 6
        return new static($cases);
276
    }
277
278
    /**
279
     * Retrieve a collection of cases sorted by the given key descending
280
     *
281
     * @param callable|string $key
282
     * @return static
283
     */
284 6
    public function sortDescBy(callable|string $key): static
285
    {
286 6
        $cases = $this->cases;
287
288 6
        usort($cases, fn ($a, $b) => $a->get($key) > $b->get($key) ? -1 : 1);
289
290 6
        return new static($cases);
291
    }
292
293
    /**
294
     * Retrieve a collection of cases sorted by value ascending
295
     *
296
     * @return static
297
     */
298 2
    public function sortByValue(): static
299
    {
300 2
        return $this->enumIsBacked ? $this->sortBy('value') : new static([]);
301
    }
302
303
    /**
304
     * Retrieve a collection of cases sorted by value descending
305
     *
306
     * @return static
307
     */
308 2
    public function sortDescByValue(): static
309
    {
310 2
        return $this->enumIsBacked ? $this->sortDescBy('value') : new static([]);
311
    }
312
}
313