mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
NEW: Variadic URL parameter matches for url_handlers (#9438)
* Add wildcard URL parameter matches for url_handlers * Extra tests for wildcard parameters * Add a PHP warning if more params appear after wildcard param
This commit is contained in:
parent
b6512edec8
commit
1fb574a5bd
@ -142,6 +142,51 @@ the `TeamController`.
|
|||||||
Match an url starting with `/admin/help/`, but don't include `/help/` as part of the action (the shift point is set to
|
Match an url starting with `/admin/help/`, but don't include `/help/` as part of the action (the shift point is set to
|
||||||
start parsing variables and the appropriate controller action AFTER the `//`).
|
start parsing variables and the appropriate controller action AFTER the `//`).
|
||||||
|
|
||||||
|
### Wildcard URL Patterns
|
||||||
|
|
||||||
|
As of SilverStripe 4.6 there are two wildcard patterns that can be used. `$@` and `$*`. These parameters can only be used
|
||||||
|
at the end of a URL pattern, any further rules are ignored.
|
||||||
|
|
||||||
|
Inspired by bash variadic variable syntax there are two ways to capture all URL parameters without having to explicitly
|
||||||
|
specify them in the URL rule.
|
||||||
|
|
||||||
|
Using `$@` will split the URL into numbered parameters (`$1`, `$2`, ..., `$n`). For example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
class StaffController extends \SilverStripe\Control\Controller
|
||||||
|
{
|
||||||
|
private static $url_handlers = [
|
||||||
|
'staff/$@' => 'index',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function index($request)
|
||||||
|
{
|
||||||
|
// GET /staff/managers/bob
|
||||||
|
$request->latestParam('$1'); // managers
|
||||||
|
$request->latestParam('$2'); // bob
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, if access to the parameters is not required in this way then it is possible to use `$*` to match all
|
||||||
|
URL parameters but not collect them in the same way:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
class StaffController extends \SilverStripe\Control\Controller
|
||||||
|
{
|
||||||
|
private static $url_handlers = [
|
||||||
|
'staff/$*' => 'index',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function index($request)
|
||||||
|
{
|
||||||
|
// GET /staff/managers/bob
|
||||||
|
$request->remaining(); // managers/bob
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## URL Handlers
|
## URL Handlers
|
||||||
|
|
||||||
|
@ -564,7 +564,28 @@ class HTTPRequest implements ArrayAccess
|
|||||||
|
|
||||||
/** @skipUpgrade */
|
/** @skipUpgrade */
|
||||||
$key = "Controller";
|
$key = "Controller";
|
||||||
$arguments[$varName] = isset($this->dirParts[$i]) ? $this->dirParts[$i] : null;
|
if ($varName === '*' || $varName === '@') {
|
||||||
|
if (isset($patternParts[$i + 1])) {
|
||||||
|
user_error(sprintf('All URL params after wildcard parameter $%s will be ignored', $varName), E_USER_WARNING);
|
||||||
|
}
|
||||||
|
if ($varName === '*') {
|
||||||
|
array_pop($patternParts);
|
||||||
|
$shiftCount = sizeof($patternParts);
|
||||||
|
$patternParts = array_merge($patternParts, array_slice($this->dirParts, $i));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
array_pop($patternParts);
|
||||||
|
$shiftCount = sizeof($patternParts);
|
||||||
|
$remaining = count($this->dirParts) - $i;
|
||||||
|
for ($j = 1; $j <= $remaining; $j++) {
|
||||||
|
$arguments["$${j}"] = $this->dirParts[$j + $i - 1];
|
||||||
|
}
|
||||||
|
$patternParts = array_merge($patternParts, array_keys($arguments));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$arguments[$varName] = $this->dirParts[$i] ?? null;
|
||||||
|
}
|
||||||
if ($part == '$Controller'
|
if ($part == '$Controller'
|
||||||
&& (
|
&& (
|
||||||
!ClassInfo::exists($arguments[$key])
|
!ClassInfo::exists($arguments[$key])
|
||||||
|
@ -25,6 +25,43 @@ class HTTPRequestTest extends SapphireTest
|
|||||||
$this->assertEquals(array("_matched" => true), $request->match('add', true));
|
$this->assertEquals(array("_matched" => true), $request->match('add', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @useDatabase false
|
||||||
|
*/
|
||||||
|
public function testWildCardMatch()
|
||||||
|
{
|
||||||
|
$request = new HTTPRequest('GET', 'admin/crm/test');
|
||||||
|
$this->assertEquals(['$1' => 'crm', '$2' => 'test'], $request->match('admin/$@', true));
|
||||||
|
$this->assertTrue($request->allParsed());
|
||||||
|
|
||||||
|
$request = new HTTPRequest('GET', 'admin/crm/test');
|
||||||
|
$this->assertEquals(['_matched' => true], $request->match('admin/$*', true));
|
||||||
|
$this->assertTrue($request->allParsed());
|
||||||
|
$this->assertEquals('crm/test', $request->remaining());
|
||||||
|
|
||||||
|
$request = new HTTPRequest('GET', 'admin/crm/test/part1/part2');
|
||||||
|
$this->assertEquals(['Action' => 'crm', '$1' => 'test', '$2' => 'part1', '$3' => 'part2'], $request->match('admin/$Action/$@', true));
|
||||||
|
$this->assertTrue($request->allParsed());
|
||||||
|
|
||||||
|
$request = new HTTPRequest('GET', 'admin/crm/test/part1/part2');
|
||||||
|
$this->assertEquals(['Action' => 'crm'], $request->match('admin/$Action/$*', true));
|
||||||
|
$this->assertTrue($request->allParsed());
|
||||||
|
$this->assertEquals('test/part1/part2', $request->remaining());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test just asserts a warning is given if there is more than one wildcard parameter. Note that this isn't an
|
||||||
|
* enforcement of an API and we an add new behaviour in the future to allow many wildcard params if we want to
|
||||||
|
*
|
||||||
|
* @expectedException \PHPUnit_Framework_Error_Warning
|
||||||
|
*/
|
||||||
|
public function testWildCardWithFurtherParams()
|
||||||
|
{
|
||||||
|
$request = new HTTPRequest('GET', 'admin/crm/test');
|
||||||
|
// all parameters after the first wildcard parameter are ignored
|
||||||
|
$request->match('admin/$Action/$@/$Other/$*', true);
|
||||||
|
}
|
||||||
|
|
||||||
public function testHttpMethodOverrides()
|
public function testHttpMethodOverrides()
|
||||||
{
|
{
|
||||||
$request = new HTTPRequest(
|
$request = new HTTPRequest(
|
||||||
|
Loading…
Reference in New Issue
Block a user