123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Component\OptionsResolver;
- use Symfony\Component\OptionsResolver\Exception\OptionDefinitionException;
- use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
- use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
- /**
- * Helper for merging default and concrete option values.
- *
- * @author Bernhard Schussek <bschussek@gmail.com>
- * @author Tobias Schultze <http://tobion.de>
- */
- class OptionsResolver implements OptionsResolverInterface
- {
- /**
- * The default option values.
- * @var Options
- */
- private $defaultOptions;
- /**
- * The options known by the resolver.
- * @var array
- */
- private $knownOptions = array();
- /**
- * The options without defaults that are required to be passed to resolve().
- * @var array
- */
- private $requiredOptions = array();
- /**
- * A list of accepted values for each option.
- * @var array
- */
- private $allowedValues = array();
- /**
- * A list of accepted types for each option.
- * @var array
- */
- private $allowedTypes = array();
- /**
- * Creates a new instance.
- */
- public function __construct()
- {
- $this->defaultOptions = new Options();
- }
- /**
- * Clones the resolver.
- */
- public function __clone()
- {
- $this->defaultOptions = clone $this->defaultOptions;
- }
- /**
- * {@inheritdoc}
- */
- public function setDefaults(array $defaultValues)
- {
- foreach ($defaultValues as $option => $value) {
- $this->defaultOptions->overload($option, $value);
- $this->knownOptions[$option] = true;
- unset($this->requiredOptions[$option]);
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function replaceDefaults(array $defaultValues)
- {
- foreach ($defaultValues as $option => $value) {
- $this->defaultOptions->set($option, $value);
- $this->knownOptions[$option] = true;
- unset($this->requiredOptions[$option]);
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setOptional(array $optionNames)
- {
- foreach ($optionNames as $key => $option) {
- if (!is_int($key)) {
- throw new OptionDefinitionException('You should not pass default values to setOptional()');
- }
- $this->knownOptions[$option] = true;
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setRequired(array $optionNames)
- {
- foreach ($optionNames as $key => $option) {
- if (!is_int($key)) {
- throw new OptionDefinitionException('You should not pass default values to setRequired()');
- }
- $this->knownOptions[$option] = true;
- // set as required if no default has been set already
- if (!isset($this->defaultOptions[$option])) {
- $this->requiredOptions[$option] = true;
- }
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setAllowedValues(array $allowedValues)
- {
- $this->validateOptionsExistence($allowedValues);
- $this->allowedValues = array_replace($this->allowedValues, $allowedValues);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function addAllowedValues(array $allowedValues)
- {
- $this->validateOptionsExistence($allowedValues);
- $this->allowedValues = array_merge_recursive($this->allowedValues, $allowedValues);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setAllowedTypes(array $allowedTypes)
- {
- $this->validateOptionsExistence($allowedTypes);
- $this->allowedTypes = array_replace($this->allowedTypes, $allowedTypes);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function addAllowedTypes(array $allowedTypes)
- {
- $this->validateOptionsExistence($allowedTypes);
- $this->allowedTypes = array_merge_recursive($this->allowedTypes, $allowedTypes);
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function setNormalizers(array $normalizers)
- {
- $this->validateOptionsExistence($normalizers);
- foreach ($normalizers as $option => $normalizer) {
- $this->defaultOptions->setNormalizer($option, $normalizer);
- }
- return $this;
- }
- /**
- * {@inheritdoc}
- */
- public function isKnown($option)
- {
- return isset($this->knownOptions[$option]);
- }
- /**
- * {@inheritdoc}
- */
- public function isRequired($option)
- {
- return isset($this->requiredOptions[$option]);
- }
- /**
- * {@inheritdoc}
- */
- public function resolve(array $options = array())
- {
- $this->validateOptionsExistence($options);
- $this->validateOptionsCompleteness($options);
- // Make sure this method can be called multiple times
- $combinedOptions = clone $this->defaultOptions;
- // Override options set by the user
- foreach ($options as $option => $value) {
- $combinedOptions->set($option, $value);
- }
- // Resolve options
- $resolvedOptions = $combinedOptions->all();
- $this->validateOptionValues($resolvedOptions);
- $this->validateOptionTypes($resolvedOptions);
- return $resolvedOptions;
- }
- /**
- * Validates that the given option names exist and throws an exception
- * otherwise.
- *
- * @param array $options An list of option names as keys.
- *
- * @throws InvalidOptionsException If any of the options has not been defined.
- */
- private function validateOptionsExistence(array $options)
- {
- $diff = array_diff_key($options, $this->knownOptions);
- if (count($diff) > 0) {
- ksort($this->knownOptions);
- ksort($diff);
- throw new InvalidOptionsException(sprintf(
- (count($diff) > 1 ? 'The options "%s" do not exist.' : 'The option "%s" does not exist.').' Known options are: "%s"',
- implode('", "', array_keys($diff)),
- implode('", "', array_keys($this->knownOptions))
- ));
- }
- }
- /**
- * Validates that all required options are given and throws an exception
- * otherwise.
- *
- * @param array $options An list of option names as keys.
- *
- * @throws MissingOptionsException If a required option is missing.
- */
- private function validateOptionsCompleteness(array $options)
- {
- $diff = array_diff_key($this->requiredOptions, $options);
- if (count($diff) > 0) {
- ksort($diff);
- throw new MissingOptionsException(sprintf(
- count($diff) > 1 ? 'The required options "%s" are missing.' : 'The required option "%s" is missing.',
- implode('", "', array_keys($diff))
- ));
- }
- }
- /**
- * Validates that the given option values match the allowed values and
- * throws an exception otherwise.
- *
- * @param array $options A list of option values.
- *
- * @throws InvalidOptionsException If any of the values does not match the
- * allowed values of the option.
- */
- private function validateOptionValues(array $options)
- {
- foreach ($this->allowedValues as $option => $allowedValues) {
- if (isset($options[$option]) && !in_array($options[$option], $allowedValues, true)) {
- throw new InvalidOptionsException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $allowedValues)));
- }
- }
- }
- /**
- * Validates that the given options match the allowed types and
- * throws an exception otherwise.
- *
- * @param array $options A list of options.
- *
- * @throws InvalidOptionsException If any of the types does not match the
- * allowed types of the option.
- */
- private function validateOptionTypes(array $options)
- {
- foreach ($this->allowedTypes as $option => $allowedTypes) {
- if (!array_key_exists($option, $options)) {
- continue;
- }
- $value = $options[$option];
- $allowedTypes = (array) $allowedTypes;
- foreach ($allowedTypes as $type) {
- $isFunction = 'is_'.$type;
- if (function_exists($isFunction) && $isFunction($value)) {
- continue 2;
- } elseif ($value instanceof $type) {
- continue 2;
- }
- }
- $printableValue = is_object($value)
- ? get_class($value)
- : (is_array($value)
- ? 'Array'
- : (string) $value);
- throw new InvalidOptionsException(sprintf(
- 'The option "%s" with value "%s" is expected to be of type "%s"',
- $option,
- $printableValue,
- implode('", "', $allowedTypes)
- ));
- }
- }
- }
|