Преглед на файлове

[FrameworkBundle] added a DIC tag-based constraint validator factory

Kris Wallsmith преди 14 години
родител
ревизия
e1f842344e

+ 4 - 1
src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml

@@ -6,7 +6,6 @@
 
     <parameters>
         <parameter key="validator.class">Symfony\Component\Validator\Validator</parameter>
-        <parameter key="validator.validator_factory.class">Symfony\Component\Validator\Extension\DependencyInjectionValidatorFactory</parameter>
         <parameter key="validator.mapping.class_metadata_factory.class">Symfony\Component\Validator\Mapping\ClassMetadataFactory</parameter>
         <parameter key="validator.mapping.loader.loader_chain.class">Symfony\Component\Validator\Mapping\Loader\LoaderChain</parameter>
         <parameter key="validator.mapping.loader.static_method_loader.class">Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader</parameter>
@@ -16,6 +15,7 @@
         <parameter key="validator.mapping.loader.xml_files_loader.class">Symfony\Component\Validator\Mapping\Loader\XmlFilesLoader</parameter>
         <parameter key="validator.mapping.loader.yaml_files_loader.class">Symfony\Component\Validator\Mapping\Loader\YamlFilesLoader</parameter>
         <parameter key="validator.mapping.loader.static_method_loader.method_name">loadValidatorMetadata</parameter>
+        <parameter key="validator.validator_factory.class">Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory</parameter>
     </parameters>
 
     <services>
@@ -30,6 +30,9 @@
 
         <service id="validator.validator_factory" class="%validator.validator_factory.class%">
             <argument type="service" id="service_container" />
+            <call method="loadTaggedServiceIds">
+                <argument type="service" id="service_container" />
+            </call>
         </service>
 
         <service id="validator.mapping.loader.loader_chain" class="%validator.mapping.loader.loader_chain.class%">

+ 64 - 0
src/Symfony/Bundle/FrameworkBundle/Tests/Validator/ConstraintValidatorFactoryTest.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace Symfony\Bundle\FrameworkBundle\Tests\Validator;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+use Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory;
+use Symfony\Component\DependencyInjection\Container;
+
+class ConstraintValidatorFactoryTest extends \PHPUnit_Framework_TestCase
+{
+    public function testLoadTaggedServiceIdsSetsValidators()
+    {
+        $service = 'validator_constraint_service';
+        $alias = 'validator_constraint_alias';
+        $validator = new \stdClass();
+
+        // mock ContainerBuilder b/c it implements TaggedContainerInterface
+        $container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerBuilder');
+        $container
+            ->expects($this->once())
+            ->method('findTaggedServiceIds')
+            ->with('validator.constraint_validator')
+            ->will($this->returnValue(array(
+                $service => array(array('alias' => $alias)),
+            )));
+        $container
+            ->expects($this->once())
+            ->method('get')
+            ->with($service)
+            ->will($this->returnValue($validator));
+
+        $constraint = $this->getMock('Symfony\\Component\\Validator\\Constraint');
+        $constraint
+            ->expects($this->once())
+            ->method('validatedBy')
+            ->will($this->returnValue($alias));
+
+        $factory = new ConstraintValidatorFactory($container);
+        $factory->loadTaggedServiceIds($container);
+        $this->assertSame($validator, $factory->getInstance($constraint));
+    }
+
+    public function testGetInstanceException()
+    {
+        $this->setExpectedException('InvalidArgumentException');
+
+        $constraint = $this->getMock('Symfony\\Component\\Validator\\Constraint');
+        $constraint
+            ->expects($this->once())
+            ->method('validatedBy')
+            ->will($this->returnValue('foo'));
+
+        $factory = new ConstraintValidatorFactory(new Container());
+        $factory->getInstance($constraint);
+    }
+}

+ 76 - 0
src/Symfony/Bundle/FrameworkBundle/Validator/ConstraintValidatorFactory.php

@@ -0,0 +1,76 @@
+<?php
+
+namespace Symfony\Bundle\FrameworkBundle\Validator;
+
+/*
+ * This file is part of the Symfony framework.
+ *
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\TaggedContainerInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
+
+/**
+ * Uses a service container to create constraint validators.
+ *
+ * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
+ */
+class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
+{
+    protected $container;
+    protected $validators = array();
+
+    /**
+     * Constructor.
+     *
+     * @param ContainerInterface $container The service container
+     */
+    public function __construct(ContainerInterface $container)
+    {
+        $this->container = $container;
+    }
+
+    /**
+     * Loads ids for services tagged as constraint validators.
+     *
+     * @param TaggedContainerInterface $container The tagged service container
+     */
+    public function loadTaggedServiceIds(TaggedContainerInterface $container)
+    {
+        foreach ($container->findTaggedServiceIds('validator.constraint_validator') as $id => $attributes) {
+            if (isset($attributes[0]['alias'])) {
+                $this->validators[$attributes[0]['alias']] = $id;
+            }
+        }
+    }
+
+    /**
+     * Returns the validator for the supplied constraint.
+     *
+     * @param Constraint $constraint A constraint
+     *
+     * @return Symfony\Component\Validator\ConstraintValidator A validator for the supplied constraint
+     *
+     * @throws InvalidArgumentException If no validator for the supplied constraint is found
+     */
+    public function getInstance(Constraint $constraint)
+    {
+        $name = $constraint->validatedBy();
+
+        if (!isset($this->validators[$name])) {
+            throw new \InvalidArgumentException(sprintf('There is no "%s" constraint validator.', $name));
+        }
+
+        if (is_string($this->validators[$name])) {
+            $this->validators[$name] = $this->container->get($this->validators[$name]);
+        }
+
+        return $this->validators[$name];
+    }
+}