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 + + + +