diff --git a/composer.json b/composer.json
index 49a9f3fb2b..c8d46114f8 100644
--- a/composer.json
+++ b/composer.json
@@ -42,6 +42,7 @@
"symfony/http-foundation": "self.version",
"symfony/http-kernel": "self.version",
"symfony/locale": "self.version",
+ "symfony/options-parser": "self.version",
"symfony/process": "self.version",
"symfony/routing": "self.version",
"symfony/security": "self.version",
diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
index 3bc7a7bb77..96582e66c4 100644
--- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
+++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php
@@ -19,7 +19,7 @@ use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface;
use Symfony\Bridge\Doctrine\Form\EventListener\MergeDoctrineCollectionListener;
use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Options;
+use Symfony\Component\OptionsParser\Options;
abstract class DoctrineType extends AbstractType
{
diff --git a/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php b/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php
index de125a070f..4c57c42b55 100644
--- a/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php
+++ b/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php
@@ -14,8 +14,8 @@ namespace Symfony\Bridge\Propel1\Form\Type;
use Symfony\Bridge\Propel1\Form\ChoiceList\ModelChoiceList;
use Symfony\Bridge\Propel1\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Options;
use Symfony\Component\Form\FormBuilder;
+use Symfony\Component\OptionsParser\Options;
/**
* ModelType class.
diff --git a/src/Symfony/Component/Form/DefaultOptions.php b/src/Symfony/Component/Form/DefaultOptions.php
deleted file mode 100644
index 9dba4b9e9d..0000000000
--- a/src/Symfony/Component/Form/DefaultOptions.php
+++ /dev/null
@@ -1,320 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form;
-
-use Symfony\Component\Form\Exception\OptionDefinitionException;
-use Symfony\Component\Form\Exception\InvalidOptionException;
-
-/**
- * Helper for specifying and resolving inter-dependent options.
- *
- * Options are a common pattern for initializing classes in PHP. Avoiding the
- * problems related to this approach is however a non-trivial task. Usually,
- * both classes and subclasses should be able to set default option values.
- * These default options should be overridden by the options passed to the
- * constructor. Last but not least, the (default) values of some options may
- * depend on the values of other options, which themselves may depend on other
- * options and so on.
- *
- * DefaultOptions resolves these problems. It allows you to:
- *
- * - Define default option values
- * - Define options in layers that correspond to your class hierarchy. Each
- * layer may depend on the default value set in the higher layers.
- * - Define default values for options that depend on the concrete
- * values of other options.
- * - Resolve the concrete option values by passing the options set by the
- * user.
- *
- * You can use it in your classes by implementing the following pattern:
- *
- *
- * class Car
- * {
- * protected $options;
- *
- * public function __construct(array $options)
- * {
- * $defaultOptions = new DefaultOptions();
- * $this->addDefaultOptions($defaultOptions);
- *
- * $this->options = $defaultOptions->resolve($options);
- * }
- *
- * protected function addDefaultOptions(DefaultOptions $options)
- * {
- * $options->add(array(
- * 'make' => 'VW',
- * 'year' => '1999',
- * ));
- * }
- * }
- *
- * $car = new Car(array(
- * 'make' => 'Mercedes',
- * 'year' => 2005,
- * ));
- *
- *
- * By calling add(), new default options are added to the container. The method
- * resolve() accepts an array of options passed by the user that are matched
- * against the defined options. If any option is not recognized, an exception
- * is thrown. Finally, resolve() returns the merged default and user options.
- *
- * You can now easily add or override options in subclasses:
- *
- *
- * class Renault extends Car
- * {
- * protected function addDefaultOptions(DefaultOptions $options)
- * {
- * parent::addDefaultOptions($options);
- *
- * $options->add(array(
- * 'make' => 'Renault',
- * 'gear' => 'auto',
- * ));
- * }
- * }
- *
- * $renault = new Renault(array(
- * 'year' => 1997,
- * 'gear' => 'manual'
- * ));
- *
- *
- * IMPORTANT: parent::addDefaultOptions() must always be called before adding
- * new default options!
- *
- * In the previous example, it makes sense to restrict the option "gear" to
- * a set of allowed values:
- *
- *
- * class Renault extends Car
- * {
- * protected function addDefaultOptions(DefaultOptions $options)
- * {
- * // ... like above ...
- *
- * $options->addAllowedValues(array(
- * 'gear' => array('auto', 'manual'),
- * ));
- * }
- * }
- *
- * // Fails!
- * $renault = new Renault(array(
- * 'gear' => 'v6',
- * ));
- *
- *
- * Now it is impossible to pass a value in the "gear" option that is not
- * expected.
- *
- * Last but not least, you can define options that depend on other options.
- * For example, depending on the "make" you could preset the country that the
- * car is registered in.
- *
- *
- * class Car
- * {
- * protected function addDefaultOptions(DefaultOptions $options)
- * {
- * $options->add(array(
- * 'make' => 'VW',
- * 'year' => '1999',
- * 'country' => function (Options $options) {
- * if ('VW' === $options['make']) {
- * return 'DE';
- * }
- *
- * return null;
- * },
- * ));
- * }
- * }
- *
- * $car = new Car(array(
- * 'make' => 'VW', // => "country" is "DE"
- * ));
- *
- *
- * The closure receives as its first parameter a container of class Options
- * that contains the concrete options determined upon resolving. The
- * closure is executed once resolve() is called.
- *
- * The closure also receives a second parameter $previousValue that contains the
- * value defined by the parent layer of the hierarchy. If the option has not
- * been defined in any parent layer, the second parameter is NULL.
- *
- *
- * class Renault extends Car
- * {
- * protected function addDefaultOptions(DefaultOptions $options)
- * {
- * $options->add(array(
- * 'country' => function (Options $options, $previousValue) {
- * if ('Renault' === $options['make']) {
- * return 'FR';
- * }
- *
- * // return default value defined in Car
- * return $previousValue;
- * },
- * ));
- * }
- * }
- *
- * $renault = new Renault(array(
- * 'make' => 'VW', // => "country" is still "DE"
- * ));
- *
- *
- * @author Bernhard Schussek
- */
-class DefaultOptions
-{
- /**
- * The container resolving the options.
- * @var Options
- */
- private $options;
-
- /**
- * A list of accepted values for each option.
- * @var array
- */
- private $allowedValues = array();
-
- /**
- * Creates a new instance.
- */
- public function __construct()
- {
- $this->options = new Options();
- }
-
- /**
- * Adds default options.
- *
- * @param array $options A list of option names as keys and option values
- * as values. The option values may be closures
- * of the following signatures:
- *
- * - function (Options $options)
- * - function (Options $options, $previousValue)
- */
- public function add(array $options)
- {
- foreach ($options as $option => $value) {
- $this->options[$option] = $value;
- }
- }
-
- /**
- * Adds allowed values for a list of options.
- *
- * @param array $allowedValues A list of option names as keys and arrays
- * with values acceptable for that option as
- * values.
- *
- * @throws InvalidOptionException If an option has not been defined for
- * which an allowed value is set.
- */
- public function addAllowedValues(array $allowedValues)
- {
- $this->validateOptionNames(array_keys($allowedValues));
-
- $this->allowedValues = array_merge_recursive($this->allowedValues, $allowedValues);
- }
-
- /**
- * Resolves the final option values by merging default options with user
- * options.
- *
- * @param array $userOptions The options passed by the user.
- *
- * @return array A list of options and their final values.
- *
- * @throws InvalidOptionException If any of the passed options has not
- * been defined or does not contain an
- * allowed value.
- * @throws OptionDefinitionException If a cyclic dependency is detected
- * between option closures.
- */
- public function resolve(array $userOptions)
- {
- // Make sure this method can be called multiple times
- $options = clone $this->options;
-
- $this->validateOptionNames(array_keys($userOptions));
-
- // Override options set by the user
- foreach ($userOptions as $option => $value) {
- $options[$option] = $value;
- }
-
- // Resolve options
- $options = iterator_to_array($options);
-
- // Validate against allowed values
- $this->validateOptionValues($options);
-
- return $options;
- }
-
- /**
- * Validates that the given option names exist and throws an exception
- * otherwise.
- *
- * @param array $optionNames A list of option names.
- *
- * @throws InvalidOptionException If any of the options has not been
- * defined.
- */
- private function validateOptionNames(array $optionNames)
- {
- $knownOptions = $this->options->getNames();
- $diff = array_diff($optionNames, $knownOptions);
-
- if (count($diff) > 0) {
- sort($knownOptions);
- sort($diff);
- }
-
- if (count($diff) > 1) {
- throw new InvalidOptionException(sprintf('The options "%s" do not exist. Known options are: "%s"', implode('", "', $diff), implode('", "', $knownOptions)));
- }
-
- if (count($diff) > 0) {
- throw new InvalidOptionException(sprintf('The option "%s" does not exist. Known options are: "%s"', current($diff), implode('", "', $knownOptions)));
- }
- }
-
- /**
- * Validates that the given option values match the allowed values and
- * throws an exception otherwise.
- *
- * @param array $options A list of option values.
- *
- * @throws InvalidOptionException 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 (!in_array($options[$option], $allowedValues, true)) {
- throw new InvalidOptionException(sprintf('The option "%s" has the value "%s", but is expected to be one of "%s"', $option, $options[$option], implode('", "', $allowedValues)));
- }
- }
- }
-}
diff --git a/src/Symfony/Component/Form/Exception/OptionDefinitionException.php b/src/Symfony/Component/Form/Exception/OptionDefinitionException.php
deleted file mode 100644
index dfd87cc7e5..0000000000
--- a/src/Symfony/Component/Form/Exception/OptionDefinitionException.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Exception;
-
-class OptionDefinitionException extends FormException
-{
-}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index 3e21af5ad1..6bfc8cbbcd 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Options;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
@@ -27,6 +26,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransform
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToBooleanArrayTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToBooleanArrayTransformer;
+use Symfony\Component\OptionsParser\Options;
class ChoiceType extends AbstractType
{
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
index e74acb20c9..1d8387d54b 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php
@@ -21,7 +21,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransfo
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
-use Symfony\Component\Form\Options;
+use Symfony\Component\OptionsParser\Options;
class DateTimeType extends AbstractType
{
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
index e67a232fec..91dfa3c3d4 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
@@ -22,7 +22,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransfo
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\ReversedTransformer;
-use Symfony\Component\Form\Options;
+use Symfony\Component\OptionsParser\Options;
class DateType extends AbstractType
{
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php b/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
index 5af6791346..dbafde1f65 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FieldType.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\EventDispatcher\EventDispatcher;
/**
* Deprecated. You should extend FormType instead.
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 0dea6d113c..c9936e2f71 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
-use Symfony\Component\Form\Options;
use Symfony\Component\Form\Util\PropertyPath;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormInterface;
@@ -23,6 +22,7 @@ use Symfony\Component\Form\Extension\Core\EventListener\ValidationListener;
use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\Form\Exception\FormException;
+use Symfony\Component\OptionsParser\Options;
class FormType extends AbstractType
{
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
index 7fb9d2bd80..5d1fef8a3e 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
@@ -20,7 +20,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransf
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Options;
+use Symfony\Component\OptionsParser\Options;
class TimeType extends AbstractType
{
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
index 3e6b2baaac..c3eb421e44 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList;
+use Symfony\Component\OptionsParser\Options;
class TimezoneType extends AbstractType
{
diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php
index 9529a7bea2..ee7ddb9170 100644
--- a/src/Symfony/Component/Form/FormFactory.php
+++ b/src/Symfony/Component/Form/FormFactory.php
@@ -14,6 +14,7 @@ namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\TypeDefinitionException;
+use Symfony\Component\OptionsParser\OptionsParser;
class FormFactory implements FormFactoryInterface
{
@@ -220,7 +221,7 @@ class FormFactory implements FormFactoryInterface
$types = array();
$optionValues = array();
$knownOptions = array();
- $defaultOptions = new DefaultOptions();
+ $optionsParser = new OptionsParser();
// Bottom-up determination of the type hierarchy
// Start with the actual type and look for the parent type
@@ -254,14 +255,14 @@ class FormFactory implements FormFactoryInterface
// options. Default options of children override default options
// of parents.
$typeOptions = $type->getDefaultOptions();
- $defaultOptions->add($typeOptions);
- $defaultOptions->addAllowedValues($type->getAllowedOptionValues());
+ $optionsParser->setDefaults($typeOptions);
+ $optionsParser->addAllowedValues($type->getAllowedOptionValues());
$knownOptions = array_merge($knownOptions, array_keys($typeOptions));
foreach ($type->getExtensions() as $typeExtension) {
$extensionOptions = $typeExtension->getDefaultOptions();
- $defaultOptions->add($extensionOptions);
- $defaultOptions->addAllowedValues($typeExtension->getAllowedOptionValues());
+ $optionsParser->setDefaults($extensionOptions);
+ $optionsParser->addAllowedValues($typeExtension->getAllowedOptionValues());
$knownOptions = array_merge($knownOptions, array_keys($extensionOptions));
}
}
@@ -277,7 +278,7 @@ class FormFactory implements FormFactoryInterface
}
// Resolve options
- $options = $defaultOptions->resolve($options);
+ $options = $optionsParser->parse($options);
for ($i = 0, $l = count($types); $i < $l && !$builder; ++$i) {
$builder = $types[$i]->createBuilder($name, $this, $options);
diff --git a/src/Symfony/Component/Form/Tests/DefaultOptionsTest.php b/src/Symfony/Component/Form/Tests/DefaultOptionsTest.php
deleted file mode 100644
index e22131d563..0000000000
--- a/src/Symfony/Component/Form/Tests/DefaultOptionsTest.php
+++ /dev/null
@@ -1,76 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\Form\Tests;
-
-use Symfony\Component\Form\DefaultOptions;
-use Symfony\Component\Form\Options;
-
-class DefaultOptionsTest extends \PHPUnit_Framework_TestCase
-{
- private $options;
-
- protected function setUp()
- {
- $this->options = new DefaultOptions();
- }
-
- public function testResolve()
- {
- $this->options->add(array(
- 'foo' => 'bar',
- 'bam' => function (Options $options) {
- return 'baz';
- },
- ));
-
- $result = array(
- 'foo' => 'fee',
- 'bam' => 'baz',
- );
-
- $this->assertEquals($result, $this->options->resolve(array(
- 'foo' => 'fee',
- )));
- }
-
- /**
- * @expectedException Symfony\Component\Form\Exception\InvalidOptionException
- */
- public function testResolveFailsIfNonExistingOption()
- {
- $this->options->add(array(
- 'foo' => 'bar',
- ));
-
- $this->options->resolve(array(
- 'non_existing' => 'option',
- ));
- }
-
- /**
- * @expectedException Symfony\Component\Form\Exception\InvalidOptionException
- */
- public function testResolveFailsIfOptionValueNotAllowed()
- {
- $this->options->add(array(
- 'foo' => 'bar',
- ));
-
- $this->options->addAllowedValues(array(
- 'foo' => array('bar', 'baz'),
- ));
-
- $this->options->resolve(array(
- 'foo' => 'bam',
- ));
- }
-}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
index 90b9a264f6..a371099eb8 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
@@ -23,7 +23,7 @@ class DateTypeTest extends LocalizedTestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\FormException
+ * @expectedException Symfony\Component\OptionsParser\Exception\InvalidOptionsException
*/
public function testInvalidWidgetOption()
{
@@ -33,7 +33,7 @@ class DateTypeTest extends LocalizedTestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\FormException
+ * @expectedException Symfony\Component\OptionsParser\Exception\InvalidOptionsException
*/
public function testInvalidInputOption()
{
diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php
index 4b8eb3f3a9..742a940d4b 100644
--- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php
+++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php
@@ -279,7 +279,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\InvalidOptionException
+ * @expectedException Symfony\Component\OptionsParser\Exception\InvalidOptionsException
*/
public function testCreateNamedBuilderExpectsOptionsToExist()
{
@@ -292,7 +292,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\InvalidOptionException
+ * @expectedException Symfony\Component\OptionsParser\Exception\InvalidOptionsException
*/
public function testCreateNamedBuilderExpectsOptionsToBeInValidRange()
{
@@ -608,7 +608,6 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($parentBuilder, $builder->getParent());
}
-
public function testFormTypeCreatesDefaultValueForEmptyDataOption()
{
$factory = new FormFactory(array(new \Symfony\Component\Form\Extension\Core\CoreExtension()));
diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json
index 80ce8df5ca..888eef4ec4 100644
--- a/src/Symfony/Component/Form/composer.json
+++ b/src/Symfony/Component/Form/composer.json
@@ -18,7 +18,8 @@
"require": {
"php": ">=5.3.3",
"symfony/event-dispatcher": "2.1.*",
- "symfony/locale": "2.1.*"
+ "symfony/locale": "2.1.*",
+ "symfony/options-parser": "2.1.*"
},
"require-dev": {
"symfony/validator": "2.1.*",
diff --git a/src/Symfony/Component/Form/Exception/InvalidOptionException.php b/src/Symfony/Component/OptionsParser/Exception/ExceptionInterface.php
old mode 100644
new mode 100755
similarity index 55%
rename from src/Symfony/Component/Form/Exception/InvalidOptionException.php
rename to src/Symfony/Component/OptionsParser/Exception/ExceptionInterface.php
index 54d782b3e1..79bc34fde7
--- a/src/Symfony/Component/Form/Exception/InvalidOptionException.php
+++ b/src/Symfony/Component/OptionsParser/Exception/ExceptionInterface.php
@@ -9,8 +9,13 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form\Exception;
+namespace Symfony\Component\OptionsParser\Exception;
-class InvalidOptionException extends FormException
+/**
+ * Marker interface for the Options component.
+ *
+ * @author Bernhard Schussek
+ */
+interface ExceptionInterface
{
}
diff --git a/src/Symfony/Component/OptionsParser/Exception/InvalidOptionsException.php b/src/Symfony/Component/OptionsParser/Exception/InvalidOptionsException.php
new file mode 100644
index 0000000000..24454d8c77
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/Exception/InvalidOptionsException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsParser\Exception;
+
+/**
+ * Exception thrown when an invalid option is passed.
+ *
+ * @author Bernhard Schussek
+ */
+class InvalidOptionsException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/src/Symfony/Component/OptionsParser/Exception/MissingOptionsException.php b/src/Symfony/Component/OptionsParser/Exception/MissingOptionsException.php
new file mode 100644
index 0000000000..3afb54dfc2
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/Exception/MissingOptionsException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsParser\Exception;
+
+/**
+ * Exception thrown when a required option is missing.
+ *
+ * @author Bernhard Schussek
+ */
+class MissingOptionsException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/src/Symfony/Component/OptionsParser/Exception/OptionDefinitionException.php b/src/Symfony/Component/OptionsParser/Exception/OptionDefinitionException.php
new file mode 100644
index 0000000000..34d317f720
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/Exception/OptionDefinitionException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsParser\Exception;
+
+/**
+ * Thrown when an option definition is invalid.
+ *
+ * @author Bernhard Schussek
+ */
+class OptionDefinitionException extends \RuntimeException implements ExceptionInterface
+{
+}
diff --git a/src/Symfony/Component/OptionsParser/LICENSE b/src/Symfony/Component/OptionsParser/LICENSE
new file mode 100644
index 0000000000..cdffe7aebc
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2012 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/src/Symfony/Component/Form/LazyOption.php b/src/Symfony/Component/OptionsParser/LazyOption.php
similarity index 96%
rename from src/Symfony/Component/Form/LazyOption.php
rename to src/Symfony/Component/OptionsParser/LazyOption.php
index 69365ec996..8d935fdf0a 100644
--- a/src/Symfony/Component/Form/LazyOption.php
+++ b/src/Symfony/Component/OptionsParser/LazyOption.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form;
+namespace Symfony\Component\OptionsParser;
use Closure;
@@ -17,8 +17,6 @@ use Closure;
* An option that is evaluated lazily using a closure.
*
* @author Bernhard Schussek
- *
- * @see DefaultOptions
*/
class LazyOption
{
diff --git a/src/Symfony/Component/Form/Options.php b/src/Symfony/Component/OptionsParser/Options.php
similarity index 56%
rename from src/Symfony/Component/Form/Options.php
rename to src/Symfony/Component/OptionsParser/Options.php
index ef2254f7a3..956616e34e 100644
--- a/src/Symfony/Component/Form/Options.php
+++ b/src/Symfony/Component/OptionsParser/Options.php
@@ -9,164 +9,16 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form;
+namespace Symfony\Component\OptionsParser;
use ArrayAccess;
use Iterator;
use OutOfBoundsException;
-use Symfony\Component\Form\Exception\OptionDefinitionException;
+use Symfony\Component\OptionsParser\Exception\OptionDefinitionException;
/**
* Container for resolving inter-dependent options.
*
- * Options are a common pattern for resolved classes in PHP. Avoiding the
- * problems related to this approach is however a non-trivial task. Usually,
- * both classes and subclasses should be able to set default option values.
- * These default options should be overridden by the options passed to the
- * constructor. Last but not least, the (default) values of some options may
- * depend on the values of other options, which themselves may depend on other
- * options.
- *
- * This class resolves these problems. You can use it in your classes by
- * implementing the following pattern:
- *
- *
- * class Car
- * {
- * protected $options;
- *
- * public function __construct(array $options)
- * {
- * $_options = new Options();
- * $this->addDefaultOptions($_options);
- *
- * $this->options = $_options->resolve($options);
- * }
- *
- * protected function addDefaultOptions(Options $options)
- * {
- * $options->add(array(
- * 'make' => 'VW',
- * 'year' => '1999',
- * ));
- * }
- * }
- *
- * $car = new Car(array(
- * 'make' => 'Mercedes',
- * 'year' => 2005,
- * ));
- *
- *
- * By calling add(), new default options are added to the container. The method
- * resolve() accepts an array of options passed by the user that are matched
- * against the allowed options. If any option is not recognized, an exception
- * is thrown. Finally, resolve() returns the merged default and user options.
- *
- * You can now easily add or override options in subclasses:
- *
- *
- * class Renault extends Car
- * {
- * protected function addDefaultOptions(Options $options)
- * {
- * parent::addDefaultOptions($options);
- *
- * $options->add(array(
- * 'make' => 'Renault',
- * 'gear' => 'auto',
- * ));
- * }
- * }
- *
- * $renault = new Renault(array(
- * 'year' => 1997,
- * 'gear' => 'manual'
- * ));
- *
- *
- * IMPORTANT: parent::addDefaultOptions() must always be called before adding
- * new options!
- *
- * In the previous example, it makes sense to restrict the option "gear" to
- * a set of allowed values:
- *
- *
- * class Renault extends Car
- * {
- * protected function addDefaultOptions(Options $options)
- * {
- * // ... like above ...
- *
- * $options->addAllowedValues(array(
- * 'gear' => array('auto', 'manual'),
- * ));
- * }
- * }
- *
- * // Fails!
- * $renault = new Renault(array(
- * 'gear' => 'v6',
- * ));
- *
- *
- * Now it is impossible to pass a value in the "gear" option that is not
- * expected.
- *
- * Last but not least, you can define options that depend on other options.
- * For example, depending on the "make" you could preset the country that the
- * car is registered in.
- *
- *
- * class Car
- * {
- * protected function addDefaultOptions(Options $options)
- * {
- * $options->add(array(
- * 'make' => 'VW',
- * 'year' => '1999',
- * 'country' => function (Options $options) {
- * if ('VW' === $options['make']) {
- * return 'DE';
- * }
- *
- * return null;
- * },
- * ));
- * }
- * }
- *
- * $car = new Car(array(
- * 'make' => 'VW', // => "country" is "DE"
- * ));
- *
- *
- * When overriding an option with a closure in subclasses, you can make use of
- * the second parameter $parentValue in which the value defined by the parent
- * class is stored.
- *
- *
- * class Renault extends Car
- * {
- * protected function addDefaultOptions(Options $options)
- * {
- * $options->add(array(
- * 'country' => function (Options $options, $parentValue) {
- * if ('Renault' === $options['make']) {
- * return 'FR';
- * }
- *
- * return $parentValue;
- * },
- * ));
- * }
- * }
- *
- * $renault = new Renault(array(
- * 'make' => 'VW', // => "country" is still "DE"
- * ));
- *
- *
* @author Bernhard Schussek
*/
class Options implements ArrayAccess, Iterator
@@ -312,16 +164,6 @@ class Options implements ArrayAccess, Iterator
unset($this->lock[$option]);
}
- /**
- * Returns the names of all defined options.
- *
- * @return array An array of option names.
- */
- public function getNames()
- {
- return array_keys($this->options);
- }
-
/**
* @see Iterator::current()
*/
diff --git a/src/Symfony/Component/OptionsParser/OptionsParser.php b/src/Symfony/Component/OptionsParser/OptionsParser.php
new file mode 100644
index 0000000000..3a5d6cc85a
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/OptionsParser.php
@@ -0,0 +1,249 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsParser;
+
+use Symfony\Component\OptionsParser\Exception\OptionDefinitionException;
+use Symfony\Component\OptionsParser\Exception\InvalidOptionsException;
+use Symfony\Component\OptionsParser\Exception\MissingOptionsException;
+
+/**
+ * Helper for merging default and concrete option values.
+ *
+ * @author Bernhard Schussek
+ */
+class OptionsParser
+{
+ /**
+ * The default option values.
+ * @var Options
+ */
+ private $defaultOptions;
+
+ /**
+ * The options known by the parser.
+ * @var array
+ */
+ private $knownOptions = array();
+
+ /**
+ * The options required to be passed to parse().
+ * @var array
+ */
+ private $requiredOptions = array();
+
+ /**
+ * A list of accepted values for each option.
+ * @var array
+ */
+ private $allowedValues = array();
+
+ /**
+ * Creates a new instance.
+ */
+ public function __construct()
+ {
+ $this->defaultOptions = new Options();
+ }
+
+ /**
+ * Sets default option values.
+ *
+ * @param array $options A list of option names as keys and default values
+ * as values. The option values may be closures
+ * of the following signatures:
+ *
+ * - function (Options $options)
+ * - function (Options $options, $previousValue)
+ */
+ public function setDefaults(array $defaultValues)
+ {
+ foreach ($defaultValues as $option => $value) {
+ $this->defaultOptions[$option] = $value;
+ $this->knownOptions[$option] = true;
+ }
+ }
+
+ /**
+ * Sets optional options.
+ *
+ * This method is identical to `setDefaults`, only that no default values
+ * are configured for the options. If these options are not passed to
+ * parse(), they will be missing in the final options array. This can be
+ * helpful if you want to determine whether an option has been set or not.
+ *
+ * @param array $optionNames A list of option names.
+ *
+ * @throws OptionDefinitionException When trying to pass default values.
+ */
+ 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;
+ }
+ }
+
+ /**
+ * Sets required options.
+ *
+ * If these options are not passed to parse(), an exception will be thrown.
+ *
+ * @param array $optionNames A list of option names.
+ *
+ * @throws OptionDefinitionException When trying to pass default values.
+ */
+ 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;
+ $this->requiredOptions[$option] = true;
+ }
+ }
+
+ /**
+ * Sets allowed values for a list of options.
+ *
+ * @param array $allowedValues A list of option names as keys and arrays
+ * with values acceptable for that option as
+ * values.
+ *
+ * @throws InvalidOptionsException If an option has not been defined for
+ * which an allowed value is set.
+ */
+ public function setAllowedValues(array $allowedValues)
+ {
+ $this->validateOptionNames(array_keys($allowedValues));
+
+ $this->allowedValues = array_replace($this->allowedValues, $allowedValues);
+ }
+
+ /**
+ * Adds allowed values for a list of options.
+ *
+ * The values are merged with the allowed values defined previously.
+ *
+ * @param array $allowedValues A list of option names as keys and arrays
+ * with values acceptable for that option as
+ * values.
+ *
+ * @throws InvalidOptionsException If an option has not been defined for
+ * which an allowed value is set.
+ */
+ public function addAllowedValues(array $allowedValues)
+ {
+ $this->validateOptionNames(array_keys($allowedValues));
+
+ $this->allowedValues = array_merge_recursive($this->allowedValues, $allowedValues);
+ }
+
+ /**
+ * Returns the combination of the default and the passed options.
+ *
+ * @param array $options The custom option values.
+ *
+ * @return array A list of options and their values.
+ *
+ * @throws InvalidOptionsException If any of the passed options has not
+ * been defined or does not contain an
+ * allowed value.
+ * @throws MissingOptionsException If a required option is missing.
+ * @throws OptionDefinitionException If a cyclic dependency is detected
+ * between two lazy options.
+ */
+ public function parse(array $options)
+ {
+ $this->validateOptionNames(array_keys($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[$option] = $value;
+ }
+
+ // Resolve options
+ $combinedOptions = iterator_to_array($combinedOptions);
+
+ // Validate against allowed values
+ $this->validateOptionValues($combinedOptions);
+
+ return $combinedOptions;
+ }
+
+ /**
+ * Validates that the given option names exist and throws an exception
+ * otherwise.
+ *
+ * @param array $optionNames A list of option names.
+ *
+ * @throws InvalidOptionsException If any of the options has not been
+ * defined.
+ */
+ private function validateOptionNames(array $optionNames)
+ {
+ ksort($this->knownOptions);
+
+ $knownOptions = array_keys($this->knownOptions);
+ $diff = array_diff($optionNames, $knownOptions);
+
+ sort($diff);
+
+ if (count($diff) > 1) {
+ throw new InvalidOptionsException(sprintf('The options "%s" do not exist. Known options are: "%s"', implode('", "', $diff), implode('", "', $knownOptions)));
+ }
+
+ if (count($diff) > 0) {
+ throw new InvalidOptionsException(sprintf('The option "%s" does not exist. Known options are: "%s"', current($diff), implode('", "', $knownOptions)));
+ }
+
+ ksort($this->requiredOptions);
+
+ $requiredOptions = array_keys($this->requiredOptions);
+ $diff = array_diff($requiredOptions, $optionNames);
+
+ sort($diff);
+
+ if (count($diff) > 1) {
+ throw new MissingOptionsException(sprintf('The options "%s" are missing.', implode('", "', $diff)));
+ }
+
+ if (count($diff) > 0) {
+ throw new MissingOptionsException(sprintf('The option "%s" is missing.', current($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 (!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)));
+ }
+ }
+ }
+}
diff --git a/src/Symfony/Component/OptionsParser/README.md b/src/Symfony/Component/OptionsParser/README.md
new file mode 100644
index 0000000000..6ae6920bb0
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/README.md
@@ -0,0 +1,103 @@
+OptionsParser Component
+======================
+
+OptionsParser helps to configure objects with option arrays.
+
+It supports default values on different levels of your class hierarchy,
+required options and lazy options where the default value depends on the
+concrete value of a different option.
+
+The following example demonstrates a Person class with two required options
+"firstName" and "lastName" and two optional options "age" and "gender", where
+the default value of "gender" is derived from the passed first name, if
+possible.
+
+ use Symfony\Component\OptionsParser\OptionsParser;
+ use Symfony\Component\OptionsParser\Options;
+
+ class Person
+ {
+ protected $options;
+
+ public function __construct(array $options = array())
+ {
+ $parser = new OptionsParser();
+ $this->setOptions($parser);
+
+ $this->options = $parser->parse($options);
+ }
+
+ protected function setOptions(OptionsParser $parser)
+ {
+ $parser->setRequired(array(
+ 'firstName',
+ 'lastName',
+ 'age',
+ ));
+
+ $parser->setDefaults(array(
+ 'age' => null,
+ 'gender' => function (Options $options) {
+ if (self::isKnownMaleName($options['firstName'])) {
+ return 'male';
+ }
+
+ return 'female';
+ },
+ ));
+
+ $parser->setAllowedValues(array(
+ 'gender' => array('male', 'female'),
+ ));
+ }
+ }
+
+We can now easily instantiate a Person object:
+
+ // 'gender' is implicitely set to 'female'
+ $person = new Person(array(
+ 'firstName' => 'Jane',
+ 'lastName' => 'Doe',
+ ));
+
+We can also override the default values of the optional options:
+
+ $person = new Person(array(
+ 'firstName' => 'Abdullah',
+ 'lastName' => 'Mogashi',
+ 'gender' => 'male',
+ 'age' => 30,
+ ));
+
+Options can be added or changed in subclasses by overriding the `setOptions`
+method:
+
+ use Symfony\Component\OptionsParser\OptionsParser;
+ use Symfony\Component\OptionsParser\Options;
+
+ class Employee extends Person
+ {
+ protected function setOptions(OptionsParser $parser)
+ {
+ parent::setOptions($parser);
+
+ $parser->setRequired(array(
+ 'birthDate',
+ ));
+
+ $parser->setDefaults(array(
+ // $previousValue contains the default value configured in the
+ // parent class
+ 'age' => function (Options $options, $previousValue) {
+ return self::configureAgeFromBirthDate($options['birthDate']);
+ }
+ ));
+ }
+ }
+
+Resources
+---------
+
+You can run the unit tests with the following command:
+
+ phpunit -c src/Symfony/Component/OptionsParser/
\ No newline at end of file
diff --git a/src/Symfony/Component/OptionsParser/Tests/OptionParserTest.php b/src/Symfony/Component/OptionsParser/Tests/OptionParserTest.php
new file mode 100644
index 0000000000..6f6e416b40
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/Tests/OptionParserTest.php
@@ -0,0 +1,271 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\OptionsParser\Tests;
+
+use Symfony\Component\OptionsParser\OptionsParser;
+use Symfony\Component\OptionsParser\Options;
+
+class OptionsParserTest extends \PHPUnit_Framework_TestCase
+{
+ private $options;
+
+ protected function setUp()
+ {
+ $this->parser = new OptionsParser();
+ }
+
+ public function testParse()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ 'two' => '2',
+ ));
+
+ $options = array(
+ 'two' => '20',
+ );
+
+ $this->assertEquals(array(
+ 'one' => '1',
+ 'two' => '20',
+ ), $this->parser->parse($options));
+ }
+
+ public function testParseLazy()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ 'two' => function (Options $options) {
+ return '20';
+ },
+ ));
+
+ $this->assertEquals(array(
+ 'one' => '1',
+ 'two' => '20',
+ ), $this->parser->parse(array()));
+ }
+
+ public function testParseLazyDependencyOnOptional()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ 'two' => function (Options $options) {
+ return $options['one'] . '2';
+ },
+ ));
+
+ $options = array(
+ 'one' => '10',
+ );
+
+ $this->assertEquals(array(
+ 'one' => '10',
+ 'two' => '102',
+ ), $this->parser->parse($options));
+ }
+
+ public function testParseLazyDependencyOnMissingOptionalWithoutDefault()
+ {
+ $test = $this;
+
+ $this->parser->setOptional(array(
+ 'one',
+ ));
+
+ $this->parser->setDefaults(array(
+ 'two' => function (Options $options) use ($test) {
+ $test->assertFalse(isset($options['one']));
+
+ return '2';
+ },
+ ));
+
+ $options = array(
+ );
+
+ $this->assertEquals(array(
+ 'two' => '2',
+ ), $this->parser->parse($options));
+ }
+
+ public function testParseLazyDependencyOnOptionalWithoutDefault()
+ {
+ $test = $this;
+
+ $this->parser->setOptional(array(
+ 'one',
+ ));
+
+ $this->parser->setDefaults(array(
+ 'two' => function (Options $options) use ($test) {
+ $test->assertTrue(isset($options['one']));
+
+ return $options['one'] . '2';
+ },
+ ));
+
+ $options = array(
+ 'one' => '10',
+ );
+
+ $this->assertEquals(array(
+ 'one' => '10',
+ 'two' => '102',
+ ), $this->parser->parse($options));
+ }
+
+ public function testParseLazyDependencyOnRequired()
+ {
+ $this->parser->setRequired(array(
+ 'one',
+ ));
+ $this->parser->setDefaults(array(
+ 'two' => function (Options $options) {
+ return $options['one'] . '2';
+ },
+ ));
+
+ $options = array(
+ 'one' => '10',
+ );
+
+ $this->assertEquals(array(
+ 'one' => '10',
+ 'two' => '102',
+ ), $this->parser->parse($options));
+ }
+
+ /**
+ * @expectedException Symfony\Component\OptionsParser\Exception\InvalidOptionsException
+ */
+ public function testParseFailsIfNonExistingOption()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ ));
+
+ $this->parser->setRequired(array(
+ 'two',
+ ));
+
+ $this->parser->setOptional(array(
+ 'three',
+ ));
+
+ $this->parser->parse(array(
+ 'foo' => 'bar',
+ ));
+ }
+
+ /**
+ * @expectedException Symfony\Component\OptionsParser\Exception\MissingOptionsException
+ */
+ public function testParseFailsIfMissingRequiredOption()
+ {
+ $this->parser->setRequired(array(
+ 'one',
+ ));
+
+ $this->parser->setDefaults(array(
+ 'two' => '2',
+ ));
+
+ $this->parser->parse(array(
+ 'two' => '20',
+ ));
+ }
+
+ public function testParseSucceedsIfOptionValueAllowed()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ ));
+
+ $this->parser->setAllowedValues(array(
+ 'one' => array('1', 'one'),
+ ));
+
+ $options = array(
+ 'one' => 'one',
+ );
+
+ $this->assertEquals(array(
+ 'one' => 'one',
+ ), $this->parser->parse($options));
+ }
+
+ public function testParseSucceedsIfOptionValueAllowed2()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ 'two' => '2',
+ ));
+
+ $this->parser->addAllowedValues(array(
+ 'one' => array('1'),
+ 'two' => array('2'),
+ ));
+ $this->parser->addAllowedValues(array(
+ 'one' => array('one'),
+ 'two' => array('two'),
+ ));
+
+ $options = array(
+ 'one' => '1',
+ 'two' => 'two',
+ );
+
+ $this->assertEquals(array(
+ 'one' => '1',
+ 'two' => 'two',
+ ), $this->parser->parse($options));
+ }
+
+ /**
+ * @expectedException Symfony\Component\OptionsParser\Exception\InvalidOptionsException
+ */
+ public function testParseFailsIfOptionValueNotAllowed()
+ {
+ $this->parser->setDefaults(array(
+ 'one' => '1',
+ ));
+
+ $this->parser->setAllowedValues(array(
+ 'one' => array('1', 'one'),
+ ));
+
+ $this->parser->parse(array(
+ 'one' => '2',
+ ));
+ }
+
+ /**
+ * @expectedException Symfony\Component\OptionsParser\Exception\OptionDefinitionException
+ */
+ public function testSetRequiredFailsIfDefaultIsPassed()
+ {
+ $this->parser->setRequired(array(
+ 'one' => '1',
+ ));
+ }
+
+ /**
+ * @expectedException Symfony\Component\OptionsParser\Exception\OptionDefinitionException
+ */
+ public function testSetOptionalFailsIfDefaultIsPassed()
+ {
+ $this->parser->setOptional(array(
+ 'one' => '1',
+ ));
+ }
+}
diff --git a/src/Symfony/Component/Form/Tests/OptionsTest.php b/src/Symfony/Component/OptionsParser/Tests/OptionsTest.php
similarity index 91%
rename from src/Symfony/Component/Form/Tests/OptionsTest.php
rename to src/Symfony/Component/OptionsParser/Tests/OptionsTest.php
index 2590adb396..0d4ab9209b 100644
--- a/src/Symfony/Component/Form/Tests/OptionsTest.php
+++ b/src/Symfony/Component/OptionsParser/Tests/OptionsTest.php
@@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form\Tests;
+namespace Symfony\Component\OptionsParser\Tests;
-use Symfony\Component\Form\Options;
+use Symfony\Component\OptionsParser\Options;
class OptionsTest extends \PHPUnit_Framework_TestCase
{
@@ -50,7 +50,7 @@ class OptionsTest extends \PHPUnit_Framework_TestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\OptionDefinitionException
+ * @expectedException Symfony\Component\OptionsParser\Exception\OptionDefinitionException
*/
public function testSetNotSupportedAfterGet()
{
@@ -60,7 +60,7 @@ class OptionsTest extends \PHPUnit_Framework_TestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\OptionDefinitionException
+ * @expectedException Symfony\Component\OptionsParser\Exception\OptionDefinitionException
*/
public function testUnsetNotSupportedAfterGet()
{
@@ -151,7 +151,7 @@ class OptionsTest extends \PHPUnit_Framework_TestCase
}
/**
- * @expectedException Symfony\Component\Form\Exception\OptionDefinitionException
+ * @expectedException Symfony\Component\OptionsParser\Exception\OptionDefinitionException
*/
public function testLazyOptionDisallowCyclicDependencies()
{
diff --git a/src/Symfony/Component/OptionsParser/Tests/bootstrap.php b/src/Symfony/Component/OptionsParser/Tests/bootstrap.php
new file mode 100644
index 0000000000..547252172d
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/Tests/bootstrap.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+spl_autoload_register(function ($class) {
+ if (0 === strpos(ltrim($class, '/'), 'Symfony\Component\OptionsParser')) {
+ if (file_exists($file = __DIR__.'/../'.substr(str_replace('\\', '/', $class), strlen('Symfony\Component\OptionsParser')).'.php')) {
+ require_once $file;
+ }
+ }
+});
diff --git a/src/Symfony/Component/OptionsParser/composer.json b/src/Symfony/Component/OptionsParser/composer.json
new file mode 100644
index 0000000000..6ea87546f9
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "symfony/options-parser",
+ "type": "library",
+ "description": "Symfony OptionsParser Component",
+ "keywords": [],
+ "homepage": "http://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "autoload": {
+ "psr-0": { "Symfony\\Component\\OptionsParser": "" }
+ },
+ "target-dir": "Symfony/Component/OptionsParser",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.1-dev"
+ }
+ }
+}
diff --git a/src/Symfony/Component/OptionsParser/phpunit.xml.dist b/src/Symfony/Component/OptionsParser/phpunit.xml.dist
new file mode 100644
index 0000000000..a10fc7a8df
--- /dev/null
+++ b/src/Symfony/Component/OptionsParser/phpunit.xml.dist
@@ -0,0 +1,29 @@
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Resources
+ ./Tests
+
+
+
+