diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php index f4c61891bddc..dd7b14ed64b6 100644 --- a/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php +++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/ExprBuilder.php @@ -6,6 +6,7 @@ * This class builds an if expression. * * @author Johannes M. Schmitt + * @author Christophe Coevoet */ class ExprBuilder { @@ -23,6 +24,18 @@ public function __construct($parent) $this->parent = $parent; } + /** + * Mark the expression as being always used. + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ExprBuilder + */ + public function always() + { + $this->ifPart = function($v) { return true; }; + + return $this; + } + /** * Sets a closure to use as tests. * @@ -78,6 +91,20 @@ public function ifArray() return $this; } + /** + * Tests if the value is in an array. + * + * @param array $array + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ExprBuilder + */ + public function ifInArray(array $array) + { + $this->ifPart = function($v) use ($array) { return in_array($v, $array, true); }; + + return $this; + } + /** * Sets the closure to run if the test pass. * @@ -104,6 +131,32 @@ public function thenEmptyArray() return $this; } + /** + * Sets a closure marking the value as invalid at validation time. + * + * @param string $message + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ExprBuilder + */ + public function thenInvalid($message) + { + $this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException($message); }; + + return $this; + } + + /** + * Sets a closure unsetting this key of the array at validation time. + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ExprBuilder + */ + public function thenUnset() + { + $this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); }; + + return $this; + } + /** * Returns the parent node * diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php index 7d2dec2df00d..e6f73c8e9f2f 100644 --- a/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php +++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/NodeBuilder.php @@ -19,6 +19,7 @@ class NodeBuilder public $children; public $prototype; public $normalization; + public $validation; public $merge; public $finalization; public $defaultValue; @@ -393,6 +394,34 @@ public function performNoDeepMerging() return $this; } + /** + * Gets the builder for validation rules. + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ValidationBuilder + */ + protected function validation() + { + if (null === $this->validation) { + $this->validation = new ValidationBuilder($this); + } + + return $this->validation; + } + + /** + * Sets an expression to run for the validation. + * + * The expression receives the value of the node and must return it. It can + * modify it. + * An exception should be thrown when the node is not valid. + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ExprBuilder + */ + public function validate() + { + return $this->validation()->rule(); + } + /** * Returns the parent node. * diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php index 71a0132cc918..806b8e4863c1 100644 --- a/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php +++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/TreeBuilder.php @@ -129,6 +129,12 @@ protected function configureScalarNode(ScalarNode $configNode, NodeBuilder $node $configNode->addEquivalentValue(true, $node->trueEquivalent); $configNode->addEquivalentValue(false, $node->falseEquivalent); $configNode->setRequired($node->required); + + if (null !== $node->validation) { + $configNode->setFinalValidationClosures( + $this->buildExpressions($node->validation->rules) + ); + } } /** @@ -185,6 +191,12 @@ protected function createArrayConfigNode(NodeBuilder $node) $configNode->setDefaultValue($node->defaultValue); } + if (null !== $node->validation) { + $configNode->setFinalValidationClosures( + $this->buildExpressions($node->validation->rules) + ); + } + return $configNode; } diff --git a/src/Symfony/Component/DependencyInjection/Configuration/Builder/ValidationBuilder.php b/src/Symfony/Component/DependencyInjection/Configuration/Builder/ValidationBuilder.php new file mode 100644 index 000000000000..8ff45bde9e66 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Configuration/Builder/ValidationBuilder.php @@ -0,0 +1,44 @@ + + */ +class ValidationBuilder +{ + public $parent; + public $rules; + + /** + * Constructor + * + * @param Symfony\Component\DependencyInjection\Configuration\Builder\NodeBuilder $parent + */ + public function __construct($parent) + { + $this->parent = $parent; + + $this->rules = array(); + } + + /** + * Registers a closure to run as normalization or an expression builder to build it if null is provided. + * + * @param \Closure $closure + * + * @return Symfony\Component\DependencyInjection\Configuration\Builder\ExprBuilder|Symfony\Component\DependencyInjection\Configuration\Builder\ValidationBuilder + */ + public function rule(\Closure $closure = null) + { + if (null !== $closure) { + $this->rules[] = $closure; + + return $this; + } + + return $this->rules[] = new ExprBuilder($this->parent); + } +} \ No newline at end of file