[CLEANUP] Polish Enumeration exceptions
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Type / Enumeration.php
1 <?php
2 namespace TYPO3\CMS\Core\Type;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Abstract class for Enumeration.
19 * Inspired by SplEnum.
20 *
21 * The prefix "Abstract" has been left out by intention because
22 * a "type" is abstract by definition.
23 */
24 abstract class Enumeration implements TypeInterface
25 {
26 /**
27 * @var mixed
28 */
29 protected $value;
30
31 /**
32 * @var array
33 */
34 protected static $enumConstants;
35
36 /**
37 * @param mixed $value
38 * @throws Exception\InvalidEnumerationValueException
39 */
40 public function __construct($value = null)
41 {
42 if ($value === null && !defined('static::__default')) {
43 throw new Exception\InvalidEnumerationValueException(
44 sprintf('A value for enumeration "%s" is required if no __default is defined.', get_class($this)),
45 1381512753
46 );
47 }
48 if ($value === null) {
49 $value = static::__default;
50 }
51 static::loadValues();
52 if (!$this->isValid($value)) {
53 throw new Exception\InvalidEnumerationValueException(
54 sprintf('Invalid value "%s" for enumeration "%s"', $value, get_class($this)),
55 1381512761
56 );
57 }
58 $this->setValue($value);
59 }
60
61 /**
62 * @throws Exception\InvalidEnumerationValueException
63 * @throws Exception\InvalidEnumerationDefinitionException
64 * @internal param string $class
65 */
66 protected static function loadValues()
67 {
68 $class = get_called_class();
69
70 if (isset(static::$enumConstants[$class])) {
71 return;
72 }
73
74 $reflection = new \ReflectionClass($class);
75 $constants = $reflection->getConstants();
76 $defaultValue = null;
77 if (isset($constants['__default'])) {
78 $defaultValue = $constants['__default'];
79 unset($constants['__default']);
80 }
81 if (empty($constants)) {
82 throw new Exception\InvalidEnumerationValueException(
83 sprintf(
84 'No constants defined in enumeration "%s"', $class
85 ),
86 1381512807
87 );
88 }
89 foreach ($constants as $constant => $value) {
90 if (!is_int($value) && !is_string($value)) {
91 throw new Exception\InvalidEnumerationDefinitionException(
92 sprintf(
93 'Constant value "%s" of enumeration "%s" must be of type integer or string, got "%s" instead',
94 $constant,
95 $class,
96 is_object($value) ? get_class($value) : gettype($value)
97 ),
98 1381512797
99 );
100 }
101 }
102 $constantValueCounts = array_count_values($constants);
103 arsort($constantValueCounts, SORT_NUMERIC);
104 $constantValueCount = current($constantValueCounts);
105 $constant = key($constantValueCounts);
106 if ($constantValueCount > 1) {
107 throw new Exception\InvalidEnumerationDefinitionException(
108 sprintf(
109 'Constant value "%s" of enumeration "%s" is not unique (defined %d times)',
110 $constant,
111 $class,
112 $constantValueCount
113 ),
114 1381512859
115 );
116 }
117 if ($defaultValue !== null) {
118 $constants['__default'] = $defaultValue;
119 }
120 static::$enumConstants[$class] = $constants;
121 }
122
123 /**
124 * Set the Enumeration value to the associated enumeration value by a loose comparison.
125 * The value, that is used as the enumeration value, will be of the same type like defined in the enumeration
126 *
127 * @param mixed $value
128 * @throws Exception\InvalidEnumerationValueException
129 */
130 protected function setValue($value)
131 {
132 $enumKey = array_search($value, static::$enumConstants[get_class($this)]);
133 if ($enumKey === false) {
134 throw new Exception\InvalidEnumerationValueException(
135 sprintf('Invalid value "%s" for enumeration "%s"', $value, __CLASS__),
136 1381615295
137 );
138 }
139 $this->value = static::$enumConstants[get_class($this)][$enumKey];
140 }
141
142 /**
143 * Check if the value on this enum is a valid value for the enum
144 *
145 * @param mixed $value
146 * @return bool
147 */
148 protected function isValid($value)
149 {
150 $value = (string)$value;
151 foreach (static::$enumConstants[get_class($this)] as $constantValue) {
152 if ($value === (string)$constantValue) {
153 return true;
154 }
155 }
156 return false;
157 }
158
159 /**
160 * Get the valid values for this enum
161 * Defaults to constants you define in your subclass
162 * override to provide custom functionality
163 *
164 * @param bool $include_default
165 * @return array
166 */
167 public static function getConstants($include_default = false)
168 {
169 static::loadValues();
170 $enumConstants = static::$enumConstants[get_called_class()];
171 if (!$include_default) {
172 unset($enumConstants['__default']);
173 }
174 return $enumConstants;
175 }
176
177 /**
178 * Cast value to enumeration type
179 *
180 * @param mixed $value Value that has to be casted
181 * @return self
182 */
183 public static function cast($value)
184 {
185 $currentClass = get_called_class();
186 if (!is_object($value) || get_class($value) !== $currentClass) {
187 $value = new $currentClass($value);
188 }
189 return $value;
190 }
191
192 /**
193 * Compare if the value of the current object value equals the given value
194 *
195 * @param mixed $value default
196 * @return bool
197 */
198 public function equals($value)
199 {
200 $value = static::cast($value);
201 return $this == $value;
202 }
203
204 /**
205 * @return string
206 */
207 public function __toString()
208 {
209 return (string)$this->value;
210 }
211 }