Explorar o código

Change Admin::getClass logic to use subclass/subject class

Fix Issue #1466 create/update routing problem in form creation, when id is 0
Fix in part Issue sonata-project/SonataDoctrineORMAdminBundle#250
Fix Issue #924 Broken field description when using subclasses
tashanta %!s(int64=12) %!d(string=hai) anos
pai
achega
9d7f443ef2

+ 45 - 29
Admin/Admin.php

@@ -847,7 +847,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
     public function getBaseRoutePattern()
     {
         if (!$this->baseRoutePattern) {
-            preg_match(self::CLASS_REGEX, $this->getClass(), $matches);
+            preg_match(self::CLASS_REGEX, $this->class, $matches);
 
             if (!$matches) {
                 throw new \RuntimeException(sprintf('Please define a default `baseRoutePattern` value for the admin class `%s`', get_class($this)));
@@ -881,7 +881,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
     public function getBaseRouteName()
     {
         if (!$this->baseRouteName) {
-            preg_match(self::CLASS_REGEX, $this->getClass(), $matches);
+            preg_match(self::CLASS_REGEX, $this->class , $matches);
 
             if (!$matches) {
                 throw new \RuntimeException(sprintf('Cannot automatically determine base route name, please define a default `baseRouteName` value for the admin class `%s`', get_class($this)));
@@ -923,13 +923,23 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getClass()
     {
-        return $this->class;
+        if (!$this->hasActiveSubClass()) {
+            $subject = $this->getSubject();
+
+            if ($subject) {
+                return get_class($subject);
+            }
+
+            return $this->class;
+        }
+
+        $subClass = $this->getRequest()->query->get('subclass');
+
+        return $this->getSubClass($subClass);
     }
 
     /**
-     * Returns the list of supported sub classes
-     *
-     * @return array the list of sub classes
+     * {@inheritdoc}
      */
     public function getSubClasses()
     {
@@ -937,9 +947,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
     }
 
     /**
-     * Sets the list of supported sub classes
-     *
-     * @param array $subClasses the list of sub classes
+     * {@inheritdoc}
      */
     public function setSubClasses(array $subClasses)
     {
@@ -963,11 +971,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
     }
 
     /**
-     * Returns true if the admin has the sub classes
-     *
-     * @param string $name The name of the sub class
-     *
-     * @return bool
+     * {@inheritdoc}
      */
     public function hasSubClass($name)
     {
@@ -975,35 +979,47 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
     }
 
     /**
-     * Returns true if a subclass is currently active
-     *
-     * @return bool
+     * {@inheritdoc}
      */
     public function hasActiveSubClass()
     {
         if ($this->request) {
-            return null !== $this->getRequest()->get('subclass');
+            return null !== $this->getRequest()->query->get('subclass');
         }
 
         return false;
     }
 
     /**
-     * Returns the currently active sub class
-     *
-     * @return string the active sub class
+     * {@inheritdoc}
      */
     public function getActiveSubClass()
     {
         if (!$this->hasActiveSubClass()) {
             return null;
         }
-
-        $subClass = $this->getRequest()->get('subclass');
-
-        return $this->getSubClass($subClass);
+        
+        return $this->getClass();
     }
-
+    
+    /**
+     * {@inheritdoc}
+     */
+    public function getActiveSubclassCode()
+    {
+        if (!$this->hasActiveSubClass()) {
+            return null;
+        }
+        
+        $subClass = $this->getRequest()->query->get('subclass');
+        
+        if(! $this->hasSubClass($subClass)){
+            return null;
+        }
+        
+        return $subClass;
+    }
+    
     /**
      * Returns the list of batchs actions
      *
@@ -1183,7 +1199,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getNewInstance()
     {
-        $object = $this->getModelManager()->getModelInstance($this->getActiveSubClass() ?: $this->getClass());
+        $object = $this->getModelManager()->getModelInstance($this->getClass());
         foreach($this->getExtensions() as $extension) {
             $extension->alterNewInstance($this, $object);
         }
@@ -1196,7 +1212,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getFormBuilder()
     {
-        $this->formOptions['data_class'] = $this->getActiveSubClass() ?: $this->getClass();
+        $this->formOptions['data_class'] = $this->getClass();
 
         $formBuilder = $this->getFormContractor()->getFormBuilder(
             $this->getUniqid(),
@@ -1582,7 +1598,7 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
             if (!preg_match('#^[0-9A-Fa-f]+$#', $id)) {
                 $this->subject = false;
             } else {
-                $this->subject = $this->getModelManager()->find($this->getClass(), $id);
+                $this->subject = $this->getModelManager()->find($this->class, $id);
             }
         }
 

+ 42 - 1
Admin/AdminInterface.php

@@ -80,7 +80,10 @@ interface AdminInterface
     public function setRouteGenerator(RouteGeneratorInterface $routeGenerator);
 
     /**
-     * Returns the class name managed
+     * Returns subjectClass/class/subclass name managed
+     * - subclass name if subclass parameter is defined
+     * - subject class name if subject is defined
+     * - class name if not
      *
      * @return string
      */
@@ -624,4 +627,42 @@ interface AdminInterface
      * @return boolean
      */
     public function isAclEnabled();
+
+    /**
+     * Sets the list of supported sub classes
+     *
+     * @param array $subClasses the list of sub classes
+     */
+    public function setSubClasses(array $subClasses);
+
+    /**
+     * Returns true if the admin has the sub classes
+     *
+     * @param string $name The name of the sub class
+     *
+     * @return bool
+     */
+    public function hasSubClass($name);
+
+    /**
+     * Returns true if a subclass is currently active
+     *
+     * @return bool
+     */
+    public function hasActiveSubClass();
+
+    /**
+     * Returns the currently active sub class
+     *
+     * @return string the active sub class
+     */
+    public function getActiveSubClass();
+    
+    /**
+     * Returns the currently active sub class code
+     * 
+     * @return string the code for active sub class
+     */
+    public function getActiveSubclassCode();
+
 }

+ 1 - 1
Resources/views/CRUD/base_edit.html.twig

@@ -12,7 +12,7 @@ file that was distributed with this source code.
 {% extends base_template %}
 
 {% block title %}
-    {% if admin.id(object) %}
+    {% if admin.id(object) is not null %}
         {{ "title_edit"|trans({'%name%': admin.toString(object) }, 'SonataAdminBundle') }}
     {% else %}
         {{ "title_create"|trans({}, 'SonataAdminBundle') }}

+ 3 - 3
Resources/views/CRUD/base_edit_form.html.twig

@@ -1,5 +1,5 @@
 {% block form %}
-    {% set url = admin.id(object) ? 'edit' : 'create' %}
+    {% set url = admin.id(object) is not null ? 'edit' : 'create' %}
 
     {% if not admin.hasRoute(url)%}
         <div>
@@ -60,7 +60,7 @@
             {% block formactions %}
                 <div class="well form-actions">
                     {% if app.request.isxmlhttprequest %}
-                        {% if admin.id(object) %}
+                        {% if admin.id(object) is not null %}
                             <input type="submit" class="btn btn-primary" name="btn_update" value="{{ 'btn_update'|trans({}, 'SonataAdminBundle') }}"/>
                         {% else %}
                             <input type="submit" class="btn" name="btn_create" value="{{ 'btn_create'|trans({}, 'SonataAdminBundle') }}"/>
@@ -72,7 +72,7 @@
                                 {{ 'btn_preview'|trans({}, 'SonataAdminBundle') }}
                             </button>
                         {% endif %}
-                        {% if admin.id(object) %}
+                        {% if admin.id(object) is not null %}
                             <input type="submit" class="btn btn-primary" name="btn_update_and_edit" value="{{ 'btn_update_and_edit_again'|trans({}, 'SonataAdminBundle') }}"/>
 
                             {% if admin.hasroute('list') %}

+ 47 - 0
Tests/Admin/BaseAdminTest.php

@@ -312,4 +312,51 @@ class BaseAdminTest extends \PHPUnit_Framework_TestCase
         $commentAdmin->setSecurityHandler($this->getMock('Sonata\AdminBundle\Security\Handler\AclSecurityHandlerInterface'));
         $this->assertTrue($commentAdmin->isAclEnabled());
     }
+    
+    /**
+     * @covers Sonata\AdminBundle\Admin\Admin::getSubClasses
+     * @covers Sonata\AdminBundle\Admin\Admin::getSubClass
+     * @covers Sonata\AdminBundle\Admin\Admin::setSubClasses
+     * @covers Sonata\AdminBundle\Admin\Admin::hasSubClass
+     * @covers Sonata\AdminBundle\Admin\Admin::hasActiveSubClass
+     * @covers Sonata\AdminBundle\Admin\Admin::getActiveSubClass
+     * @covers Sonata\AdminBundle\Admin\Admin::getActiveSubclassCode
+     * @covers Sonata\AdminBundle\Admin\Admin::getClass
+     */
+    public function testSubClass()
+    {
+        $admin = new PostAdmin('sonata.post.admin.post', 'NewsBundle\Entity\Post', 'SonataNewsBundle:PostAdmin');
+        $this->assertFalse($admin->hasSubClass('test'));
+        $this->assertFalse($admin->hasActiveSubClass());
+        $this->assertCount(0, $admin->getSubClasses());
+        $this->assertNull($admin->getActiveSubClass());
+        $this->assertNull($admin->getActiveSubclassCode());
+        $this->assertEquals('NewsBundle\Entity\Post', $admin->getClass());
+        
+        $admin->setSubject(new \stdClass());
+        $this->assertEquals('stdClass', $admin->getClass());
+        
+        $admin->setSubClasses(array('extended1' => 'NewsBundle\Entity\PostExtended1', 'extended2' => 'NewsBundle\Entity\PostExtended2'));
+        $this->assertFalse($admin->hasSubClass('test'));
+        $this->assertTrue($admin->hasSubClass('extended1'));
+        $this->assertFalse($admin->hasActiveSubClass());
+        $this->assertCount(2, $admin->getSubClasses());
+        $this->assertNull($admin->getActiveSubClass());
+        $this->assertNull($admin->getActiveSubclassCode());
+        $this->assertEquals('stdClass', $admin->getClass());
+        
+        $request = new \Symfony\Component\HttpFoundation\Request(array('subclass' => 'extended1'));
+        $admin->setRequest($request);
+        $this->assertFalse($admin->hasSubClass('test'));
+        $this->assertTrue($admin->hasSubClass('extended1'));
+        $this->assertTrue($admin->hasActiveSubClass());
+        $this->assertCount(2, $admin->getSubClasses());
+        $this->assertEquals('NewsBundle\Entity\PostExtended1', $admin->getActiveSubClass());
+        $this->assertEquals('extended1', $admin->getActiveSubclassCode());
+        $this->assertEquals('NewsBundle\Entity\PostExtended1', $admin->getClass());
+        
+        $request->query->set('subclass', 'inject');
+        $this->assertNull($admin->getActiveSubClass());
+        $this->assertNull($admin->getActiveSubclassCode());
+    }
 }