Browse Source

Fix validation with nested schema information

Thomas Rabaix 13 years ago
parent
commit
32d59e6c2f
4 changed files with 78 additions and 28 deletions
  1. 33 20
      Admin/Admin.php
  2. 22 1
      Admin/AdminInterface.php
  3. 10 0
      Validator/Constraints/InlineConstraint.php
  4. 13 7
      Validator/InlineValidator.php

+ 33 - 20
Admin/Admin.php

@@ -328,6 +328,9 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
     protected $securityHandler = null;
 
+    /**
+     * @var \Symfony\Component\Validator\ValidatorInterface $validator
+     */
     protected $validator = null;
 
     /**
@@ -445,20 +448,6 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
     }
 
-    /**
-     * @param \Sonata\AdminBundle\Validator\ErrorElement $errorElement
-     * @param $object
-     * @return void
-     */
-    public function doValidate(ErrorElement $errorElement, $object)
-    {
-        $this->validate($errorElement, $object);
-
-        foreach ($this->extensions as $extension) {
-            $extension->validate($this, $errorElement, $object);
-        }
-    }
-
     /**
      * @param string $code
      * @param string $class
@@ -596,7 +585,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
         $this->configureListFields($mapper);
 
-        foreach($this->extensions as $extension) {
+        foreach($this->getExtensions() as $extension) {
             $extension->configureListFields($mapper);
         }
     }
@@ -659,7 +648,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
             ));
         }
 
-        foreach($this->extensions as $extension) {
+        foreach($this->getExtensions() as $extension) {
             $extension->configureDatagridFilters($mapper);
         }
     }
@@ -865,7 +854,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
         $this->configureRoutes($this->routes);
 
-        foreach($this->extensions as $extension) {
+        foreach($this->getExtensions() as $extension) {
             $extension->configureRoutes($this, $this->routes);
         }
     }
@@ -1052,11 +1041,27 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getFormBuilder()
     {
+        $admin = $this;
+
         // add the custom inline validation option
         $metadata = $this->validator->getMetadataFactory()->getClassMetadata($this->getClass());
         $metadata->addConstraint(new \Sonata\AdminBundle\Validator\Constraints\InlineConstraint(array(
             'service' => $this,
-            'method'  => 'doValidate'
+            'method'  => function(ErrorElement $errorElement, $object) use ($admin) {
+                /* @var \Sonata\AdminBundle\Admin\AdminInterface $admin */
+
+                // This avoid the main validation to be cascaded to children
+                // The problem occurs when a model Page has a collection of Page as property
+                if ($admin->hasSubject() && spl_object_hash($object) !== spl_object_hash($admin->getSubject())) {
+                    return;
+                }
+
+                $admin->validate($errorElement, $object);
+
+                foreach ($admin->getExtensions() as $extension) {
+                    $extension->validate($admin, $errorElement, $object);
+                }
+            }
         )));
 
         $this->formOptions['data_class'] = $this->getClass();
@@ -1081,7 +1086,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
         $this->configureFormFields($mapper);
 
-        foreach($this->extensions as $extension) {
+        foreach($this->getExtensions() as $extension) {
             $extension->configureFormFields($mapper);
         }
     }
@@ -1177,7 +1182,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
 
         $this->configureSideMenu($menu, $action, $childAdmin);
 
-        foreach ($this->extensions as $extension) {
+        foreach ($this->getExtensions() as $extension) {
             $extension->configureSideMenu($this, $menu, $action, $childAdmin);
         }
 
@@ -2208,6 +2213,14 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
         $this->extensions[] = $extension;
     }
 
+    /**
+     * @return array
+     */
+    public function getExtensions()
+    {
+        return $this->extensions;
+    }
+
     /**
      * @param \Knp\Menu\FactoryInterface $menuFactory
      * @return void

+ 22 - 1
Admin/AdminInterface.php

@@ -19,6 +19,7 @@ use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
 use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
 use Sonata\AdminBundle\Builder\RouteBuilderInterface;
 use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
+use Sonata\AdminBundle\Validator\ErrorElement;
 
 use Knp\Menu\FactoryInterface as MenuFactoryInterface;
 
@@ -286,6 +287,13 @@ interface AdminInterface
      */
     function addExtension(AdminExtensionInterface $extension);
 
+    /**
+     * Returns an array of extension related to the current Admin
+     * 
+     * @return void
+     */
+    function getExtensions();
+
     /**
      * @param \Knp\Menu\FactoryInterface $menuFactory
      * @return void
@@ -375,7 +383,6 @@ interface AdminInterface
      */
     function getListFieldDescription($name);
 
-
     function configure();
 
     function update($object);
@@ -395,4 +402,18 @@ interface AdminInterface
     function preRemove($object);
 
     function postRemove($object);
+
+    /**
+     * Return true if the Admin is related to a subject
+     *
+     * @return boolean
+     */
+    function hasSubject();
+
+    /**
+     * @param \Sonata\AdminBundle\Validator\ErrorElement $errorElement
+     * @param $object
+     * @return void
+     */
+    function validate(ErrorElement $errorElement, $object);
 }

+ 10 - 0
Validator/Constraints/InlineConstraint.php

@@ -23,6 +23,16 @@ class InlineConstraint extends Constraint
         return 'sonata.admin.validator.inline';
     }
 
+    public function isClosure()
+    {
+        return $this->method instanceof \Closure;
+    }
+
+    public function getClosure()
+    {
+        return $this->method;
+    }
+
     /**
      * {@inheritDoc}
      */

+ 13 - 7
Validator/InlineValidator.php

@@ -28,12 +28,6 @@ class InlineValidator extends ConstraintValidator
 
     public function isValid($value, Constraint $constraint)
     {
-        if (is_string($constraint->getService())) {
-            $service = $this->container->get($constraint->getService());
-        } else {
-            $service = $constraint->getService();
-        }
-
         $errorElement = new ErrorElement(
             $value,
             $this->constraintValidatorFactory,
@@ -41,7 +35,19 @@ class InlineValidator extends ConstraintValidator
             $this->context->getGroup()
         );
 
-        call_user_func(array($service, $constraint->getMethod()), $errorElement, $value);
+        if ($constraint->isClosure()) {
+            $function = $constraint->getClosure();
+        } else {
+            if (is_string($constraint->getService())) {
+                $service = $this->container->get($constraint->getService());
+            } else {
+                $service = $constraint->getService();
+            }
+
+            $function = array($service, $constraint->getMethod());
+        }
+
+        call_user_func($function, $errorElement, $value);
 
         return count($this->context->getViolations()) == 0;
     }