Skip to content

Commit d9c3229

Browse files
author
Marc Bennewitz
committed
Merge pull request #20 from marc-mabe/feature/EnumSet
implemented EnumSet - fixed #5
2 parents 58d6533 + d392f07 commit d9c3229

File tree

2 files changed

+461
-0
lines changed

2 files changed

+461
-0
lines changed

src/MabeEnum/EnumSet.php

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<?php
2+
3+
namespace MabeEnum;
4+
5+
use Iterator;
6+
use Countable;
7+
use InvalidArgumentException;
8+
use RuntimeException;
9+
10+
/**
11+
* EnumSet implementation in base of SplObjectStorage
12+
*
13+
* @link http://github.com/marc-mabe/php-enum for the canonical source repository
14+
* @copyright Copyright (c) 2012 Marc Bennewitz
15+
* @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
16+
*/
17+
class EnumSet implements Iterator, Countable
18+
{
19+
/**
20+
* Flag for a unique set of enumerations
21+
*/
22+
const UNIQUE = 1;
23+
24+
/**
25+
* Flag for an ordered set of enumerations by ordinal
26+
*/
27+
const ORDERED = 2;
28+
29+
private $enumClass;
30+
private $list = array();
31+
private $index = 0;
32+
private $flags = self::UNIQUE;
33+
34+
/**
35+
* Constructor
36+
* @param string $enumClass The classname of an enumeration the map is for
37+
* @param null|int $flags Flags to define behaviours
38+
*/
39+
public function __construct($enumClass, $flags = null)
40+
{
41+
if (!is_subclass_of($enumClass, __NAMESPACE__ . '\Enum')) {
42+
throw new InvalidArgumentException(sprintf(
43+
"This EnumMap can handle subclasses of '%s' only",
44+
__NAMESPACE__ . '\Enum'
45+
));
46+
}
47+
$this->enumClass = $enumClass;
48+
49+
if ($flags !== null) {
50+
$this->flags = (int) $flags;
51+
}
52+
}
53+
54+
/**
55+
* Get the classname of enumeration this map is for
56+
* @return string
57+
*/
58+
public function getEnumClass()
59+
{
60+
return $this->enumClass;
61+
}
62+
63+
/**
64+
* Get flags of defined behaviours
65+
* @return int
66+
*/
67+
public function getFlags()
68+
{
69+
return $this->flags;
70+
}
71+
72+
/**
73+
* Attach a new enumeration or overwrite an existing one
74+
* @param Enum|scalar $enum
75+
* @param mixed $data
76+
* @return void
77+
* @throws InvalidArgumentException On an invalid given enum
78+
*/
79+
public function attach($enum, $data = null)
80+
{
81+
$this->initEnum($enum);
82+
$ordinal = $enum->getOrdinal();
83+
84+
if (!($this->flags & self::UNIQUE) || !in_array($ordinal, $this->list, true)) {
85+
$this->list[] = $ordinal;
86+
87+
if ($this->flags & self::ORDERED) {
88+
sort($this->list);
89+
}
90+
}
91+
}
92+
93+
/**
94+
* Test if the given enumeration exists
95+
* @param Enum|scalar $enum
96+
* @return boolean
97+
*/
98+
public function contains($enum)
99+
{
100+
$this->initEnum($enum);
101+
return in_array($enum->getOrdinal(), $this->list, true);
102+
}
103+
104+
/**
105+
* Detach all enumerations same as the given enum
106+
* @param Enum|scalar $enum
107+
* @return void
108+
* @throws InvalidArgumentException On an invalid given enum
109+
*/
110+
public function detach($enum)
111+
{
112+
$this->initEnum($enum);
113+
114+
while (($index = array_search($enum->getOrdinal(), $this->list, true)) !== false) {
115+
unset($this->list[$index]);
116+
}
117+
118+
// reset index positions to have a real list
119+
$this->list = array_values($this->list);
120+
}
121+
122+
/* Iterator */
123+
124+
/**
125+
* Get the current Enum
126+
* @return Enum|null Returns the current Enum or NULL on an invalid iterator position
127+
*/
128+
public function current()
129+
{
130+
if (!isset($this->list[$this->index])) {
131+
return null;
132+
}
133+
134+
$enumClass = $this->enumClass;
135+
return $enumClass::getByOrdinal($this->list[$this->index]);
136+
}
137+
138+
/**
139+
* Get the current iterator position
140+
* @return int
141+
*/
142+
public function key()
143+
{
144+
return $this->index;
145+
}
146+
147+
public function next()
148+
{
149+
++$this->index;
150+
}
151+
152+
public function rewind()
153+
{
154+
$this->index = 0;
155+
}
156+
157+
public function valid()
158+
{
159+
return isset($this->list[$this->index]);
160+
}
161+
162+
/* Countable */
163+
164+
public function count()
165+
{
166+
return count($this->list);
167+
}
168+
169+
/**
170+
* Initialize an enumeration
171+
* @param Enum|scalar $enum
172+
* @return Enum
173+
* @throws InvalidArgumentException On an invalid given enum
174+
*/
175+
private function initEnum(&$enum)
176+
{
177+
// auto instantiate
178+
if (is_scalar($enum)) {
179+
$enumClass = $this->enumClass;
180+
$enum = $enumClass::get($enum);
181+
return;
182+
}
183+
184+
// allow only enums of the same type
185+
// (don't allow instance of)
186+
$enumClass = get_class($enum);
187+
if ($enumClass && strcasecmp($enumClass, $this->enumClass) === 0) {
188+
return;
189+
}
190+
191+
throw new InvalidArgumentException(sprintf(
192+
"The given enum of type '%s' isn't same as the required type '%s'",
193+
get_class($enum) ?: gettype($enum),
194+
$this->enumClass
195+
));
196+
}
197+
}

0 commit comments

Comments
 (0)