mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-16 02:30:09 +03:00
Merge pull request #367 from skipperbent/v3-rewrite-update
Simplified url-rewriting and callback handling.
This commit is contained in:
116
README.md
116
README.md
@@ -1136,125 +1136,18 @@ $siteId = input('site_id', 2, ['post', 'get']);
|
||||
|
||||
## Url rewriting
|
||||
Sometimes it can be useful to manipulate the route about to be loaded.
|
||||
simple-php-router allows you to easily change the route about to be executed.
|
||||
simple-php-router allows you to easily manipulate and change the routes which are about to be rendered.
|
||||
All information about the current route is stored in the `\Pecee\SimpleRouter\Router` instance's `loadedRoute` property.
|
||||
|
||||
For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::router()`.
|
||||
For easy access you can use the shortcut helper function `request()` instead of calling the class directly `\Pecee\SimpleRouter\SimpleRouter::router()`.
|
||||
|
||||
|
||||
```php
|
||||
use Pecee\SimpleRouter;
|
||||
$request = SimpleRouter::request();
|
||||
$request->setRewriteCallback('Example\MyCustomClass@hello');
|
||||
request()->setRewriteCallback('Example\MyCustomClass@hello');
|
||||
|
||||
// -- or you can rewrite by url --
|
||||
|
||||
$request->setRewriteUrl('/my-rewrite-url');
|
||||
```
|
||||
|
||||
**Note:** It's only possible to change the route BEFORE the route has initially been rendered. You can use the `Request` object to manipulate the route which are about to be loaded.
|
||||
|
||||
### Rewrite using callback
|
||||
|
||||
This method is most efficient, as it will render the route immediately.
|
||||
|
||||
This method is useful for rendering 404-pages etc.
|
||||
|
||||
You can also change the callback by modifying the `$route` parameter. This is perfect if you just want to display a view quickly - or change the callback depending
|
||||
on some criteria's for the request.
|
||||
|
||||
The callback below will fire immediately after the `Middleware` or `ExceptionHandler` has been loaded, as they are loaded before the route is rendered.
|
||||
If you wish to change the callback from outside, please have this in mind.
|
||||
|
||||
The example below will render `DefaultController@notFound` regardless of the url.
|
||||
|
||||
**NOTE: Use this method if you want to load another controller. No additional middlewares or rules will be loaded.**
|
||||
|
||||
##### Middleware example
|
||||
|
||||
```php
|
||||
namespace Demo\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class CustomMiddleware implements IMiddleware {
|
||||
|
||||
public function handle(Request $request) {
|
||||
|
||||
$request->setRewriteCallback('Demo\Controllers\DefaultController@notFound');
|
||||
return $request;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
##### Exception handler example
|
||||
|
||||
```php
|
||||
namespace Demo\Handlers;
|
||||
|
||||
use Pecee\Handlers\IExceptionHandler;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
|
||||
|
||||
class CustomExceptionHandler implements IExceptionHandler
|
||||
{
|
||||
public function handleError(Request $request, \Exception $error)
|
||||
{
|
||||
/* The router will throw the NotFoundHttpException on 404 */
|
||||
if($error instanceof NotFoundHttpException) {
|
||||
|
||||
/*
|
||||
* Render your own custom 404-view, rewrite the request to another route,
|
||||
* or simply return the $request object to ignore the error and continue on rendering the route.
|
||||
*
|
||||
* The code below will make the router render our page.notfound route.
|
||||
*/
|
||||
|
||||
$request->setRewriteCallback('Demo\Controllers\DefaultController@notFound');
|
||||
return $request;
|
||||
|
||||
}
|
||||
|
||||
throw $error;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Rewrite using url
|
||||
|
||||
The example below will cause the router to reload the request and reinitialize all the routes. This method is slower, but will ensure that all middlewares and rules for the route is loaded.
|
||||
|
||||
This method is useful if you want to redirect a url to another-url which is dependent on a middleware. You can also add a custom rule by calling `$request->setRewriteRoute($route)` if
|
||||
you want to customize request-methods or use another route-type like `RouteController` etc.
|
||||
|
||||
We are using the `url()` helper function to get the uri to another route added in the `routes.php` file.
|
||||
|
||||
**NOTE: Use this method if you want to fully load another route using it's settings (request method, middlewares etc).**
|
||||
|
||||
##### Middleware example
|
||||
|
||||
The example below will redirect the request to the `home`-route.
|
||||
|
||||
```php
|
||||
namespace Demo\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class CustomMiddleware implements IMiddleware {
|
||||
|
||||
public function handle(Request $request) {
|
||||
|
||||
$request->setRewriteUrl(url('home'));
|
||||
return $request;
|
||||
|
||||
}
|
||||
}
|
||||
request()->setRewriteUrl('/my-rewrite-url');
|
||||
```
|
||||
|
||||
### Bootmanager: loading routes dynamically
|
||||
@@ -1282,7 +1175,6 @@ class CustomRouterRules implement IRouterBootManager {
|
||||
|
||||
if($request->getUri()->getPath() === $url) {
|
||||
$request->setRewriteUrl($rule);
|
||||
return $request;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ class Request
|
||||
protected $method;
|
||||
protected $input;
|
||||
|
||||
protected $hasRewrite = false;
|
||||
|
||||
/**
|
||||
* @var ILoadableRoute|null
|
||||
*/
|
||||
@@ -231,6 +233,7 @@ class Request
|
||||
*/
|
||||
public function setRewriteRoute(ILoadableRoute $route)
|
||||
{
|
||||
$this->hasRewrite = true;
|
||||
$this->rewriteRoute = SimpleRouter::addDefaultNamespace($route);
|
||||
|
||||
return $this;
|
||||
@@ -264,7 +267,8 @@ class Request
|
||||
*/
|
||||
public function setRewriteUrl($rewriteUrl)
|
||||
{
|
||||
$this->rewriteUrl = $rewriteUrl;
|
||||
$this->hasRewrite = true;
|
||||
$this->rewriteUrl = rtrim($rewriteUrl, '/') . '/';
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -276,7 +280,9 @@ class Request
|
||||
*/
|
||||
public function setRewriteCallback($callback)
|
||||
{
|
||||
return $this->setRewriteRoute(new RouteUrl($this->uri, $callback));
|
||||
$this->hasRewrite = true;
|
||||
|
||||
return $this->setRewriteRoute(new RouteUrl($this->getUri()->getPath(), $callback));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,6 +307,23 @@ class Request
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasRewrite()
|
||||
{
|
||||
return $this->hasRewrite;
|
||||
}
|
||||
|
||||
public function setHasRewrite($value)
|
||||
{
|
||||
$this->hasRewrite = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isRewrite($url)
|
||||
{
|
||||
return ($this->rewriteUrl === $url);
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return array_key_exists($name, $this->data);
|
||||
|
||||
@@ -128,7 +128,7 @@ abstract class Route implements IRoute
|
||||
// Ensures that hostnames/domains will work with parameters
|
||||
$url = '/' . ltrim($url, '/');
|
||||
|
||||
if (preg_match_all('/' . $regex . '/u', $route, $parameters) > 0) {
|
||||
if (preg_match_all('/' . $regex . '/u', $route, $parameters) !== 0) {
|
||||
|
||||
$urlParts = preg_split('/((\-?\/?)\{[^}]+\})/', $route);
|
||||
|
||||
@@ -166,22 +166,21 @@ abstract class Route implements IRoute
|
||||
$urlRegex = preg_quote($route, '/');
|
||||
}
|
||||
|
||||
if (preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) > 0) {
|
||||
|
||||
$values = [];
|
||||
|
||||
if (isset($parameters[1]) === true) {
|
||||
|
||||
/* Only take matched parameters with name */
|
||||
foreach ((array)$parameters[1] as $name) {
|
||||
$values[$name] = (isset($matches[$name]) && $matches[$name] !== '') ? $matches[$name] : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
if (preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
$values = [];
|
||||
|
||||
if (isset($parameters[1]) === true) {
|
||||
|
||||
/* Only take matched parameters with name */
|
||||
foreach ((array)$parameters[1] as $name) {
|
||||
$values[$name] = (isset($matches[$name]) && $matches[$name] !== '') ? $matches[$name] : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -224,6 +224,8 @@ class Router
|
||||
/* Verify csrf token for request */
|
||||
$this->csrfVerifier->handle($this->request);
|
||||
}
|
||||
} else {
|
||||
$this->request->setHasRewrite(false);
|
||||
}
|
||||
|
||||
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
|
||||
@@ -231,7 +233,6 @@ class Router
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $key => $route) {
|
||||
|
||||
|
||||
/* If the route matches */
|
||||
if ($route->matchRoute($url, $this->request) === true) {
|
||||
|
||||
@@ -243,29 +244,28 @@ class Router
|
||||
|
||||
$route->loadMiddleware($this->request);
|
||||
|
||||
$rewriteRoute = $this->request->getRewriteRoute();
|
||||
|
||||
if ($rewriteRoute !== null) {
|
||||
$rewriteRoute->loadMiddleware($this->request);
|
||||
|
||||
return $rewriteRoute->renderRoute($this->request);
|
||||
}
|
||||
|
||||
/* If the request has changed */
|
||||
$rewriteUrl = $this->request->getRewriteUrl();
|
||||
|
||||
if ($rewriteUrl !== null && $rewriteUrl !== $url) {
|
||||
if ($this->hasRewrite($url) === true) {
|
||||
unset($this->processedRoutes[$key]);
|
||||
$this->processedRoutes = array_values($this->processedRoutes);
|
||||
|
||||
return $this->routeRequest(true);
|
||||
}
|
||||
|
||||
/* Render route */
|
||||
$routeNotAllowed = false;
|
||||
|
||||
$this->request->setLoadedRoute($route);
|
||||
|
||||
return $route->renderRoute($this->request);
|
||||
$output = $route->renderRoute($this->request);
|
||||
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
if ($this->hasRewrite($url) === true) {
|
||||
unset($this->processedRoutes[$key]);
|
||||
|
||||
return $this->routeRequest(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,6 +294,31 @@ class Router
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function hasRewrite($url)
|
||||
{
|
||||
|
||||
/* If the request has changed */
|
||||
if ($this->request->hasRewrite() === true) {
|
||||
|
||||
if ($this->request->getRewriteRoute() !== null) {
|
||||
/* Render rewrite-route */
|
||||
$this->processedRoutes[] = $this->request->getRewriteRoute();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->request->isRewrite($url) === false) {
|
||||
|
||||
/* Render rewrite-url */
|
||||
$this->processedRoutes = array_values($this->processedRoutes);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception $e
|
||||
* @throws HttpException
|
||||
@@ -302,8 +327,6 @@ class Router
|
||||
*/
|
||||
protected function handleException(\Exception $e)
|
||||
{
|
||||
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri()->getPath();
|
||||
|
||||
/* @var $handler IExceptionHandler */
|
||||
foreach ($this->exceptionHandlers as $key => $handler) {
|
||||
|
||||
@@ -317,25 +340,13 @@ class Router
|
||||
|
||||
try {
|
||||
|
||||
if ($handler->handleError($this->request, $e) !== null) {
|
||||
$handler->handleError($this->request, $e);
|
||||
|
||||
$rewriteRoute = $this->request->getRewriteRoute();
|
||||
if ($this->request->hasRewrite() === true) {
|
||||
unset($this->exceptionHandlers[$key]);
|
||||
$this->exceptionHandlers = array_values($this->exceptionHandlers);
|
||||
|
||||
if ($rewriteRoute !== null) {
|
||||
$rewriteRoute->loadMiddleware($this->request);
|
||||
|
||||
return $rewriteRoute->renderRoute($this->request);
|
||||
}
|
||||
|
||||
$rewriteUrl = $this->request->getRewriteUrl();
|
||||
|
||||
/* If the request has changed */
|
||||
if ($rewriteUrl !== null && $rewriteUrl !== $url) {
|
||||
unset($this->exceptionHandlers[$key]);
|
||||
$this->exceptionHandlers = array_values($this->exceptionHandlers);
|
||||
|
||||
return $this->routeRequest(true);
|
||||
}
|
||||
return $this->routeRequest(true);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
16
test/Dummy/Middlewares/RewriteMiddleware.php
Normal file
16
test/Dummy/Middlewares/RewriteMiddleware.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RewriteMiddleware implements IMiddleware {
|
||||
|
||||
public function handle(Request $request) {
|
||||
|
||||
$request->setRewriteCallback(function() {
|
||||
return 'ok';
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ require_once 'Dummy/Handler/ExceptionHandlerFirst.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandlerSecond.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandlerThird.php';
|
||||
require_once 'Helpers/TestRouter.php';
|
||||
require_once 'Dummy/Middlewares/RewriteMiddleware.php';
|
||||
|
||||
class RouteRewriteTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
@@ -33,9 +34,9 @@ class RouteRewriteTest extends PHPUnit_Framework_TestCase
|
||||
global $stack;
|
||||
$stack = [];
|
||||
|
||||
TestRouter::group(['exceptionHandler' => [ExceptionHandlerFirst::class, ExceptionHandlerSecond::class]], function () {
|
||||
TestRouter::group(['exceptionHandler' => [ExceptionHandlerFirst::class, ExceptionHandlerSecond::class]], function () use ($stack) {
|
||||
|
||||
TestRouter::group(['exceptionHandler' => ExceptionHandlerThird::class], function () {
|
||||
TestRouter::group(['exceptionHandler' => ExceptionHandlerThird::class], function () use ($stack) {
|
||||
|
||||
TestRouter::get('/my-path', 'DummyController@method1');
|
||||
|
||||
@@ -64,10 +65,8 @@ class RouteRewriteTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
TestRouter::error(function (\Pecee\Http\Request $request, \Exception $error) {
|
||||
|
||||
if (strtolower($request->getUri()->getPath()) == '/my/test') {
|
||||
if (strtolower($request->getUri()->getPath()) === '/my/test/') {
|
||||
$request->setRewriteUrl('/another-non-existing');
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -75,4 +74,104 @@ class RouteRewriteTest extends PHPUnit_Framework_TestCase
|
||||
TestRouter::debug('/my/test', 'get');
|
||||
}
|
||||
|
||||
public function testRewriteUrlFromRoute()
|
||||
{
|
||||
|
||||
TestRouter::get('/old', function () {
|
||||
TestRouter::request()->setRewriteUrl('/new');
|
||||
});
|
||||
|
||||
TestRouter::get('/new', function () {
|
||||
echo 'ok';
|
||||
});
|
||||
|
||||
TestRouter::get('/new1', function () {
|
||||
echo 'ok';
|
||||
});
|
||||
|
||||
TestRouter::get('/new2', function () {
|
||||
echo 'ok';
|
||||
});
|
||||
|
||||
$output = TestRouter::debugOutput('/old');
|
||||
|
||||
$this->assertEquals('ok', $output);
|
||||
|
||||
}
|
||||
|
||||
public function testRewriteCallbackFromRoute()
|
||||
{
|
||||
|
||||
TestRouter::get('/old', function () {
|
||||
TestRouter::request()->setRewriteUrl('/new');
|
||||
});
|
||||
|
||||
TestRouter::get('/new', function () {
|
||||
return 'ok';
|
||||
});
|
||||
|
||||
TestRouter::get('/new1', function () {
|
||||
return 'fail';
|
||||
});
|
||||
|
||||
TestRouter::get('/new/2', function () {
|
||||
return 'fail';
|
||||
});
|
||||
|
||||
$output = TestRouter::debugOutput('/old');
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
$this->assertEquals('ok', $output);
|
||||
|
||||
}
|
||||
|
||||
public function testRewriteRouteFromRoute()
|
||||
{
|
||||
|
||||
TestRouter::get('/match', function () {
|
||||
TestRouter::request()->setRewriteRoute(new \Pecee\SimpleRouter\Route\RouteUrl('/match', function () {
|
||||
return 'ok';
|
||||
}));
|
||||
});
|
||||
|
||||
TestRouter::get('/old1', function () {
|
||||
return 'fail';
|
||||
});
|
||||
|
||||
TestRouter::get('/old/2', function () {
|
||||
return 'fail';
|
||||
});
|
||||
|
||||
TestRouter::get('/new2', function () {
|
||||
return 'fail';
|
||||
});
|
||||
|
||||
$output = TestRouter::debugOutput('/match');
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
$this->assertEquals('ok', $output);
|
||||
|
||||
}
|
||||
|
||||
public function testMiddlewareRewrite()
|
||||
{
|
||||
|
||||
TestRouter::group(['middleware' => 'RewriteMiddleware'], function () {
|
||||
TestRouter::get('/', function () {
|
||||
return 'fail';
|
||||
});
|
||||
|
||||
TestRouter::get('no/match', function () {
|
||||
return 'fail';
|
||||
});
|
||||
});
|
||||
|
||||
$output = TestRouter::debugOutput('/');
|
||||
|
||||
$this->assertEquals('ok', $output);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user