Skip to content
Permalink
Browse files

Add prefix support to resources.

This allows resources and more importantly nested resources to have
routing prefixes applied to them. This allows nested resource
controllers to be mapped onto namespaces/routing prefixes. I thought
this was a more robust/opinionated solution that allowing arbitrary
class names.

I've had to relax the duplicate key checking between scopes and their
routes to allow differences in prefixes to be created.

Refs #8063
  • Loading branch information...
markstory committed Mar 16, 2016
1 parent f41fd23 commit 5b7a7889e1a54ef16c149632c2342b344f290eeb
Showing 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
@@ -287,6 +287,8 @@ public function namePrefix($value = null)
* - '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 @@ public function resources($name, $options = [], $callback = null)
'only' => [],
'actions' => [],
'map' => [],
'prefix' => null,
];
foreach ($options['map'] as $k => $mapped) {
@@ -327,6 +330,14 @@ public function resources($name, $options = [], $callback = null)
$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 @@ public function resources($name, $options = [], $callback = null)
'action' => $action,
'_method' => $params['method'],
];
if ($prefix) {
$params['prefix'] = $prefix;
}
$routeOptions = $connectOptions + [
'id' => $options['id'],
'pass' => ['id'],
@@ -482,7 +496,7 @@ protected function _makeRoute($route, $defaults, $options)
$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(
@@ -289,6 +289,7 @@ public static function mapResources($controller, $options = [])
$prefix = $pluginUrl = false;
if (!empty($options['prefix'])) {
$prefix = $options['prefix'];
unset($options['prefix']);
}
if ($plugin) {
$pluginUrl = Inflector::underscore($plugin);
@@ -252,8 +252,8 @@ public function testConnectErrorInvalidRouteClass()
*/
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']);
}
/**
@@ -366,6 +366,39 @@ public function testResources()
$this->assertEquals('Articles', $all[0]->defaults['controller']);
}
/**
* 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
*

0 comments on commit 5b7a788

Please sign in to comment.
You can’t perform that action at this time.