Completed
Push — master ( 9803f7...848250 )
by Marc
01:37
created

EnumMap::offsetExists()   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 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace MabeEnum;
4
5
use SplObjectStorage;
6
use InvalidArgumentException;
7
use RuntimeException;
8
9
/**
10
 * EnumMap implementation in base of SplObjectStorage
11
 *
12
 * @link http://github.com/marc-mabe/php-enum for the canonical source repository
13
 * @copyright Copyright (c) 2015 Marc Bennewitz
14
 * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
15
 */
16
class EnumMap extends SplObjectStorage
17
{
18
19
    /**
20
     * key()-behaviour: return the iterator position
21
     */
22
    const KEY_AS_INDEX   = 1;
23
24
    /**
25
     * key()-behaviour: return the name of the current element
26
     */
27
    const KEY_AS_NAME    = 2;
28
29
    /**
30
     * key()-behaviour: return the value of the current element
31
     */
32
    const KEY_AS_VALUE   = 3;
33
34
    /**
35
     * key()-behaviour: return the ordinal number of the current element
36
     */
37
    const KEY_AS_ORDINAL = 4;
38
39
    /**
40
     * current()-behaviour: return the instance of the enumerator
41
     */
42
    const CURRENT_AS_ENUM    = 8;
43
44
    /**
45
     * current()-behaviour: return the data mapped the enumerator
46
     */
47
    const CURRENT_AS_DATA    = 16;
48
49
    /**
50
     * current()-behaviour: return the name of the enumerator
51
     */
52
    const CURRENT_AS_NAME    = 24;
53
54
    /**
55
     * current()-behaviour: return the value of the enumerator
56
     */
57
    const CURRENT_AS_VALUE   = 32;
58
59
    /**
60
     * current()-behaviour: return the ordinal number of the enumerator
61
     */
62
    const CURRENT_AS_ORDINAL = 40;
63
64
    /**
65
     * The classname of the enumeration type
66
     * @var string
67
     */
68
    private $enumeration;
69
70
    /**
71
     * Flags to define behaviors
72
     * (Default = KEY_AS_INDEX | CURRENT_AS_ENUM)
73
     * @var int
74
     */
75
    private $flags = 9;
76
77
    /**
78
     * Constructor
79
     * @param string   $enumeration The classname of the enumeration type
80
     * @param int|null $flags       Behaviour flags, see KEY_AS_* and CURRENT_AS_* constants
81
     * @throws InvalidArgumentException
82
     */
83 13
    public function __construct($enumeration, $flags = null)
84
    {
85 13 View Code Duplication
        if (!is_subclass_of($enumeration, __NAMESPACE__ . '\Enum')) {
86 1
            throw new InvalidArgumentException(sprintf(
87 1
                "This EnumMap can handle subclasses of '%s' only",
88
                __NAMESPACE__ . '\Enum'
89 1
            ));
90
        }
91 12
        $this->enumeration = $enumeration;
92
93 12
        if ($flags !== null) {
94 1
            $this->setFlags($flags);
95 1
        }
96 12
    }
97
98
    /**
99
     * Get the classname of the enumeration
100
     * @return string
101
     */
102 1
    public function getEnumeration()
103
    {
104 1
        return $this->enumeration;
105
    }
106
107
    /**
108
     * Set behaviour flags
109
     * see KEY_AS_* and CURRENT_AS_* constants
110
     * @param int $flags
111
     * @return void
112
     * @throws InvalidArgumentException On invalid or unsupported flags
113
     */
114 3
    public function setFlags($flags)
115
    {
116 3
        $flags = (int)$flags;
117
118 3
        $keyFlag = $flags & 7;
119 3
        if ($keyFlag > 4) {
120 1
            throw new InvalidArgumentException(
121
                "Unsupported flag given for key() behavior"
122 1
            );
123 2
        } elseif (!$keyFlag) {
124 2
            $keyFlag = $this->flags & 7;
125 2
        }
126
127 2
        $currentFlag = $flags & 56;
128 2
        if ($currentFlag > 40) {
129 1
            throw new InvalidArgumentException(
130
                "Unsupported flag given for current() behavior"
131 1
            );
132 1
        } elseif (!$currentFlag) {
133 1
            $currentFlag = $this->flags & 56;
134 1
        }
135
136 1
        $this->flags = $keyFlag | $currentFlag;
137 1
    }
138
139
    /**
140
     * Get the behaviour flags
141
     * @return int
142
     */
143 1
    public function getFlags()
144
    {
145 1
        return $this->flags;
146
    }
147
148
    /**
149
     * Attach a new enumerator or overwrite an existing one
150
     * @param Enum|null|boolean|int|float|string $enumerator
151
     * @param mixed                              $data
152
     * @return void
153
     * @throws InvalidArgumentException On an invalid given enumerator
154
     */
155 6
    public function attach($enumerator, $data = null)
156
    {
157 6
        $enumeration = $this->enumeration;
158 6
        parent::attach($enumeration::get($enumerator), $data);
159 6
    }
160
161
    /**
162
     * Test if the given enumerator exists
163
     * @param Enum|null|boolean|int|float|string $enumerator
164
     * @return boolean
165
     */
166 5
    public function contains($enumerator)
167
    {
168
        try {
169 5
            $enumeration = $this->enumeration;
170 5
            return parent::contains($enumeration::get($enumerator));
171 1
        } catch (InvalidArgumentException $e) {
172
            // On an InvalidArgumentException the given argument can't be contained in this map
173 1
            return false;
174
        }
175
    }
176
177
    /**
178
     * Detach an enumerator
179
     * @param Enum|null|boolean|int|float|string $enumerator
180
     * @return void
181
     * @throws InvalidArgumentException On an invalid given enumerator
182
     */
183 2
    public function detach($enumerator)
184
    {
185 2
        $enumeration = $this->enumeration;
186 2
        parent::detach($enumeration::get($enumerator));
187 2
    }
188
189
    /**
190
     * Get a unique identifier for the given enumerator
191
     * @param Enum|scalar $enumerator
192
     * @return string
193
     * @throws InvalidArgumentException On an invalid given enumerator
194
     */
195 8
    public function getHash($enumerator)
196
    {
197
        // getHash is available since PHP 5.4
198 8
        $enumeration = $this->enumeration;
199 8
        return spl_object_hash($enumeration::get($enumerator));
200
    }
201
202
    /**
203
     * Test if the given enumerator exists
204
     * @param Enum|null|boolean|int|float|string $enumerator
205
     * @return boolean
206
     * @see contains()
207
     */
208 3
    public function offsetExists($enumerator)
209
    {
210 3
        return $this->contains($enumerator);
211
    }
212
213
    /**
214
     * Get mapped data for the given enumerator
215
     * @param Enum|null|boolean|int|float|string $enumerator
216
     * @return mixed
217
     * @throws InvalidArgumentException On an invalid given enumerator
218
     */
219 4
    public function offsetGet($enumerator)
220
    {
221 4
        $enumeration = $this->enumeration;
222 4
        return parent::offsetGet($enumeration::get($enumerator));
223
    }
224
225
    /**
226
     * Attach a new enumerator or overwrite an existing one
227
     * @param Enum|null|boolean|int|float|string $enumerator
228
     * @param mixed                              $data
229
     * @return void
230
     * @throws InvalidArgumentException On an invalid given enumerator
231
     * @see attach()
232
     */
233 3
    public function offsetSet($enumerator, $data = null)
234
    {
235 3
        $enumeration = $this->enumeration;
236 3
        parent::offsetSet($enumeration::get($enumerator), $data);
237 2
    }
238
239
    /**
240
     * Detach an existing enumerator
241
     * @param Enum|null|boolean|int|float|string $enumerator
242
     * @return void
243
     * @throws InvalidArgumentException On an invalid given enumerator
244
     * @see detach()
245
     */
246 2
    public function offsetUnset($enumerator)
247
    {
248 2
        $enumeration = $this->enumeration;
249 2
        parent::offsetUnset($enumeration::get($enumerator));
250 2
    }
251
252
    /**
253
     * Get the current item
254
     * The return value varied by the behaviour of the current flag
255
     * @return mixed
256
     */
257 3 View Code Duplication
    public function current()
258
    {
259 3
        switch ($this->flags & 120) {
260 3
            case self::CURRENT_AS_ENUM:
261 2
                return parent::current();
262 2
            case self::CURRENT_AS_DATA:
263 1
                return parent::getInfo();
264 2
            case self::CURRENT_AS_VALUE:
265 1
                return parent::current()->getValue();
266 2
            case self::CURRENT_AS_NAME:
267 1
                return parent::current()->getName();
268 2
            case self::CURRENT_AS_ORDINAL:
269 1
                return parent::current()->getOrdinal();
270 1
            default:
271 1
                throw new RuntimeException('Invalid current flag');
272 1
        }
273
    }
274
275
    /**
276
     * Get the current item-key
277
     * The return value varied by the behaviour of the key flag
278
     * @return null|boolean|int|float|string
279
     */
280 3 View Code Duplication
    public function key()
281
    {
282 3
        switch ($this->flags & 7) {
283 3
            case self::KEY_AS_INDEX:
284 2
                return parent::key();
285 2
            case self::KEY_AS_NAME:
286 1
                return parent::current()->getName();
287 2
            case self::KEY_AS_ORDINAL:
288 1
                return parent::current()->getOrdinal();
289 2
            case self::KEY_AS_VALUE:
290 1
                return parent::current()->getValue();
291 1
            default:
292 1
                throw new RuntimeException('Invalid key flag');
293 1
        }
294
    }
295
}
296