ソースを参照

refactorize the Route generation

Thomas 14 年 前
コミット
67bd124981

+ 41 - 95
Admin/Admin.php

@@ -25,6 +25,8 @@ use Sonata\AdminBundle\Builder\FormBuilderInterface;
 use Sonata\AdminBundle\Builder\ListBuilderInterface;
 use Sonata\AdminBundle\Builder\ListBuilderInterface;
 use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
 use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
 
 
+use Sonata\AdminBundle\Route\RouteCollection;
+
 use Knplabs\MenuBundle\Menu;
 use Knplabs\MenuBundle\Menu;
 use Knplabs\MenuBundle\MenuItem;
 use Knplabs\MenuBundle\MenuItem;
 
 
@@ -153,11 +155,11 @@ abstract class Admin implements AdminInterface
     protected $label;
     protected $label;
 
 
     /**
     /**
-     * Array of urls related to this admin
+     * Array of routes related to this admin
      *
      *
      * @var array
      * @var array
      */
      */
-    protected $urls = array();
+    protected $routes = array();
 
 
     /**
     /**
      * The subject only set in edit/update/create mode
      * The subject only set in edit/update/create mode
@@ -280,7 +282,7 @@ abstract class Admin implements AdminInterface
         'form_groups' => false,
         'form_groups' => false,
         'list_fields' => false,
         'list_fields' => false,
         'filter_fields' => false,
         'filter_fields' => false,
-        'urls'        => false,
+        'routes'        => false,
     );
     );
 
 
     /**
     /**
@@ -348,7 +350,7 @@ abstract class Admin implements AdminInterface
         $this->baseCodeRoute = $this->getCode();
         $this->baseCodeRoute = $this->getCode();
     }
     }
 
 
-    public function configureUrls()
+    public function configureRoutes(RouteCollection $collection)
     {
     {
 
 
     }
     }
@@ -555,7 +557,6 @@ abstract class Admin implements AdminInterface
             if (!$matches) {
             if (!$matches) {
                 throw new \RuntimeException(sprintf('Please define a default `baseRouteName` value for the admin class `%s`', get_class($this)));
                 throw new \RuntimeException(sprintf('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
             if ($this->isChild()) { // the admin class is a child, prefix it with the parent route name
                 $this->baseRouteName = sprintf('%s_%s',
                 $this->baseRouteName = sprintf('%s_%s',
@@ -583,7 +584,6 @@ abstract class Admin implements AdminInterface
      */
      */
     public function urlize($word, $sep = '_')
     public function urlize($word, $sep = '_')
     {
     {
-
         return strtolower(preg_replace('/[^a-z0-9_]/i', $sep.'$1', $word));
         return strtolower(preg_replace('/[^a-z0-9_]/i', $sep.'$1', $word));
     }
     }
 
 
@@ -605,7 +605,6 @@ abstract class Admin implements AdminInterface
      */
      */
     public function getBatchActions()
     public function getBatchActions()
     {
     {
-
         return array(
         return array(
             'delete' => $this->trans('action_delete')
             'delete' => $this->trans('action_delete')
         );
         );
@@ -616,12 +615,11 @@ abstract class Admin implements AdminInterface
      *
      *
      * @return array the list of available urls
      * @return array the list of available urls
      */
      */
-    public function getUrls($baseCode = '')
+    public function getRoutes()
     {
     {
+        $this->buildRoutes();
 
 
-        $this->buildUrls($baseCode);
-
-        return $this->urls;
+        return $this->routes;
     }
     }
 
 
     /**
     /**
@@ -649,106 +647,54 @@ abstract class Admin implements AdminInterface
      *
      *
      * @return void
      * @return void
      */
      */
-    public function buildUrls()
+    public function buildRoutes()
     {
     {
-        if ($this->loaded['urls']) {
+        if ($this->loaded['routes']) {
             return;
             return;
         }
         }
 
 
-        $this->loaded['urls'] = true;
-        
-        $this->urls =  array(
-            $this->baseCodeRoute . '.list' => array(
-                'name'      => $this->getBaseRouteName().'_list',
-                'pattern'   => $this->getBaseRoutePattern().'/list',
-                'defaults'  => array(
-                    '_controller' => $this->getBaseControllerName().':list',
-                    '_sonata_admin' => $this->baseCodeRoute
-                ),
-                'requirements' => array(),
-                'options' => array(),
-                'params'    => array(),
-            ),
-            $this->baseCodeRoute . '.create' => array(
-                'name'      => $this->getBaseRouteName().'_create',
-                'pattern'       => $this->getBaseRoutePattern().'/create',
-                'defaults'  => array(
-                    '_controller' => $this->getBaseControllerName().':create',
-                    '_sonata_admin' => $this->baseCodeRoute
-                ),
-                'requirements' => array(),
-                'options' => array(),
-                'params'    => array(),
-            ),
-            $this->baseCodeRoute . '.edit' => array(
-                'name'      => $this->getBaseRouteName().'_edit',
-                'pattern'   => $this->getBaseRoutePattern().'/'.$this->getRouterIdParameter().'/edit',
-                'defaults'  => array(
-                    '_controller' => $this->getBaseControllerName().':edit',
-                    '_sonata_admin' => $this->baseCodeRoute
-                ),
-                'requirements' => array(),
-                'options' => array(),
-                'params'    => array(),
-            ),
-            $this->baseCodeRoute . '.update' => array(
-                'name'      => $this->getBaseRouteName().'_update',
-                'pattern'       => $this->getBaseRoutePattern().'/update',
-                'defaults'  => array(
-                    '_controller' => $this->getBaseControllerName().':update',
-                    '_sonata_admin' => $this->baseCodeRoute
-                ),
-                'requirements' => array(),
-                'options' => array(),
-                'params'    => array(),
-            ),
-            $this->baseCodeRoute . '.delete' => array(
-                'name'      => $this->getBaseRouteName().'_delete',
-                'pattern'   => $this->getBaseRoutePattern().'/'.$this->getRouterIdParameter().'/delete',
-                'defaults'  => array(
-                    '_controller' => $this->getBaseControllerName().':delete',
-                    '_sonata_admin' => $this->baseCodeRoute
-                ),
-                'requirements' => array(),
-                'options' => array(),
-                'params'    => array(),
-            ),
-            $this->baseCodeRoute . '.batch' => array(
-                'name'      => $this->getBaseRouteName().'_batch',
-                'pattern'       => $this->getBaseRoutePattern().'/batch',
-                'defaults'  => array(
-                    '_controller' => $this->getBaseControllerName().':batch',
-                    '_sonata_admin' => $this->baseCodeRoute
-                ),
-                'requirements' => array(),
-                'options' => array(),
-                'params'    => array(),
-            )
+        $this->loaded['routes'] = true;
+
+        $collection = new \Sonata\AdminBundle\Route\RouteCollection(
+            $this->getBaseCodeRoute(),
+            $this->getBaseRouteName(),
+            $this->getBaseRoutePattern(),
+            $this->getBaseControllerName()
         );
         );
-        
+
+        $collection->add('list');
+        $collection->add('create');
+        $collection->add('update');
+        $collection->add('create');
+        $collection->add('batch');
+        $collection->add('edit', $this->getRouterIdParameter().'/edit');
+        $collection->add('delete', $this->getRouterIdParameter().'/delete');
+
         // add children urls
         // add children urls
         foreach ($this->getChildren() as $children) {
         foreach ($this->getChildren() as $children) {
-            $this->urls = array_merge($this->urls, $children->getUrls());
+            $collection->addCollection($children->getRoutes());
         }
         }
 
 
-        $this->configureUrls();
+        $this->configureRoutes($collection);
+
+        $this->routes = $collection;
     }
     }
 
 
     /**
     /**
      * return the url defined by the $name
      * return the url defined by the $name
      *
      *
-     * @param  $name
-     * @return bool
+     * @param strinf $name
+     * @return Route
      */
      */
-    public function getUrl($name)
+    public function getRoute($name)
     {
     {
-        $urls = $this->getUrls();
+        $this->buildRoutes();
 
 
-        if (!isset($urls[$name])) {
+        if (!$this->routes->has($name)) {
             return false;
             return false;
         }
         }
 
 
-        return $urls[$name];
+        return $this->routes->get($name);
     }
     }
 
 
     /**
     /**
@@ -803,13 +749,13 @@ abstract class Admin implements AdminInterface
         // allows to define persistent parameters 
         // allows to define persistent parameters 
         $parameters = array_merge($this->getPersistentParameters(), $parameters);
         $parameters = array_merge($this->getPersistentParameters(), $parameters);
 
 
-        $url = $this->getUrl($name);
+        $route = $this->getRoute($name);
 
 
-        if (!$url) {
-            throw new \RuntimeException(sprintf('unable to find the url `%s`', $name));
+        if (!$route) {
+            throw new \RuntimeException(sprintf('unable to find the route `%s`', $name));
         }
         }
 
 
-        return $this->router->generate($url['name'], $parameters);
+        return $this->router->generate($route->getDefault('_sonata_name'), $parameters);
     }
     }
 
 
     /**
     /**

+ 2 - 2
Builder/ORM/DatagridBuilder.php

@@ -160,7 +160,7 @@ class DatagridBuilder implements DatagridBuilderInterface
 
 
             case ClassMetadataInfo::MANY_TO_ONE:
             case ClassMetadataInfo::MANY_TO_ONE:
                 $options = $fieldDescription->getOption('filter_field_options');
                 $options = $fieldDescription->getOption('filter_field_options');
-                $filter = new \Sonata\AdminBundle\Filter\IntegerFilter($fieldDescription);
+                $filter = new \Sonata\AdminBundle\Filter\ORM\IntegerFilter($fieldDescription);
 
 
                 break;
                 break;
             case ClassMetadataInfo::MANY_TO_MANY:
             case ClassMetadataInfo::MANY_TO_MANY:
@@ -170,7 +170,7 @@ class DatagridBuilder implements DatagridBuilderInterface
 
 
                 $fieldDescription->setOption('filter_field_options', $options);
                 $fieldDescription->setOption('filter_field_options', $options);
 
 
-                $filter = new \Sonata\AdminBundle\Filter\ChoiceFilter($fieldDescription);
+                $filter = new \Sonata\AdminBundle\Filter\ORM\ChoiceFilter($fieldDescription);
 
 
                 break;
                 break;
 
 

+ 1 - 3
Controller/CRUDController.php

@@ -123,10 +123,8 @@ class CRUDController extends Controller
     public function listAction()
     public function listAction()
     {
     {
 
 
-        $datagrid = $this->admin->getDatagrid();
-
         return $this->render($this->admin->getListTemplate(), array(
         return $this->render($this->admin->getListTemplate(), array(
-            'datagrid'          => $datagrid,
+            'datagrid'          => $this->admin->getDatagrid(),
             'list'              => $this->admin->getList(),
             'list'              => $this->admin->getList(),
             'admin'             => $this->admin,
             'admin'             => $this->admin,
             'base_template'     => $this->getBaseTemplate(),
             'base_template'     => $this->getBaseTemplate(),

+ 27 - 0
Datagrid/ListCollection.php

@@ -18,21 +18,37 @@ class ListCollection
 
 
     protected $elements = array();
     protected $elements = array();
 
 
+    /**
+     * @param \Sonata\AdminBundle\Admin\FieldDescription $fieldDescription
+     * @return void
+     */
     public function add(FieldDescription $fieldDescription)
     public function add(FieldDescription $fieldDescription)
     {
     {
         $this->elements[$fieldDescription->getName()] = $fieldDescription;
         $this->elements[$fieldDescription->getName()] = $fieldDescription;
     }
     }
 
 
+    /**
+     * @return array
+     */
     public function getElements()
     public function getElements()
     {
     {
         return $this->elements;
         return $this->elements;
     }
     }
 
 
+    /**
+     * @param  $name
+     * @return bool
+     */
     public function has($name)
     public function has($name)
     {
     {
         return array_key_exists($name, $this->elements);
         return array_key_exists($name, $this->elements);
     }
     }
 
 
+    /**
+     * @throws \InvalidArgumentException
+     * @param  $name
+     * @return array
+     */
     public function get($name)
     public function get($name)
     {
     {
         if ($this->has($name)) {
         if ($this->has($name)) {
@@ -41,4 +57,15 @@ class ListCollection
 
 
         throw new \InvalidArgumentException(sprintf('Element "%s" does not exist.', $name));
         throw new \InvalidArgumentException(sprintf('Element "%s" does not exist.', $name));
     }
     }
+
+    /**
+     * @param  $name
+     * @return void
+     */
+    public function remove($name)
+    {
+        if ($this->has($name)) {
+            unset($this->elements[$name]);
+        }
+    }
 }
 }

+ 49 - 1
Resources/doc/reference/routing.rst

@@ -6,7 +6,7 @@ The default routes used in the CRUD controller are accessible through the
 
 
 The ``Admin`` class contains two routing method:
 The ``Admin`` class contains two routing method:
 
 
-* ``getUrls()``: Returns the available routes;
+* ``getRoutes()``: Returns the available routes;
 * ``generateUrl($name, $options)``: Generates the related routes.
 * ``generateUrl($name, $options)``: Generates the related routes.
 
 
 Routing Definition
 Routing Definition
@@ -41,3 +41,51 @@ Inside a CRUD template, a route can be generated by using the ``Admin`` class.
 
 
     <a href="{{ admin.generateUrl('list', params|merge('page': 1) }}">List</a>
     <a href="{{ admin.generateUrl('list', params|merge('page': 1) }}">List</a>
 
 
+Create a route
+--------------
+
+You can easily register new routes by defining them in the ``Admin`` class. Only Admin routes should be register this
+way. Of course this require to have the related action defined in the controller.
+
+A route is always generated with the ``Admin`` context, that is why a route can be only defined by its name.
+
+.. code-block:: php
+
+    use Sonata\AdminBundle\Route\RouteCollection;
+    
+    class MediaAdmin extends Admin
+    {
+        public function configureRoutes(RouteCollection $collection)
+        {
+            $collection->add('duplicate');
+            $collection->add('view', $this->getRouterIdParameter().'/view');
+        }
+    }
+
+
+Persistent parameters
+---------------------
+
+In some cases, the interface might required to pass the same parameters across the different ``Admin``'s actions.
+Instead of settings them in the template or doing other weird hacks, you can defined a ``getPersistentParameters``
+method. This method will be used when a link is being generated.
+
+.. code-block:: php
+
+    class MediaAdmin extends Admin
+    {
+        public function getPersistentParameters()
+        {
+            if(!$this->getRequest()) {
+                return array();
+            }
+
+            return array(
+                'provider' => $this->getRequest()->get('provider'),
+                'context'  => $this->getRequest()->get('context', 'default'),
+            );
+        }
+    }
+
+    // the result :
+    //   $admin->generateUrl('create') => /admin/module/create?context=default

+ 16 - 35
Route/AdminPoolLoader.php

@@ -31,12 +31,21 @@ class AdminPoolLoader extends FileLoader
      */
      */
     protected $adminServiceIds = array();
     protected $adminServiceIds = array();
 
 
+    /**
+     * @param \Sonata\AdminBundle\Admin\Pool $pool
+     * @param  $adminServiceIds
+     */
     public function __construct(Pool $pool, $adminServiceIds)
     public function __construct(Pool $pool, $adminServiceIds)
     {
     {
         $this->pool = $pool;
         $this->pool = $pool;
         $this->adminServiceIds = $adminServiceIds;
         $this->adminServiceIds = $adminServiceIds;
     }
     }
 
 
+    /**
+     * @param string $resource
+     * @param null $type
+     * @return bool
+     */
     function supports($resource, $type = null)
     function supports($resource, $type = null)
     {
     {
         if ($type == 'sonata_admin') {
         if ($type == 'sonata_admin') {
@@ -46,6 +55,11 @@ class AdminPoolLoader extends FileLoader
         return false;
         return false;
     }
     }
 
 
+    /**
+     * @param string $resource
+     * @param null $type
+     * @return \Symfony\Component\Routing\RouteCollection
+     */
     function load($resource, $type = null)
     function load($resource, $type = null)
     {
     {
         $collection = new RouteCollection;
         $collection = new RouteCollection;
@@ -53,24 +67,8 @@ class AdminPoolLoader extends FileLoader
 
 
             $admin = $this->pool->getInstance($id);
             $admin = $this->pool->getInstance($id);
 
 
-            foreach ($admin->getUrls() as $action => $configuration) {
-
-                $defaults = isset($configuration['defaults'])       ? $configuration['defaults'] : array();
-
-                if (!isset($defaults['_controller'])) {
-                    $defaults['_controller'] = sprintf('%s:%s', $admin->getBaseControllerName(), $this->actionify($action));
-                }
-
-                if (!isset($defaults['_sonata_admin'])) {
-                    $defaults['_sonata_admin'] = $admin->getBaseCodeRoute();
-                }
-
-                $collection->add($configuration['name'], new Route(
-                    $configuration['pattern'],
-                    $defaults,
-                    isset($configuration['requirements'])   ? $configuration['requirements'] : array(),
-                    isset($configuration['options'])        ? $configuration['options'] : array()
-                ));
+            foreach ($admin->getRoutes()->getElements() as $code => $route) {
+                $collection->add($route->getDefault('_sonata_name'), $route);
             }
             }
 
 
             $reflection = new \ReflectionObject($admin);
             $reflection = new \ReflectionObject($admin);
@@ -79,21 +77,4 @@ class AdminPoolLoader extends FileLoader
 
 
         return $collection;
         return $collection;
     }
     }
-
-
-    /**
-     * Convert a word in to the format for a symfony action action_name => actionName
-     *
-     * @param string  $word Word to actionify
-     * @return string $word Actionified word
-     */
-    public static function actionify($action)
-    {
-        if(($pos = strrpos($action, '.')) !== false) {
-
-          $action = substr($action, $pos + 1);
-        }
-
-        return lcfirst(str_replace(' ', '', ucwords(strtr($action, '_-', '  '))));
-    }
 }
 }

+ 125 - 0
Route/RouteCollection.php

@@ -0,0 +1,125 @@
+<?php
+/*
+ * This file is part of the Sonata package.
+ *
+ * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ *
+ */
+namespace Sonata\AdminBundle\Route;
+
+use Sonata\AdminBundle\Admin\FieldDescription;
+use Symfony\Component\Routing\Route;
+
+class RouteCollection
+{
+
+    protected $elements = array();
+
+    protected $baseCodeRoute;
+
+    protected $baseRouteName;
+
+    protected $baseControllerName;
+
+    protected $baseRoutePattern;
+
+    /**
+     * @param string $baseCodeRoute
+     * @param string $baseRouteName
+     * @param string $baseControllerName
+     */
+    public function __construct($baseCodeRoute, $baseRouteName, $baseRoutePattern, $baseControllerName)
+    {
+        $this->baseCodeRoute        = $baseCodeRoute;
+        $this->baseRouteName        = $baseRouteName;
+        $this->baseRoutePattern     = $baseRoutePattern;
+        $this->baseControllerName   = $baseControllerName;
+    }
+
+    /**
+     * @param string $name
+     * @param string $pattern
+     * @param array $defaults
+     * @param array $requirements
+     * @param array $options
+     * @return void
+     */
+    public function add($name, $pattern = null, array $defaults = array(), array $requirements = array(), array $options = array())
+    {
+
+        $pattern    = sprintf('%s/%s', $this->baseRoutePattern, $pattern ?: $name);
+        $code       = sprintf('%s.%s', $this->baseCodeRoute, $name);
+        $name       = sprintf('%s_%s', $this->baseRouteName, $name);
+
+        if (!isset($defaults['_controller'])) {
+            $defaults['_controller'] = sprintf('%s:%s', $this->baseControllerName, $this->actionify($code));
+        }
+
+        if (!isset($defaults['_sonata_admin'])) {
+            $defaults['_sonata_admin'] = $this->baseCodeRoute;
+        }
+
+        $defaults['_sonata_name'] = $name;
+
+        $this->elements[$code] = new Route($pattern, $defaults, $requirements, $options);;
+    }
+
+    /**
+     * @param RouteCollection
+     */
+    public function addCollection(RouteCollection $collection)
+    {
+        foreach($collection->getElements() as $name => $route) {
+            $this->elements[$name] = $route;
+        }
+    }
+
+    /**
+     * @return array
+     */
+    public function getElements()
+    {
+        return $this->elements;
+    }
+
+    /**
+     * @param string $name
+     * @return bool
+     */
+    public function has($name)
+    {
+        return array_key_exists($name, $this->elements);
+    }
+
+    /**
+     * @param string $name
+     * @return Route
+     */
+    public function get($name)
+    {
+        if ($this->has($name)) {
+            return $this->elements[$name];
+        }
+
+        throw new \InvalidArgumentException(sprintf('Element "%s" does not exist.', $name));
+    }
+
+    /**
+     * Convert a word in to the format for a symfony action action_name => actionName
+     *
+     * @param string  $word Word to actionify
+     * @return string $word Actionified word
+     */
+    public function actionify($action)
+    {
+        if(($pos = strrpos($action, '.')) !== false) {
+
+          $action = substr($action, $pos + 1);
+        }
+
+        return lcfirst(str_replace(' ', '', ucwords(strtr($action, '_-', '  '))));
+    }
+}