Browse Source

Merge pull request #8493 from cakephp/nested-resources

3.next - Add prefix support to nested resource routes
José Lorenzo Rodríguez 10 years ago
parent
commit
6e162c2d6d
3 changed files with 51 additions and 3 deletions
  1. 15 1
      src/Routing/RouteBuilder.php
  2. 1 0
      src/Routing/Router.php
  3. 35 2
      tests/TestCase/Routing/RouteBuilderTest.php

+ 15 - 1
src/Routing/RouteBuilder.php

@@ -287,6 +287,8 @@ class RouteBuilder
      * - 'actions' - Override the method names used for connecting actions.
      * - 'map' - Additional resource routes that should be connected. If you define 'only' and 'map',
      *   make sure that your mapped methods are also in the 'only' list.
+     * - 'prefix' - Define a routing prefix for the resource controller. If the current scope
+     *   defines a prefix, this prefix will be appended to it.
      *
      * @param string $name A controller name to connect resource routes for.
      * @param array|callable $options Options to use when generating REST routes, or a callback.
@@ -307,6 +309,7 @@ class RouteBuilder
             'only' => [],
             'actions' => [],
             'map' => [],
+            'prefix' => null,
         ];
 
         foreach ($options['map'] as $k => $mapped) {
@@ -327,6 +330,14 @@ class RouteBuilder
             $only = array_keys($resourceMap);
         }
 
+        $prefix = '';
+        if ($options['prefix']) {
+            $prefix = $options['prefix'];
+        }
+        if (isset($this->_params['prefix']) && $prefix) {
+            $prefix = $this->_params['prefix'] . '/' . $prefix;
+        }
+
         foreach ($resourceMap as $method => $params) {
             if (!in_array($method, $only, true)) {
                 continue;
@@ -343,6 +354,9 @@ class RouteBuilder
                 'action' => $action,
                 '_method' => $params['method'],
             ];
+            if ($prefix) {
+                $params['prefix'] = $prefix;
+            }
             $routeOptions = $connectOptions + [
                 'id' => $options['id'],
                 'pass' => ['id'],
@@ -482,7 +496,7 @@ class RouteBuilder
             $route = $route === '/' ? $route : rtrim($route, '/');
 
             foreach ($this->_params as $param => $val) {
-                if (isset($defaults[$param]) && $defaults[$param] !== $val) {
+                if (isset($defaults[$param]) && $param !== 'prefix' && $defaults[$param] !== $val) {
                     $msg = 'You cannot define routes that conflict with the scope. ' .
                         'Scope had %s = %s, while route had %s = %s';
                     throw new BadMethodCallException(sprintf(

+ 1 - 0
src/Routing/Router.php

@@ -289,6 +289,7 @@ class Router
             $prefix = $pluginUrl = false;
             if (!empty($options['prefix'])) {
                 $prefix = $options['prefix'];
+                unset($options['prefix']);
             }
             if ($plugin) {
                 $pluginUrl = Inflector::underscore($plugin);

+ 35 - 2
tests/TestCase/Routing/RouteBuilderTest.php

@@ -252,8 +252,8 @@ class RouteBuilderTest extends TestCase
      */
     public function testConnectConflictingParameters()
     {
-        $routes = new RouteBuilder($this->collection, '/admin', ['prefix' => 'admin']);
-        $routes->connect('/', ['prefix' => 'manager', 'controller' => 'Dashboard', 'action' => 'view']);
+        $routes = new RouteBuilder($this->collection, '/admin', ['plugin' => 'TestPlugin']);
+        $routes->connect('/', ['plugin' => 'TestPlugin2', 'controller' => 'Dashboard', 'action' => 'view']);
     }
 
     /**
@@ -367,6 +367,39 @@ class RouteBuilderTest extends TestCase
     }
 
     /**
+     * Test connecting resources with a prefix
+     *
+     * @return void
+     */
+    public function testResourcesPrefix()
+    {
+        $routes = new RouteBuilder($this->collection, '/api');
+        $routes->resources('Articles', ['prefix' => 'rest']);
+        $all = $this->collection->routes();
+        $this->assertEquals('rest', $all[0]->defaults['prefix']);
+    }
+
+    /**
+     * Test that resource prefixes work within a prefixed scope.
+     *
+     * @return void
+     */
+    public function testResourcesNestedPrefix()
+    {
+        $routes = new RouteBuilder($this->collection, '/api', ['prefix' => 'api']);
+        $routes->resources('Articles', ['prefix' => 'rest']);
+
+        $all = $this->collection->routes();
+        $this->assertCount(5, $all);
+
+        $this->assertEquals('/api/articles', $all[0]->template);
+        foreach ($all as $route) {
+            $this->assertEquals('api/rest', $route->defaults['prefix']);
+            $this->assertEquals('Articles', $route->defaults['controller']);
+        }
+    }
+
+    /**
      * Test connecting resources with the inflection option
      *
      * @return void