mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-17 08:47:52 +00:00
Version 3
- Easier rewrite management. - Optimisations. - Updated documentation.
This commit is contained in:
@@ -2,16 +2,14 @@
|
||||
namespace Pecee\Handlers;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
interface IExceptionHandler
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ILoadableRoute $route
|
||||
* @param \Exception $error
|
||||
* @return Request|null
|
||||
*/
|
||||
public function handleError(Request $request, ILoadableRoute &$route = null, \Exception $error);
|
||||
public function handleError(Request $request, \Exception $error);
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@ namespace Pecee\Http\Middleware;
|
||||
use Pecee\CsrfToken;
|
||||
use Pecee\Http\Middleware\Exceptions\TokenMismatchException;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
class BaseCsrfVerifier implements IMiddleware
|
||||
{
|
||||
@@ -55,7 +54,7 @@ class BaseCsrfVerifier implements IMiddleware
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handle(Request $request, ILoadableRoute &$route = null)
|
||||
public function handle(Request $request)
|
||||
{
|
||||
|
||||
if ($this->skip($request) === false && in_array($request->getMethod(), ['post', 'put', 'delete'], false) === true) {
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
namespace Pecee\Http\Middleware;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
interface IMiddleware
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ILoadableRoute $route
|
||||
* @return Request|null
|
||||
*/
|
||||
public function handle(Request $request, ILoadableRoute &$route);
|
||||
public function handle(Request $request);
|
||||
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
namespace Pecee\Http;
|
||||
|
||||
use Pecee\Http\Input\Input;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
use Pecee\SimpleRouter\Route\IRoute;
|
||||
use Pecee\SimpleRouter\Route\RouteUrl;
|
||||
|
||||
class Request
|
||||
{
|
||||
@@ -12,6 +15,17 @@ class Request
|
||||
protected $method;
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @var ILoadableRoute|null
|
||||
*/
|
||||
protected $rewriteRoute;
|
||||
protected $rewriteUrl;
|
||||
|
||||
/**
|
||||
* @var ILoadableRoute|null
|
||||
*/
|
||||
protected $loadedRoute;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->parseHeaders();
|
||||
@@ -213,6 +227,86 @@ class Request
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rewrite route
|
||||
*
|
||||
* @param ILoadableRoute $route
|
||||
* @return static
|
||||
*/
|
||||
public function setRewriteRoute(ILoadableRoute $route)
|
||||
{
|
||||
$this->rewriteRoute = $route;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rewrite route
|
||||
*
|
||||
* @return IRoute|null
|
||||
*/
|
||||
public function getRewriteRoute()
|
||||
{
|
||||
return $this->rewriteRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rewrite url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRewriteUrl()
|
||||
{
|
||||
return $this->rewriteUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rewrite url
|
||||
*
|
||||
* @param string $rewriteUrl
|
||||
* @return static
|
||||
*/
|
||||
public function setRewriteUrl($rewriteUrl)
|
||||
{
|
||||
$this->rewriteUrl = $rewriteUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rewrite callback
|
||||
* @param string $callback
|
||||
* @return static
|
||||
*/
|
||||
public function setRewriteCallback($callback)
|
||||
{
|
||||
$this->rewriteRoute = new RouteUrl($this->uri, $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loaded route
|
||||
* @return ILoadableRoute|null
|
||||
*/
|
||||
public function getLoadedRoute()
|
||||
{
|
||||
return $this->loadedRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set loaded route
|
||||
*
|
||||
* @param ILoadableRoute $route
|
||||
* @return static
|
||||
*/
|
||||
public function setLoadedRoute(ILoadableRoute $route)
|
||||
{
|
||||
$this->loadedRoute = $route;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return array_key_exists($name, $this->data);
|
||||
|
||||
@@ -3,4 +3,5 @@ namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
class NotFoundHttpException extends HttpException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -20,9 +20,8 @@ interface ILoadableRoute extends IRoute
|
||||
* Loads and renders middlewares-classes
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ILoadableRoute $route
|
||||
*/
|
||||
public function loadMiddleware(Request $request, ILoadableRoute $route);
|
||||
public function loadMiddleware(Request $request);
|
||||
|
||||
public function getUrl();
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ interface IRoute
|
||||
/**
|
||||
* Method called to check if a domain matches
|
||||
*
|
||||
* @param string $route
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function matchRoute(Request $request);
|
||||
public function matchRoute($route, Request $request);
|
||||
|
||||
/**
|
||||
* Called when route is matched.
|
||||
|
||||
@@ -23,10 +23,9 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* Loads and renders middlewares-classes
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ILoadableRoute $route
|
||||
* @throws HttpException
|
||||
*/
|
||||
public function loadMiddleware(Request $request, ILoadableRoute $route)
|
||||
public function loadMiddleware(Request $request)
|
||||
{
|
||||
if (count($this->getMiddlewares()) > 0) {
|
||||
|
||||
@@ -42,7 +41,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
throw new HttpException($middleware . ' must be instance of Middleware');
|
||||
}
|
||||
|
||||
$middleware->handle($request, $route);
|
||||
$middleware->handle($request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +83,9 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
return '/' . trim($url, '/') . '/';
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request)
|
||||
public function matchRoute($url, Request $request)
|
||||
{
|
||||
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
|
||||
$url = parse_url(urldecode($url), PHP_URL_PATH);
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
/* Match global regular-expression for route */
|
||||
|
||||
@@ -40,13 +40,14 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
/**
|
||||
* Method called to check if route matches
|
||||
*
|
||||
* @param string $url
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function matchRoute(Request $request)
|
||||
public function matchRoute($url, Request $request)
|
||||
{
|
||||
/* Skip if prefix doesn't match */
|
||||
if ($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) {
|
||||
if ($this->prefix !== null && stripos($url, $this->prefix) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,9 +76,9 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
return true;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request)
|
||||
public function matchRoute($url, Request $request)
|
||||
{
|
||||
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
|
||||
$url = parse_url(urldecode($url), PHP_URL_PATH);
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
/* Match global regular-expression for route */
|
||||
|
||||
@@ -11,9 +11,9 @@ class RouteUrl extends LoadableRoute
|
||||
$this->setCallback($callback);
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request)
|
||||
public function matchRoute($url, Request $request)
|
||||
{
|
||||
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
|
||||
$url = parse_url(urldecode($url), PHP_URL_PATH);
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
/* Match global regular-expression for route */
|
||||
|
||||
@@ -69,24 +69,6 @@ class Router
|
||||
*/
|
||||
protected $exceptionHandlers;
|
||||
|
||||
/**
|
||||
* The current loaded route
|
||||
* @var ILoadableRoute|null
|
||||
*/
|
||||
protected $loadedRoute;
|
||||
|
||||
/**
|
||||
* List over route changes (to avoid endless-looping)
|
||||
* @var array
|
||||
*/
|
||||
protected $routeRewrites = [];
|
||||
|
||||
/**
|
||||
* If the route has been rewritten/changed this property will contain the original url.
|
||||
* @var string
|
||||
*/
|
||||
protected $originalUrl;
|
||||
|
||||
/**
|
||||
* Get current router instance
|
||||
* @return static
|
||||
@@ -151,6 +133,8 @@ class Router
|
||||
|
||||
$exceptionHandlers = [];
|
||||
|
||||
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
|
||||
|
||||
/* @var $route IRoute */
|
||||
for ($i = $max; $i >= 0; $i--) {
|
||||
|
||||
@@ -167,7 +151,7 @@ class Router
|
||||
$route->renderRoute($this->request);
|
||||
$this->processingRoute = false;
|
||||
|
||||
if ($route->matchRoute($this->request) === true) {
|
||||
if ($route->matchRoute($url, $this->request) === true) {
|
||||
|
||||
/* Add exception handlers */
|
||||
if (count($route->getExceptionHandlers()) > 0) {
|
||||
@@ -216,30 +200,24 @@ class Router
|
||||
|
||||
public function routeRequest($rewrite = false)
|
||||
{
|
||||
$this->loadedRoute = null;
|
||||
$routeNotAllowed = false;
|
||||
|
||||
try {
|
||||
/* Initialize boot-managers */
|
||||
if (count($this->bootManagers) > 0) {
|
||||
|
||||
$max = count($this->bootManagers) - 1;
|
||||
|
||||
/* @var $manager IRouterBootManager */
|
||||
for ($i = $max; $i >= 0; $i--) {
|
||||
|
||||
$manager = $this->bootManagers[$i];
|
||||
|
||||
$this->request = $manager->boot($this->request);
|
||||
|
||||
if (!($this->request instanceof Request)) {
|
||||
throw new HttpException('Bootmanager "' . get_class($manager) . '" must return instance of ' . Request::class, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($rewrite === false) {
|
||||
|
||||
/* Initialize boot-managers */
|
||||
if (count($this->bootManagers) > 0) {
|
||||
|
||||
$max = count($this->bootManagers) - 1;
|
||||
|
||||
/* @var $manager IRouterBootManager */
|
||||
for ($i = $max; $i >= 0; $i--) {
|
||||
$manager = $this->bootManagers[$i];
|
||||
$manager->boot($this->request);
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop through each route-request */
|
||||
$this->processRoutes($this->routes);
|
||||
|
||||
@@ -248,19 +226,19 @@ class Router
|
||||
/* Verify csrf token for request */
|
||||
$this->csrfVerifier->handle($this->request);
|
||||
}
|
||||
|
||||
$this->originalUrl = $this->request->getUri();
|
||||
}
|
||||
|
||||
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
|
||||
|
||||
$max = count($this->processedRoutes) - 1;
|
||||
|
||||
/* @var $route IRoute */
|
||||
/* @var $route ILoadableRoute */
|
||||
for ($i = $max; $i >= 0; $i--) {
|
||||
|
||||
$route = $this->processedRoutes[$i];
|
||||
|
||||
/* If the route matches */
|
||||
if ($route->matchRoute($this->request) === true) {
|
||||
if ($route->matchRoute($url, $this->request) === true) {
|
||||
|
||||
/* Check if request method matches */
|
||||
if (count($route->getRequestMethods()) > 0 && in_array($this->request->getMethod(), $route->getRequestMethods(), false) === false) {
|
||||
@@ -268,12 +246,20 @@ class Router
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->loadedRoute = $route;
|
||||
$this->loadedRoute->loadMiddleware($this->request, $this->loadedRoute);
|
||||
$route->loadMiddleware($this->request);
|
||||
|
||||
/* If the request has changed, we reinitialize the router */
|
||||
if ($this->request->getUri() !== $this->originalUrl && in_array($this->request->getUri(), $this->routeRewrites) === false) {
|
||||
$this->routeRewrites[] = $this->request->getUri();
|
||||
if ($this->request->getRewriteRoute() !== null) {
|
||||
$this->request->getRewriteRoute()->renderRoute($this->request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the request has changed */
|
||||
$rewriteUrl = $this->request->getRewriteUrl();
|
||||
|
||||
if ($rewriteUrl !== null && $rewriteUrl !== $url) {
|
||||
unset($this->processedRoutes[$i]);
|
||||
$this->processedRoutes = array_values($this->processedRoutes);
|
||||
$this->routeRequest(true);
|
||||
|
||||
return;
|
||||
@@ -281,8 +267,8 @@ class Router
|
||||
|
||||
/* Render route */
|
||||
$routeNotAllowed = false;
|
||||
$this->request->setUri($this->originalUrl);
|
||||
$this->loadedRoute->renderRoute($this->request);
|
||||
$this->request->setLoadedRoute($route);
|
||||
$route->renderRoute($this->request);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -296,35 +282,45 @@ class Router
|
||||
$this->handleException(new HttpException('Route or method not allowed', 403));
|
||||
}
|
||||
|
||||
if ($this->loadedRoute === null) {
|
||||
if ($this->request->getLoadedRoute() === null) {
|
||||
$this->handleException(new NotFoundHttpException('Route not found: ' . $this->request->getUri(), 404));
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleException(\Exception $e)
|
||||
{
|
||||
$url = ($this->request->getRewriteUrl() !== null) ? $this->request->getRewriteUrl() : $this->request->getUri();
|
||||
|
||||
$max = count($this->exceptionHandlers);
|
||||
|
||||
/* @var $handler IExceptionHandler */
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
|
||||
$handler = $this->exceptionHandlers[$i];
|
||||
|
||||
$handler = new $handler();
|
||||
|
||||
if (!($handler instanceof IExceptionHandler)) {
|
||||
if (($handler instanceof IExceptionHandler) === false) {
|
||||
throw new HttpException('Exception handler must implement the IExceptionHandler interface.', 500);
|
||||
}
|
||||
|
||||
$request = $handler->handleError($this->request, $this->loadedRoute, $e);
|
||||
if ($handler->handleError($this->request, $e) !== null) {
|
||||
|
||||
/* If the request has changed */
|
||||
if ($request !== null && $this->request->getUri() !== $this->originalUrl && in_array($request->getUri(), $this->routeRewrites) === false) {
|
||||
$this->request = $request;
|
||||
$this->routeRewrites[] = $request->getUri();
|
||||
$this->routeRequest(true);
|
||||
if ($this->request->getRewriteRoute() !== null) {
|
||||
$this->request->getRewriteRoute()->renderRoute($this->request);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
$rewriteUrl = $this->request->getRewriteUrl();
|
||||
|
||||
/* If the request has changed */
|
||||
if ($rewriteUrl !== null && $rewriteUrl !== $url) {
|
||||
unset($this->exceptionHandlers[$i]);
|
||||
$this->exceptionHandlers = array_values($this->exceptionHandlers);
|
||||
$this->routeRequest(true);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,9 +433,11 @@ class Router
|
||||
return (($url === '') ? '/' : $url . '/') . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
$loadedRoute = $this->request->getLoadedRoute();
|
||||
|
||||
/* If nothing is defined and a route is loaded we use that */
|
||||
if ($name === null && $this->loadedRoute !== null) {
|
||||
return $this->loadedRoute->findUrl($this->loadedRoute->getMethod(), $parameters, $name) . $this->arrayToParams($getParams);
|
||||
if ($name === null && $loadedRoute !== null) {
|
||||
return $loadedRoute->findUrl($loadedRoute->getMethod(), $parameters, $name) . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
/* We try to find a match on the given name */
|
||||
@@ -548,13 +546,4 @@ class Router
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loaded route
|
||||
* @return ILoadableRoute|null
|
||||
*/
|
||||
public function getLoadedRoute()
|
||||
{
|
||||
return $this->loadedRoute;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user