Skip to content

Commit fba38bb

Browse files
author
Cas Leentfaar
committed

File tree

1 file changed

+145
-63
lines changed

1 file changed

+145
-63
lines changed

src/Symfony/Component/OptionsResolver/Options.php

Lines changed: 145 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,45 @@
2323
*/
2424
class Options implements \ArrayAccess, \Iterator, \Countable
2525
{
26+
/**
27+
* Whether to format {@link \DateTime} objects as RFC-3339 dates
28+
* during exceptions ("Y-m-d H:i:s").
29+
*
30+
* @var int
31+
*/
32+
const PRETTY_DATE = 1;
33+
34+
/**
35+
* Whether to cast objects with a "__toString()" method to strings.
36+
*
37+
* @var int
38+
*/
39+
const OBJECT_TO_STRING = 2;
40+
2641
/**
2742
* A list of option values.
43+
*
2844
* @var array
2945
*/
3046
private $options = array();
3147

3248
/**
3349
* A list of normalizer closures.
50+
*
3451
* @var array
3552
*/
3653
private $normalizers = array();
3754

3855
/**
3956
* A list of closures for evaluating lazy options.
57+
*
4058
* @var array
4159
*/
4260
private $lazy = array();
4361

4462
/**
4563
* A list containing the currently locked options.
64+
*
4665
* @var array
4766
*/
4867
private $lock = array();
@@ -155,7 +174,7 @@ public static function validateNames(array $options, $acceptedOptions, $namesAsK
155174
ksort($diff);
156175

157176
throw new InvalidOptionsException(sprintf(
158-
(count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Known options are: "%s"',
177+
(count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.') . ' Known options are: "%s"',
159178
implode('", "', array_keys($diff)),
160179
implode('", "', array_keys($acceptedOptions))
161180
));
@@ -228,11 +247,11 @@ public static function validateTypes(array $options, array $acceptedTypes)
228247
continue;
229248
}
230249

231-
$value = $options[$option];
250+
$value = $options[$option];
232251
$optionTypes = (array) $optionTypes;
233252

234253
foreach ($optionTypes as $type) {
235-
$isFunction = 'is_'.$type;
254+
$isFunction = 'is_' . $type;
236255

237256
if (function_exists($isFunction) && $isFunction($value)) {
238257
continue 2;
@@ -244,61 +263,12 @@ public static function validateTypes(array $options, array $acceptedTypes)
244263
throw new InvalidOptionsException(sprintf(
245264
'The option "%s" with value "%s" is expected to be of type "%s"',
246265
$option,
247-
self::createPrintableValue($value),
248-
implode('", "', array_map(function ($optionType) { return self::createPrintableType($optionType); }, $optionTypes))
266+
self::formatValue($value),
267+
implode('", "', self::formatTypesOf($optionTypes))
249268
));
250269
}
251270
}
252271

253-
/**
254-
* Attempts to convert a given value into a (short) string or integer.
255-
*
256-
* @param mixed $value The value to convert.
257-
*
258-
* @return string The printable value.
259-
*/
260-
private static function createPrintableValue($value)
261-
{
262-
if (is_object($value)) {
263-
return get_class($value);
264-
}
265-
266-
if (is_array($value)) {
267-
return 'Array';
268-
}
269-
270-
if (null === $value) {
271-
return 'null';
272-
}
273-
274-
if (is_string($value)) {
275-
return '"'.$value.'"';
276-
}
277-
278-
if (is_bool($value)) {
279-
return (string) var_export($value, true);
280-
}
281-
282-
return (string) $value;
283-
}
284-
285-
/**
286-
* Attempts to convert a given value's type into a printable string.
287-
*
288-
* @param mixed $value The value to convert.
289-
*
290-
* @return string Objects get returned as their classname,
291-
* all other values are put through gettype().
292-
*/
293-
private static function createPrintableType($value)
294-
{
295-
if (is_object($value)) {
296-
return get_class($value);
297-
} else {
298-
return gettype($value);
299-
}
300-
}
301-
302272
/**
303273
* Validates that the given option values match the accepted values and
304274
* throws an exception otherwise.
@@ -318,7 +288,7 @@ public static function validateValues(array $options, array $acceptedValues)
318288
foreach ($acceptedValues as $option => $optionValues) {
319289
if (array_key_exists($option, $options)) {
320290
if (is_array($optionValues) && !in_array($options[$option], $optionValues, true)) {
321-
throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $optionValues)));
291+
throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', self::formatValues($optionValues))));
322292
}
323293

324294
if (is_callable($optionValues) && !call_user_func($optionValues, $options[$option])) {
@@ -328,6 +298,118 @@ public static function validateValues(array $options, array $acceptedValues)
328298
}
329299
}
330300

301+
/**
302+
* Returns a string representation of the type of the value.
303+
*
304+
* @param mixed $value
305+
*
306+
* @return string
307+
*/
308+
private static function formatTypeOf($value)
309+
{
310+
return is_object($value) ? get_class($value) : gettype($value);
311+
}
312+
313+
/**
314+
* @param array $optionTypes
315+
*
316+
* @return array
317+
*/
318+
private static function formatTypesOf(array $optionTypes)
319+
{
320+
return array_map(function ($optionType) {
321+
return self::formatTypeOf($optionType);
322+
}, $optionTypes);
323+
}
324+
325+
/**
326+
* Returns a string representation of the value.
327+
*
328+
* This method returns the equivalent PHP tokens for most scalar types
329+
* (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped
330+
* in double quotes ("). Objects, arrays and resources are formatted as
331+
* "object", "array" and "resource". If the parameter $prettyDateTime
332+
* is set to true, {@link \DateTime} objects will be formatted as
333+
* RFC-3339 dates ("Y-m-d H:i:s").
334+
*
335+
* @param mixed $value The value to format as string
336+
* @param int $format A bitwise combination of the format
337+
* constants in this class
338+
*
339+
* @return string The string representation of the passed value
340+
*/
341+
private static function formatValue($value, $format = 0)
342+
{
343+
$isDateTime = $value instanceof \DateTime || $value instanceof \DateTimeInterface;
344+
if (($format & self::PRETTY_DATE) && $isDateTime) {
345+
if (class_exists('IntlDateFormatter')) {
346+
$locale = \Locale::getDefault();
347+
$formatter = new \IntlDateFormatter($locale, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT);
348+
// neither the native nor the stub IntlDateFormatter support
349+
// DateTimeImmutable as of yet
350+
if (!$value instanceof \DateTime) {
351+
$value = new \DateTime(
352+
$value->format('Y-m-d H:i:s.u e'),
353+
$value->getTimezone()
354+
);
355+
}
356+
357+
return $formatter->format($value);
358+
}
359+
360+
return $value->format('Y-m-d H:i:s');
361+
}
362+
363+
if (is_object($value)) {
364+
if ($format & self::OBJECT_TO_STRING && method_exists($value, '__toString')) {
365+
return $value->__toString();
366+
}
367+
368+
return 'object';
369+
}
370+
371+
if (is_array($value)) {
372+
return 'array';
373+
}
374+
375+
if (is_string($value)) {
376+
return '"' . $value . '"';
377+
}
378+
379+
if (is_resource($value)) {
380+
return 'resource';
381+
}
382+
383+
if (null === $value) {
384+
return 'null';
385+
}
386+
387+
if (false === $value) {
388+
return 'false';
389+
}
390+
391+
if (true === $value) {
392+
return 'true';
393+
}
394+
395+
return (string) $value;
396+
}
397+
398+
/**
399+
* Returns a string representation of a list of values.
400+
*
401+
* @param array $values
402+
* @param bool $prettyDateTime
403+
*
404+
* @return string
405+
*/
406+
private static function formatValues(array $values, $prettyDateTime = false)
407+
{
408+
return array_map(function ($value) use ($prettyDateTime) {
409+
return self::formatValue($value, $prettyDateTime);
410+
}, $values);
411+
}
412+
331413
/**
332414
* Constructs a new object with a set of default options.
333415
*
@@ -425,8 +507,8 @@ public function replace(array $options)
425507
throw new OptionDefinitionException('Options cannot be replaced anymore once options have been read.');
426508
}
427509

428-
$this->options = array();
429-
$this->lazy = array();
510+
$this->options = array();
511+
$this->lazy = array();
430512
$this->normalizers = array();
431513

432514
foreach ($options as $option => $value) {
@@ -467,7 +549,7 @@ public function overload($option, $value)
467549
$reflClosure = is_array($value)
468550
? new \ReflectionMethod($value[0], $value[1])
469551
: new \ReflectionFunction($value);
470-
$params = $reflClosure->getParameters();
552+
$params = $reflClosure->getParameters();
471553

472554
if (isset($params[0]) && null !== ($class = $params[0]->getClass()) && __CLASS__ === $class->name) {
473555
// Initialize the option if no previous value exists
@@ -530,7 +612,7 @@ public function get($option)
530612
*
531613
* @param string $option The option name.
532614
*
533-
* @return bool Whether the option exists.
615+
* @return bool Whether the option exists.
534616
*/
535617
public function has($option)
536618
{
@@ -570,8 +652,8 @@ public function clear()
570652
throw new OptionDefinitionException('Options cannot be cleared anymore once options have been read.');
571653
}
572654

573-
$this->options = array();
574-
$this->lazy = array();
655+
$this->options = array();
656+
$this->lazy = array();
575657
$this->normalizers = array();
576658
}
577659

@@ -610,7 +692,7 @@ public function all()
610692
*
611693
* @param string $option The option name.
612694
*
613-
* @return bool Whether the option exists.
695+
* @return bool Whether the option exists.
614696
*
615697
* @see \ArrayAccess::offsetExists()
616698
*/
@@ -789,7 +871,7 @@ private function normalizeOption($option)
789871
/** @var \Closure $normalizer */
790872
$normalizer = $this->normalizers[$option];
791873

792-
$this->lock[$option] = true;
874+
$this->lock[$option] = true;
793875
$this->options[$option] = $normalizer($this, array_key_exists($option, $this->options) ? $this->options[$option] : null);
794876
unset($this->lock[$option]);
795877

0 commit comments

Comments
 (0)