Callback, faking route and documentation updates

This commit is contained in:
Simon Sessingø
2016-11-15 05:44:24 +01:00
parent bc14790a67
commit 83c73a4240
8 changed files with 131 additions and 50 deletions

View File

@@ -354,15 +354,16 @@ By doing this the route will now load the url ```/article/view/1``` instead of `
The last thing we need to do, is to add our custom boot-manager to the ```routes.php``` file. You can create as many bootmanagers as you like and easily add them in your ```routes.php``` file.
## Easily overwrite route about to be loaded
Sometimes it can be useful to manipulate the route that's about to be loaded, for instance if a user is not authenticated or if an error occurred within your Middleware that requires
some other route to be initialised. Simple PHP Router allows you to easily change the route about to be executed. All information about the current route is stored in
the ```\Pecee\SimpleRouter\Http\Request``` object. All information about the current route is as a ```\Pecee\SimpleRouter\Http\Request``` object which can always be obtained on
the `RouterBase` instance. For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::request()`.
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.
All information about the current route is stored in the ```\Pecee\SimpleRouter\RouterBase``` instance.
For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::router()`.
**Note:** Please note that it's only possible to change the route BEFORE any route has initially been loaded, so doing this in your custom ExceptionHandler or Middleware is highly recommended.
```php
$route = request()->getLoadedRoute();
use Pecee\SimpleRouter;
$route = SimpleRouter::router()->getLoadedRoute();
$route->setCallback('Example\MyCustomClass@hello');
@@ -372,6 +373,54 @@ $route->setClass('Example\MyCustomClass');
$route->setMethod('hello');
```
### Examples
#### Faking new route
It's only possible to change the route BEFORE the route has initially been loaded. If you want to redirect to another route, we highly recommend that you
modify the `RouterRoute` object from a `Middleware` or `ExceptionHandler`, for like the examples below.
The example below will cause the router to re-route the request with the "fake" uri. This does require the `$request` object to be returned,
otherwise the `request` object will be ignored by the router.
```php
namespace demo\Middlewares;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
class CustomMiddleware implements Middleware {
public function handle(Request $request, RouterEntry &$route = null) {
return $request->setUri('/home');
}
}
```
#### Changing callback
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.
```php
namespace demo\Middlewares;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
class CustomMiddleware implements Middleware {
public function handle(Request $request, RouterEntry &$route = null) {
$route->callback('DefaultController@home');
}
}
```
## Using the Input class to manage parameters
We've added the `Input` class to easy access parameters from your Controller-classes.
@@ -425,7 +474,7 @@ Below example requires you to have the helper functions added. Please refer to t
```php
// Get parameter site_id or default-value 2
$value = input()->get('site_id', '2');
$siteId = input()->get('site_id', 2);
```
## Sites

View File

@@ -6,7 +6,7 @@ use Pecee\Http\Request;
class ApiVerification implements IMiddleware {
public function handle(Request $request) {
public function handle(Request &$request) {
// Do authentication
$request->authenticated = true;

View File

@@ -6,6 +6,12 @@ use Pecee\SimpleRouter\RouterEntry;
interface IExceptionHandler {
public function handleError(Request $request, RouterEntry $router = null, \Exception $error);
/**
* @param Request $request
* @param RouterEntry|null $route
* @param \Exception $error
* @return Request|null
*/
public function handleError(Request $request, RouterEntry &$route = null, \Exception $error);
}

View File

@@ -4,6 +4,7 @@ namespace Pecee\Http\Middleware;
use Pecee\CsrfToken;
use Pecee\Exception\TokenMismatchException;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
class BaseCsrfVerifier implements IMiddleware {
@@ -49,11 +50,11 @@ class BaseCsrfVerifier implements IMiddleware {
return false;
}
public function handle(Request $request) {
public function handle(Request $request, RouterEntry &$route = null) {
if($request->getMethod() != 'get' && !$this->skip($request)) {
if($request->getMethod() !== 'get' && !$this->skip($request)) {
$token = (isset($_POST[static::POST_KEY])) ? $_POST[static::POST_KEY] : null;
$token = $request->getInput()->post->findFirst(static::POST_KEY);
// If the token is not posted, check headers for valid x-csrf-token
if($token === null) {

View File

@@ -2,7 +2,15 @@
namespace Pecee\Http\Middleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
interface IMiddleware {
public function handle(Request $request);
/**
* @param Request $request
* @param RouterEntry|null $route
* @return Request|null
*/
public function handle(Request $request, RouterEntry &$route = null);
}

View File

@@ -71,6 +71,14 @@ class RouterBase {
*/
protected $exceptionHandlers;
/**
* The current loaded route
* @var RouterRoute|null
*/
protected $loadedRoute;
protected $routeChanges;
public function __construct() {
$this->reset();
}
@@ -83,6 +91,7 @@ class RouterBase {
$this->controllerUrlMap = array();
$this->bootManagers = array();
$this->exceptionHandlers = array();
$this->routeChanges = array();
}
/**
@@ -173,18 +182,21 @@ class RouterBase {
}
}
public function routeRequest($original = true) {
public function routeRequest(Request $newRequest = null) {
$originalUri = $this->request->getUri();
$this->loadedRoute = null;
$routeNotAllowed = false;
// Create a fictive request - so it can be changed in the middleware or exceptionhandler later on...
$request = clone $this->request;
try {
// Initialize boot-managers
if(count($this->bootManagers)) {
/* @var $manager RouterBootManager */
foreach($this->bootManagers as $manager) {
$this->request = $manager->boot($this->request);
$request = $manager->boot($request);
if(!($this->request instanceof Request)) {
throw new RouterException('Custom router bootmanager "'. get_class($manager) .'" must return instance of Request.');
@@ -192,35 +204,42 @@ class RouterBase {
}
}
// Loop through each route-request
$this->processRoutes($this->routes);
if($newRequest === null && $this->csrfVerifier !== null) {
// Loop through each route-request
$this->processRoutes($this->routes);
if($original === true && $this->csrfVerifier !== null) {
// Verify csrf token for request
$this->csrfVerifier->handle($this->request);
}
$request = ($newRequest !== null) ? $newRequest : $request;
/* @var $route RouterEntry */
for ($i = 0; $i < count($this->controllerUrlMap); $i++) {
$route = $this->controllerUrlMap[$i];
if ($route->matchRoute($this->request)) {
if ($route->matchRoute($request)) {
if (count($route->getRequestMethods()) && !in_array($this->request->getMethod(), $route->getRequestMethods())) {
if (count($route->getRequestMethods()) && !in_array($request->getMethod(), $route->getRequestMethods())) {
$routeNotAllowed = true;
continue;
}
$routeNotAllowed = false;
$this->request->rewrite_uri = $this->request->getUri();
$this->request->setUri($originalUri);
$this->loadedRoute = $route;
$request = $this->loadedRoute->loadMiddleware($request, $this->loadedRoute);
$request = ($request === null) ? $this->request : $request;
$this->request->loadedRoute = $route;
$this->request->loadedRoute->loadMiddleware($this->request);
if($request !== null && $request->getUri() !== $this->request->getUri() && !in_array($request->getUri(), $this->routeChanges)) {
$this->routeChanges[] = $request->getUri();
$this->routeRequest($request);
return;
}
$this->request->loadedRoute->renderRoute($this->request);
$this->loadedRoute->renderRoute($request);
break;
}
@@ -234,18 +253,17 @@ class RouterBase {
$this->handleException(new RouterException('Route or method not allowed', 403));
}
if(!$this->request->loadedRoute) {
$this->handleException(new RouterException(sprintf('Route not found: %s', $this->request->getUri()), 404));
if($this->loadedRoute === null) {
$this->handleException(new RouterException(sprintf('Route not found: %s', $request->getUri()), 404));
}
}
protected function handleException(\Exception $e) {
$request = null;
$request = clone $this->request;
/* @var $route RouterGroup */
foreach ($this->exceptionHandlers as $route) {
$route->loadMiddleware($this->request);
$handler = $route->getExceptionHandler();
$handler = new $handler();
@@ -253,13 +271,20 @@ class RouterBase {
throw new RouterException('Exception handler must implement the IExceptionHandler interface.');
}
$request = $handler->handleError($this->request, $this->request->loadedRoute, $e);
}
$request = $handler->handleError($request, $this->loadedRoute, $e);
$request = ($request === null) ? $this->request : $request;
if(!in_array($request->getUri(), $this->routeChanges)) {
$this->routeChanges[] = $request->getUri();
if($request->getUri() !== $this->request->getUri()) {
$this->routeRequest($request);
} else {
$this->routeChanges[] = $request->getUri();
$this->loadedRoute->renderRoute($request);
}
return;
}
if($request !== null) {
$this->request = $request;
$this->routeRequest(false);
return;
}
throw $e;
@@ -307,14 +332,6 @@ class RouterBase {
$this->bootManagers[] = $bootManager;
}
/**
* Get the loaded route
* @return RouterEntry
*/
public function getLoadedRoute() {
return $this->request->loadedRoute;
}
/**
* @return array
*/
@@ -451,8 +468,8 @@ class RouterBase {
return $url;
}
if($controller === null && $this->request->loadedRoute !== null) {
return $this->processUrl($this->request->loadedRoute, $this->request->loadedRoute->getMethod(), $parameters, $getParams);
if($controller === null && $this->loadedRoute !== null) {
return $this->processUrl($this->loadedRoute, $this->loadedRoute->getMethod(), $parameters, $getParams);
}
$c = '';

View File

@@ -291,7 +291,7 @@ abstract class RouterEntry {
return null;
}
public function loadMiddleware(Request $request) {
public function loadMiddleware(Request $request, RouterRoute &$route) {
if(count($this->getMiddleware())) {
foreach($this->getMiddleware() as $middleware) {
$middleware = $this->loadClass($middleware);
@@ -300,7 +300,7 @@ abstract class RouterEntry {
}
/* @var $class IMiddleware */
$middleware->handle($request);
$middleware->handle($request, $route);
}
}
}

View File

@@ -113,8 +113,8 @@ class RouterGroup extends RouterEntry {
// Push middleware if multiple
if ($this->getMiddleware() !== null && isset($settings['middleware'])) {
if (!is_array($this->getMiddleware())) {
$settings['middleware'] = array($this->getMiddleware(), $settings['middleware']);
if (!is_array($settings['middleware'])) {
$settings['middleware'] = array_merge($this->getMiddleware(), array($settings['middleware']));
} else {
$settings['middleware'][] = $this->getMiddleware();
}