Completed
Push — refactor_EnumMap ( 436164 )
by Marc
01:27
created

EnumMap::contains()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 1
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace MabeEnum;
4
5
use ArrayAccess;
6
use Countable;
7
use InvalidArgumentException;
8
use Iterator;
9
use UnexpectedValueException;
10
11
/**
12
 * A map of enumerators (EnumMap<T>) and mixed values.
13
 *
14
 * @link http://github.com/marc-mabe/php-enum for the canonical source repository
15
 * @copyright Copyright (c) 2017 Marc Bennewitz
16
 * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
17
 */
18
class EnumMap implements ArrayAccess, Countable, Iterator
19
{
20
    /**
21
     * The classname of the enumeration type
22
     * @var string
23
     */
24
    private $enumeration;
25
26
    /**
27
     * Internal map of ordinal number and value
28
     * @var array
29
     */
30
    private $map = [];
31
32
    /**
33
     * List of ordinal numbers
34
     * @var int[]
35
     */
36
    private $ordinals = [];
37
38
    /**
39
     * Current iterator position
40
     * @var int
41
     */
42
    private $pos = 0;
43
44
    /**
45
     * Constructor
46
     * @param string $enumeration The classname of the enumeration type
47
     * @throws InvalidArgumentException
48
     */
49 18
    public function __construct($enumeration)
50
    {
51 18
        if (!is_subclass_of($enumeration, Enum::class)) {
52 2
            throw new InvalidArgumentException(sprintf(
53 2
                "This EnumMap can handle subclasses of '%s' only",
54 2
                Enum::class
55
            ));
56
        }
57 16
        $this->enumeration = $enumeration;
58 16
    }
59
60
    /**
61
     * Get the classname of the enumeration
62
     * @return string
63
     */
64 2
    public function getEnumeration()
65
    {
66 2
        return $this->enumeration;
67
    }
68
69
    /**
70
     * Attach a new enumerator or overwrite an existing one
71
     * @param Enum|null|boolean|int|float|string $enumerator
72
     * @param mixed                              $data
73
     * @return void
74
     * @throws InvalidArgumentException On an invalid given enumerator
75
     */
76 6
    public function attach($enumerator, $data = null)
77
    {
78 6
        return $this->offsetSet($enumerator, $data);
79
    }
80
81
    /**
82
     * Test if the given enumerator exists
83
     * @param Enum|null|boolean|int|float|string $enumerator
84
     * @return boolean
85
     */
86 6
    public function contains($enumerator)
87
    {
88 6
        return $this->offsetExists($enumerator);
89
    }
90
91
    /**
92
     * Detach an enumerator
93
     * @param Enum|null|boolean|int|float|string $enumerator
94
     * @return void
95
     * @throws InvalidArgumentException On an invalid given enumerator
96
     */
97 4
    public function detach($enumerator)
98
    {
99 4
        $this->offsetUnset($enumerator);
100 4
    }
101
102
    /**
103
     * Test if the given enumerator exists
104
     * @param Enum|null|boolean|int|float|string $enumerator
105
     * @return boolean
106
     * @see contains()
107
     */
108 12
    public function offsetExists($enumerator)
109
    {
110
        try {
111 12
            $enumeration = $this->enumeration;
112 12
            $ord  = $enumeration::get($enumerator)->getOrdinal();
113 10
            return isset($this->map[$ord]);
114 2
        } catch (InvalidArgumentException $e) {
115
            // On an InvalidArgumentException the given argument can't be contained in this map
116 2
            return false;
117
        }
118
    }
119
120
    /**
121
     * Get mapped data for the given enumerator
122
     * @param Enum|null|boolean|int|float|string $enumerator
123
     * @return mixed
124
     * @throws InvalidArgumentException On an invalid given enumerator
125
     */
126 8
    public function offsetGet($enumerator)
127
    {
128 8
        $enumeration = $this->enumeration;
129 8
        $ord = $enumeration::get($enumerator)->getOrdinal();
130 8
        if (!isset($this->map[$ord])) {
131
            throw new UnexpectedValueException(sprintf(
132
                "Enumerator '%s' could not be found",
133
                is_object($enumerator) ? $enumerator->getValue() : $enumerator
134
            ));
135
        }
136
137 8
        return $this->map[$ord];
138
    }
139
140
    /**
141
     * Attach a new enumerator or overwrite an existing one
142
     * @param Enum|null|boolean|int|float|string $enumerator
143
     * @param mixed                              $data
144
     * @return void
145
     * @throws InvalidArgumentException On an invalid given enumerator
146
     * @see attach()
147
     */
148 14
    public function offsetSet($enumerator, $data = null)
149
    {
150 14
        $enumeration = $this->enumeration;
151 14
        $ord = $enumeration::get($enumerator)->getOrdinal();
152
153 12
        if (!isset($this->map[$ord])) {
154 12
            $this->ordinals[] = $ord;
155
        }
156 12
        $this->map[$ord] = $data;
157 12
    }
158
159
    /**
160
     * Detach an existing enumerator
161
     * @param Enum|null|boolean|int|float|string $enumerator
162
     * @return void
163
     * @throws InvalidArgumentException On an invalid given enumerator
164
     * @see detach()
165
     */
166 8
    public function offsetUnset($enumerator)
167
    {
168 8
        $enumeration = $this->enumeration;
169 8
        $ord = $enumeration::get($enumerator)->getOrdinal();
170
171 8
        if (($idx = array_search($ord, $this->ordinals, true)) !== false) {
172 8
            unset($this->map[$ord]);
173 8
            unset($this->ordinals[$idx]);
174
        }
175 8
    }
176
177
    /**
178
     * Get the current value
179
     * @return mixed
180
     */
181 2
    public function current()
182
    {
183 2
        if (!isset($this->ordinals[$this->pos])) {
184
            return null;
185
        }
186
187 2
        return $this->map[$this->ordinals[$this->pos]];
188
    }
189
190
    /**
191
     * Get the current key
192
     * @return Enum|null
193
     */
194 4
    public function key()
195
    {
196 4
        if (!isset($this->ordinals[$this->pos])) {
197 2
            return null;
198
        }
199
200 4
        $enumeration = $this->enumeration;
201 4
        return $enumeration::byOrdinal($this->ordinals[$this->pos]);
202
    }
203
204
    /**
205
     * Reset the iterator position to zero.
206
     * @return void
207
     */
208 2
    public function rewind()
209
    {
210 2
        $this->pos = 0;
211 2
    }
212
213
    /**
214
     * Increment the iterator position by one.
215
     * @return void
216
     */
217 2
    public function next()
218
    {
219 2
        ++$this->pos;
220 2
    }
221
222
    /**
223
     * Test if the iterator is in a valid state
224
     * @return boolean
225
     */
226 2
    public function valid()
227
    {
228 2
        return isset($this->ordinals[$this->pos]);
229
    }
230
231
    /**
232
     * Count the number of elements
233
     *
234
     * @return int
235
     */
236 2
    public function count()
237
    {
238 2
        return count($this->ordinals);
239
    }
240
}
241