Completed
Pull Request — 4.x (#121)
by Marc
04:26 queued 02:50
created

EnumMap::withoutIterable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MabeEnum;
6
7
use ArrayAccess;
8
use Countable;
9
use InvalidArgumentException;
10
use Iterator;
11
use IteratorAggregate;
12
use UnexpectedValueException;
13
14
/**
15
 * A map of enumerators and data values (EnumMap<K extends Enum, V>).
16
 *
17
 * @copyright 2019 Marc Bennewitz
18
 * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
19
 * @link http://github.com/marc-mabe/php-enum for the canonical source repository
20
 */
3 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
21
class EnumMap implements ArrayAccess, Countable, IteratorAggregate
22
{
23
    /**
24
     * The classname of the enumeration type
25
     * @var string
26
     */
27
    private $enumeration;
1 ignored issue
show
Coding Style introduced by
Expected 1 blank line before member var; 0 found
Loading history...
Coding Style introduced by
Private member variable "enumeration" must contain a leading underscore
Loading history...
28
29
    /**
30
     * Internal map of ordinal number and data value
31
     * @var array
32
     */
33
    private $map = [];
1 ignored issue
show
Coding Style introduced by
Private member variable "map" must contain a leading underscore
Loading history...
34
35
    /**
36
     * Constructor
37
     * @param string $enumeration The classname of the enumeration type
1 ignored issue
show
introduced by
Parameter comment must end with a full stop
Loading history...
Coding Style introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
38
     * @param null|iterable $map Initialize map
1 ignored issue
show
Coding Style introduced by
Expected 9 spaces after parameter name; 1 found
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
39
     * @throws InvalidArgumentException
0 ignored issues
show
introduced by
Comment missing for @throws tag in function comment
Loading history...
40
     */
41 19
    public function __construct(string $enumeration, iterable $map = null)
2 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$map" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$map"; expected 0 but found 1
Loading history...
42
    {
43 19
        if (!\is_subclass_of($enumeration, Enum::class)) {
44 1
            throw new InvalidArgumentException(\sprintf(
45 1
                '%s can handle subclasses of %s only',
46 1
                 __CLASS__,
47 1
                Enum::class
48
            ));
49
        }
50 18
        $this->enumeration = $enumeration;
51
52 18
        if ($map) {
0 ignored issues
show
introduced by
$map is of type iterable|null, thus it always evaluated to false.
Loading history...
53 2
            $this->addIterable($map);
54
        }
55 18
    }
56
57
    /* write access (mutable) */
58
59
    /**
60
     * Adds the given enumerator (object or value) mapping to the specified data value.
61
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
62
     * @param mixed                                 $value
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
63
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
64
     * @see offsetSet()
65
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
66 11
    public function add($enumerator, $value): void
67
    {
68 11
        $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
69 10
        $this->map[$ord] = $value;
70 10
    }
71
72
    /**
73
     * Adds the given iterable, mapping enumerators (objects or values) to data values.
74
     * @param iterable $map
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
75
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
76
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
77 4
    public function addIterable(iterable $map): void
78
    {
79 4
        $innerMap = $this->map;
80 4
        foreach ($map as $enumerator => $value) {
81 4
            $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
82 4
            $innerMap[$ord] = $value;
83
        }
84 4
        $this->map = $innerMap;
85 4
    }
86
87
    /**
88
     * Removes the given enumerator (object or value) mapping.
89
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
90
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
91
     * @see offsetUnset()
92
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
93 5
    public function remove($enumerator): void
94
    {
95 5
        $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
96 5
        unset($this->map[$ord]);
97 5
    }
98
99
    /**
100
     * Removes the given iterable enumerator (object or value) mappings.
101
     * @param iterable $enumerators
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
102
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
103
     */
0 ignored issues
show
introduced by
Missing @return tag in function comment
Loading history...
104 2
    public function removeIterable(iterable $enumerators): void
105
    {
106 2
        $map = $this->map;
107 2
        foreach ($enumerators as $enumerator) {
108 2
            $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
109 2
            unset($map[$ord]);
110
        }
111
112 2
        $this->map = $map;
113 2
    }
114
115
    /* write access (immutable) */
116
117
    /**
118
     * Creates a new map with the given enumerator (object or value) mapping to the specified data value added.
1 ignored issue
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 111 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
119
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
120
     * @param mixed                                 $value
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
121
     * @return static
122
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
123
     */
124 1
    public function with($enumerator, $value): self
125
    {
126 1
        $clone = clone $this;
127 1
        $clone->add($enumerator, $value);
128 1
        return $clone;
129
    }
130
131
    /**
132
     * Creates a new map with the given iterable mapping enumerators (objects or values) to data values added.
1 ignored issue
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 110 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
133
     * @param iterable $map
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
134
     * @return static
135
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
136
     */
137 1
    public function withIterable(iterable $map): self
138
    {
139 1
        $clone = clone $this;
140 1
        $clone->addIterable($map);
141 1
        return $clone;
142
    }
143
144
    /**
145
     * Create a new map with the given enumerator mapping removed.
146
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
147
     * @return static
148
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
149
     */
150 1
    public function without($enumerator): self
151
    {
152 1
        $clone = clone $this;
153 1
        $clone->remove($enumerator);
154 1
        return $clone;
155
    }
156
157
    /**
158
     * Creates a new map with the given iterable enumerator (object or value) mappings removed.
159
     * @param iterable $enumerators
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
160
     * @return static
161
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
162
     */
163 1
    public function withoutIterable(iterable $enumerators): self
164
    {
165 1
        $clone = clone $this;
166 1
        $clone->removeIterable($enumerators);
167 1
        return $clone;
168
    }
169
170
    /* read access */
171
172
    /**
173
     * Get the classname of the enumeration type.
174
     * @return string
175
     */
176 1
    public function getEnumeration(): string
177
    {
178 1
        return $this->enumeration;
179
    }
180
181
    /**
182
     * Get the mapped data value of the given enumerator (object or value).
183
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
184
     * @return mixed
185
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
186
     * @throws UnexpectedValueException If the given enumerator does not exist in this map
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
187
     * @see offsetGet()
188
     */
189 10
    public function get($enumerator)
190
    {
191 10
        $enumerator = ($this->enumeration)::get($enumerator);
192 10
        $ord = $enumerator->getOrdinal();
193 10
        if (!\array_key_exists($ord, $this->map)) {
194 2
            throw new UnexpectedValueException(sprintf(
195 2
                'Enumerator %s could not be found',
196 2
                \var_export($enumerator->getValue(), true)
197
            ));
198
        }
199
200 8
        return $this->map[$ord];
201
    }
202
203
    /**
204
     * Get a list of enumerator keys.
205
     * @return Enum[]
206
     */
207 7
    public function getKeys(): array
208
    {
209 7
        return \array_map([$this->enumeration, 'byOrdinal'], \array_keys($this->map));
210
    }
211
212
    /**
213
     * Get a list of mapped data values.
214
     * @return mixed[]
215
     */
216 7
    public function getValues(): array
217
    {
218 7
        return \array_values($this->map);
219
    }
220
221
    /**
222
     * Search for the given data value.
223
     * @param mixed $value
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
224
     * @param bool $strict Use strict type comparison
2 ignored issues
show
Coding Style introduced by
Expected "boolean" but found "bool" for parameter type
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
introduced by
Parameter comment must end with a full stop
Loading history...
225
     * @return Enum|null The enumerator object of the first matching data value or NULL
226
     */
227 2
    public function search($value, bool $strict = false)
2 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$strict" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$strict"; expected 0 but found 1
Loading history...
228
    {
229 2
        $ord = \array_search($value, $this->map, $strict);
230 2
        if ($ord !== false) {
231 2
            return ($this->enumeration)::byOrdinal($ord);
232
        }
233
234 2
        return null;
235
    }
236
237
    /**
238
     * Test if the given enumerator key (object or value) exists.
239
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
240
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
241
     * @see offsetExists()
242
     */
243 8
    public function has($enumerator): bool
244
    {
245
        try {
246 8
            $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
247 7
            return \array_key_exists($ord, $this->map);
248 1
        } catch (InvalidArgumentException $e) {
249
            // An invalid enumerator can't be contained in this map
250 1
            return false;
251
        }
252
    }
253
254
    /**
255
     * Test if the given enumerator key (object or value) exists.
256
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
257
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
258
     * @see offsetExists()
259
     * @see has()
260
     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
261
     */
262 1
    public function contains($enumerator): bool
263
    {
264 1
        return $this->has($enumerator);
265
    }
266
267
    /* ArrayAccess */
268
269
    /**
270
     * Test if the given enumerator key (object or value) exists and is not NULL
271
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
272
     * @return bool
1 ignored issue
show
Coding Style introduced by
Expected "boolean" but found "bool" for function return type
Loading history...
273
     * @see contains()
274
     */
275 5
    public function offsetExists($enumerator): bool
276
    {
277
        try {
278 5
            return isset($this->map[($this->enumeration)::get($enumerator)->getOrdinal()]);
279 1
        } catch (InvalidArgumentException $e) {
280
            // An invalid enumerator can't be an offset of this map
281 1
            return false;
282
        }
283
    }
284
285
    /**
286
     * Get the mapped data value of the given enumerator (object or value).
287
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
288
     * @return mixed The mapped date value of the given enumerator or NULL
289
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
290
     * @see get()
291
     */
292 4
    public function offsetGet($enumerator)
293
    {
294
        try {
295 4
            return $this->get($enumerator);
296 1
        } catch (UnexpectedValueException $e) {
297 1
            return null;
298
        }
299
    }
300
301
    /**
302
     * Adds the given enumerator (object or value) mapping to the specified data value.
303
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
304
     * @param mixed                                 $value
0 ignored issues
show
Documentation introduced by
Missing parameter comment
Loading history...
305
     * @return void
306
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
307
     * @see add()
308
     */
309 7
    public function offsetSet($enumerator, $value = null): void
2 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$value" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$value"; expected 0 but found 1
Loading history...
310
    {
311 7
        $this->add($enumerator, $value);
312 6
    }
313
314
    /**
315
     * Removes the given enumerator (object or value) mapping.
316
     * @param Enum|null|bool|int|float|string|array $enumerator
1 ignored issue
show
Documentation introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected "Enum|null|boolean|integer|float|string|array" but found "Enum|null|bool|int|float|string|array" for parameter type
Loading history...
317
     * @return void
318
     * @throws InvalidArgumentException On an invalid given enumerator
0 ignored issues
show
introduced by
@throws tag comment must end with a full stop
Loading history...
319
     * @see remove()
320
     */
321 2
    public function offsetUnset($enumerator): void
322
    {
323 2
        $this->remove($enumerator);
324 2
    }
325
326
    /* IteratorAggregate */
327
328
    /**
329
     * Get a new Iterator.
330
     *
331
     * @return Iterator Iterator<K extends Enum, V>
332
     */
333 2
    public function getIterator(): Iterator
334
    {
335 2
        $map = $this->map;
336 2
        foreach ($map as $ordinal => $value) {
337 2
            yield ($this->enumeration)::byOrdinal($ordinal) => $value;
338
        }
339 2
    }
340
341
    /* Countable */
342
343
    /**
344
     * Count the number of elements
345
     *
346
     * @return int
1 ignored issue
show
Coding Style introduced by
Expected "integer" but found "int" for function return type
Loading history...
347
     */
348 3
    public function count(): int
349
    {
350 3
        return \count($this->map);
351
    }
352
}
353