Browse Source

Add support for child base route pattern and name in admin class

Virgile Vivier 9 years ago
parent
commit
ee138c7de2

+ 66 - 28
Admin/Admin.php

@@ -145,6 +145,13 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     protected $baseRouteName;
 
+    /**
+     * The cached base route name.
+     *
+     * @var string
+     */
+    private $cachedBaseRouteName;
+
     /**
      * The base route pattern used to generate the routing information.
      *
@@ -152,6 +159,13 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     protected $baseRoutePattern;
 
+    /**
+     * The cached base route pattern.
+     *
+     * @var string
+     */
+    private $cachedBaseRoutePattern;
+
     /**
      * The base name controller used to generate the routing information.
      *
@@ -972,28 +986,40 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getBaseRoutePattern()
     {
-        if (!$this->baseRoutePattern) {
+        if (null !== $this->cachedBaseRoutePattern) {
+            return $this->cachedBaseRoutePattern;
+        }
+
+        if ($this->isChild()) { // the admin class is a child, prefix it with the parent route pattern
+            if (!$this->baseRoutePattern) {
+                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)));
+                }
+            }
+
+            $this->cachedBaseRoutePattern = sprintf('%s/{id}/%s',
+                $this->getParent()->getBaseRoutePattern(),
+                $this->baseRoutePattern ?: $this->urlize($matches[5], '-')
+            );
+        } elseif ($this->baseRoutePattern) {
+            $this->cachedBaseRoutePattern = $this->baseRoutePattern;
+        } else {
             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)));
             }
 
-            if ($this->isChild()) { // the admin class is a child, prefix it with the parent route name
-                $this->baseRoutePattern = sprintf('%s/{id}/%s',
-                    $this->getParent()->getBaseRoutePattern(),
-                    $this->urlize($matches[5], '-')
-                );
-            } else {
-                $this->baseRoutePattern = sprintf('/%s%s/%s',
-                    empty($matches[1]) ? '' : $this->urlize($matches[1], '-').'/',
-                    $this->urlize($matches[3], '-'),
-                    $this->urlize($matches[5], '-')
-                );
-            }
+            $this->cachedBaseRoutePattern = sprintf('/%s%s/%s',
+                empty($matches[1]) ? '' : $this->urlize($matches[1], '-').'/',
+                $this->urlize($matches[3], '-'),
+                $this->urlize($matches[5], '-')
+            );
         }
 
-        return $this->baseRoutePattern;
+        return $this->cachedBaseRoutePattern;
     }
 
     /**
@@ -1005,28 +1031,40 @@ abstract class Admin implements AdminInterface, DomainObjectInterface
      */
     public function getBaseRouteName()
     {
-        if (!$this->baseRouteName) {
+        if (null !== $this->cachedBaseRouteName) {
+            return $this->cachedBaseRouteName;
+        }
+
+        if ($this->isChild()) { // the admin class is a child, prefix it with the parent route name
+            if (!$this->baseRouteName) {
+                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)));
+                }
+            }
+
+            $this->cachedBaseRouteName = sprintf('%s_%s',
+                $this->getParent()->getBaseRouteName(),
+                $this->baseRouteName ?: $this->urlize($matches[5])
+            );
+        } elseif ($this->baseRouteName) {
+            $this->cachedBaseRouteName = $this->baseRouteName;
+        } else {
             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)));
             }
 
-            if ($this->isChild()) { // the admin class is a child, prefix it with the parent route name
-                $this->baseRouteName = sprintf('%s_%s',
-                    $this->getParent()->getBaseRouteName(),
-                    $this->urlize($matches[5])
-                );
-            } else {
-                $this->baseRouteName = sprintf('admin_%s%s_%s',
-                    empty($matches[1]) ? '' : $this->urlize($matches[1]).'_',
-                    $this->urlize($matches[3]),
-                    $this->urlize($matches[5])
-                );
-            }
+            $this->cachedBaseRouteName = sprintf('admin_%s%s_%s',
+                empty($matches[1]) ? '' : $this->urlize($matches[1]).'_',
+                $this->urlize($matches[3]),
+                $this->urlize($matches[5])
+            );
         }
 
-        return $this->baseRouteName;
+        return $this->cachedBaseRouteName;
     }
 
     /**

+ 46 - 0
Resources/doc/reference/routing.rst

@@ -46,6 +46,30 @@ route names for your actions like 'admin_vendor_bundlename_entityname_list'.
 If the Admin fails to find a baseRouteName for your Admin class a ``RuntimeException``
 will be thrown with a related message.
 
+If the admin class is a child of another admin class the route name will be prefixed by the parent route name, example :
+
+.. code-block:: php
+
+    <?php
+    // The parent admin class
+    class PostAdmin extends Admin
+    {
+        protected $baseRouteName = 'sonata_post';
+        // ...
+    }
+
+    // The child admin class
+    class CommentAdmin extends Admin
+    {
+        protected $baseRouteName = 'comment'
+        // will result in routes named :
+        //   sonata_post_comment_list
+        //   sonata_post_comment_create
+        //   etc..
+
+        // ...
+    }
+
 Route patterns (URLs)
 ^^^^^^^^^^^^^^^^^^^^^
 
@@ -68,6 +92,28 @@ use the following code:
 You will then have route URLs like ``http://yourdomain.com/admin/foo/list`` and
 ``http://yourdomain.com/admin/foo/1/edit``
 
+If the admin class is a child of another admin class the route pattern will be prefixed by the parent route pattern, example :
+
+.. code-block:: php
+
+    <?php
+    // The parent admin class
+    class PostAdmin extends Admin
+    {
+        protected $baseRoutePattern = 'post';
+        // ...
+    }
+
+    // The child admin class
+    class CommentAdmin extends Admin
+    {
+        protected $baseRoutePattern = 'comment'
+        // ...
+    }
+
+For comment you will then have route URLs like ``http://yourdomain.com/admin/post/{postId}/comment/list`` and
+``http://yourdomain.com/admin/post/{postId}/comment/{commentId}/edit``
+
 Routing usage
 -------------
 

+ 34 - 0
Tests/Admin/AdminTest.php

@@ -16,9 +16,11 @@ use Sonata\AdminBundle\Admin\AdminInterface;
 use Sonata\AdminBundle\Route\DefaultRouteGenerator;
 use Sonata\AdminBundle\Route\RoutesCache;
 use Sonata\AdminBundle\Tests\Fixtures\Admin\CommentAdmin;
+use Sonata\AdminBundle\Tests\Fixtures\Admin\CommentWithCustomRouteAdmin;
 use Sonata\AdminBundle\Tests\Fixtures\Admin\FieldDescription;
 use Sonata\AdminBundle\Tests\Fixtures\Admin\ModelAdmin;
 use Sonata\AdminBundle\Tests\Fixtures\Admin\PostAdmin;
+use Sonata\AdminBundle\Tests\Fixtures\Admin\PostWithCustomRouteAdmin;
 use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\Post;
 use Sonata\AdminBundle\Tests\Fixtures\Bundle\Entity\Tag;
 use Sonata\AdminBundle\Tests\Fixtures\Entity\FooToString;
@@ -460,6 +462,22 @@ class AdminTest extends \PHPUnit_Framework_TestCase
         $this->assertSame('/sonata/news/post/{id}/comment', $commentAdmin->getBaseRoutePattern());
     }
 
+    public function testGetBaseRoutePatternWithSpecifedPattern()
+    {
+        $postAdmin = new PostWithCustomRouteAdmin('sonata.post.admin.post_with_custom_route', 'Application\Sonata\NewsBundle\Entity\Post', 'SonataNewsBundle:PostWithCustomRouteAdmin');
+
+        $this->assertSame('/post-custom', $postAdmin->getBaseRoutePattern());
+    }
+
+    public function testGetBaseRoutePatternWithChildAdminAndWithSpecifedPattern()
+    {
+        $postAdmin = new PostAdmin('sonata.post.admin.post', 'Application\Sonata\NewsBundle\Entity\Post', 'SonataNewsBundle:PostAdmin');
+        $commentAdmin = new CommentWithCustomRouteAdmin('sonata.post.admin.comment_with_custom_route', 'Application\Sonata\NewsBundle\Entity\Comment', 'SonataNewsBundle:CommentWithCustomRouteAdmin');
+        $commentAdmin->setParent($postAdmin);
+
+        $this->assertSame('/sonata/news/post/{id}/comment-custom', $commentAdmin->getBaseRoutePattern());
+    }
+
     /**
      * @expectedException RuntimeException
      */
@@ -580,6 +598,22 @@ class AdminTest extends \PHPUnit_Framework_TestCase
         $admin->getBaseRouteName();
     }
 
+    public function testGetBaseRouteNameWithSpecifiedName()
+    {
+        $postAdmin = new PostWithCustomRouteAdmin('sonata.post.admin.post_with_custom_route', 'Application\Sonata\NewsBundle\Entity\Post', 'SonataNewsBundle:PostAdmin');
+
+        $this->assertSame('post_custom', $postAdmin->getBaseRouteName());
+    }
+
+    public function testGetBaseRouteNameWithChildAdminAndWithSpecifiedName()
+    {
+        $postAdmin = new PostAdmin('sonata.post.admin.post', 'Application\Sonata\NewsBundle\Entity\Post', 'SonataNewsBundle:PostAdmin');
+        $commentAdmin = new CommentWithCustomRouteAdmin('sonata.post.admin.comment_with_custom_route', 'Application\Sonata\NewsBundle\Entity\Comment', 'SonataNewsBundle:CommentWithCustomRouteAdmin');
+        $commentAdmin->setParent($postAdmin);
+
+        $this->assertSame('admin_sonata_news_post_comment_custom', $commentAdmin->getBaseRouteName());
+    }
+
     /**
      * @covers Sonata\AdminBundle\Admin\Admin::setUniqid
      * @covers Sonata\AdminBundle\Admin\Admin::getUniqid

+ 12 - 0
Tests/Fixtures/Admin/CommentWithCustomRouteAdmin.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace Sonata\AdminBundle\Tests\Fixtures\Admin;
+
+use Sonata\AdminBundle\Admin\Admin;
+use Sonata\AdminBundle\Route\RouteCollection;
+
+class CommentWithCustomRouteAdmin extends CommentAdmin
+{
+    protected $baseRoutePattern = 'comment-custom';
+    protected $baseRouteName = 'comment_custom';
+}

+ 9 - 0
Tests/Fixtures/Admin/PostWithCustomRouteAdmin.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace Sonata\AdminBundle\Tests\Fixtures\Admin;
+
+class PostWithCustomRouteAdmin extends PostAdmin
+{
+    protected $baseRoutePattern = '/post-custom';
+    protected $baseRouteName = 'post_custom';
+}