From 2c5221051e0df631a7040e0a2f7f29293c602ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sat, 26 Nov 2016 10:40:42 +0100 Subject: [PATCH] Development --- src/Pecee/SimpleRouter/Route/IRoute.php | 3 +- .../SimpleRouter/Route/LoadableRoute.php | 35 ++++-- src/Pecee/SimpleRouter/Route/Route.php | 77 +++++++----- .../SimpleRouter/Route/RouteController.php | 51 ++------ src/Pecee/SimpleRouter/Route/RouteGroup.php | 36 +++--- .../SimpleRouter/Route/RouteResource.php | 116 +++++++----------- src/Pecee/SimpleRouter/Route/RouteUrl.php | 24 ++-- src/Pecee/SimpleRouter/Router.php | 9 +- 8 files changed, 165 insertions(+), 186 deletions(-) diff --git a/src/Pecee/SimpleRouter/Route/IRoute.php b/src/Pecee/SimpleRouter/Route/IRoute.php index 14bcbe8..a8df2da 100644 --- a/src/Pecee/SimpleRouter/Route/IRoute.php +++ b/src/Pecee/SimpleRouter/Route/IRoute.php @@ -18,7 +18,8 @@ interface IRoute * Returns class to be rendered. * * @param Request $request - * @return \Closure|string + * @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException + * @return void */ public function renderRoute(Request $request); diff --git a/src/Pecee/SimpleRouter/Route/LoadableRoute.php b/src/Pecee/SimpleRouter/Route/LoadableRoute.php index 81b0297..9ae2c0b 100644 --- a/src/Pecee/SimpleRouter/Route/LoadableRoute.php +++ b/src/Pecee/SimpleRouter/Route/LoadableRoute.php @@ -46,6 +46,32 @@ abstract class LoadableRoute extends Route implements ILoadableRoute } } + public function matchRegex(Request $request, $url) { + + /* Match on custom defined regular expression */ + + if ($this->regex === null) { + return false; + } + + $parameters = []; + + if (preg_match($this->regex, $request->getHost() . $url, $parameters) !== false) { + + /* Remove global match */ + if (count($parameters) > 1) { + + $this->setParameters(array_slice($parameters, 1)); + //array_shift($parameters); + //$this->parameters = $parameters; + } + + return true; + } + + return false; + } + /** * Set url * @@ -61,15 +87,8 @@ abstract class LoadableRoute extends Route implements ILoadableRoute $regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]); if (preg_match_all('/' . $regex . '/is', $this->url, $matches)) { - - $max = count($matches[1]); - - for ($i = 0; $i < $max; $i++) { - $this->parameters[$matches[1][$i]] = null; - } - + $this->parameters = array_fill_keys($matches[1], null); } - } return $this; diff --git a/src/Pecee/SimpleRouter/Route/Route.php b/src/Pecee/SimpleRouter/Route/Route.php index cb2a8d3..283e4d7 100644 --- a/src/Pecee/SimpleRouter/Route/Route.php +++ b/src/Pecee/SimpleRouter/Route/Route.php @@ -23,6 +23,13 @@ abstract class Route implements IRoute self::REQUEST_TYPE_DELETE, ]; + /** + * If enabled parameters containing null-value + * will not be passed along to the callback. + * + * @var bool + */ + protected $filterEmptyParams = false; protected $paramModifiers = '{}'; protected $paramOptionalSymbol = '?'; protected $group; @@ -38,6 +45,15 @@ abstract class Route implements IRoute protected $parameters = []; protected $middlewares = []; + protected function loadClass($name) + { + if (!class_exists($name)) { + throw new NotFoundHttpException(sprintf('Class %s does not exist', $name), 404); + } + + return new $name(); + } + public function renderRoute(Request $request) { if ($this->getCallback() !== null && is_callable($this->getCallback())) { @@ -54,20 +70,22 @@ abstract class Route implements IRoute $class = $this->loadClass($className); $method = $controller[1]; - if (!method_exists($class, $method)) { + if (method_exists($class, $method) === false) { throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404); } - $parameters = array_filter($this->getParameters(), function ($var) { - return ($var !== null); - }); + $parameters = []; + + /* Filter parameters with null-value */ + + if ($this->filterEmptyParams === true) { + $parameters = array_filter($this->getParameters(), function ($var) { + return ($var !== null); + }); + } call_user_func_array([$class, $method], $parameters); - - return $class; } - - return null; } protected function parseParameters($route, $url, $parameterRegex = '[\w]+') @@ -84,13 +102,16 @@ abstract class Route implements IRoute $character = strrev($route)[$i]; if ($character === '{') { + /* Remove "/" and "\" from regex */ if (substr($regex, strlen($regex) - 1) === '/') { $regex = substr($regex, 0, -2); } $isParameter = true; - } elseif ($isParameter && $character === '}') { + + } elseif ($isParameter === true && $character === '}') { + $required = true; /* Check for optional parameter and use custom parameter regex if it exists */ @@ -99,11 +120,15 @@ abstract class Route implements IRoute } if ($lastCharacter === '?') { + $parameter = substr($parameter, 0, -1); $regex .= '(?:\/?(?P<' . $parameter . '>' . $parameterRegex . ')[^\/]?)?'; $required = false; + } else { + $regex .= '\/?(?P<' . $parameter . '>' . $parameterRegex . ')[^\/]?'; + } $parameterNames[] = [ @@ -113,12 +138,19 @@ abstract class Route implements IRoute $parameter = ''; $isParameter = false; - } elseif ($isParameter) { + + } elseif ($isParameter === true) { + $parameter .= $character; + } elseif ($character === '/') { + $regex .= '\\' . $character; + } else { + $regex .= str_replace('.', '\\.', $character); + } $lastCharacter = $character; @@ -129,7 +161,6 @@ abstract class Route implements IRoute if (preg_match('/^' . $regex . '\/?$/is', $url, $parameterValues)) { $parameters = []; - $max = count($parameterNames) - 1; for ($i = $max; $i >= 0; $i--) { @@ -155,15 +186,6 @@ abstract class Route implements IRoute return null; } - protected function loadClass($name) - { - if (!class_exists($name)) { - throw new NotFoundHttpException(sprintf('Class %s does not exist', $name), 404); - } - - return new $name(); - } - /** * Returns callback name/identifier for the current route based on the callback. * Useful if you need to get a unique identifier for the loaded route, for instance @@ -384,13 +406,7 @@ abstract class Route implements IRoute } if (count($this->parameters) > 0) { - - /* Ensure the right order + values */ - $parameters = (isset($values['parameters']) ? $values['parameters'] : []) + $this->parameters; - $parameters = array_merge($parameters, $this->parameters); - - $this->setParameters($parameters); - $values['parameters'] = $parameters; + $values['parameters'] = $this->parameters; } if (count($this->middlewares) > 0) { @@ -422,7 +438,7 @@ abstract class Route implements IRoute } if (isset($values['parameters'])) { - $this->setParameters(array_merge($this->parameters, (array)$values['parameters'])); + $this->setParameters($values['parameters']); } // Push middleware if multiple @@ -487,7 +503,10 @@ abstract class Route implements IRoute */ public function setParameters(array $parameters) { - $this->parameters = $parameters; + /* Ensure the right order + values */ + + $this->parameters = array_fill_keys(array_keys($parameters), null) + $this->parameters; + $this->parameters = $parameters + $this->parameters; return $this; } diff --git a/src/Pecee/SimpleRouter/Route/RouteController.php b/src/Pecee/SimpleRouter/Route/RouteController.php index 486d92a..c4e5520 100644 --- a/src/Pecee/SimpleRouter/Route/RouteController.php +++ b/src/Pecee/SimpleRouter/Route/RouteController.php @@ -2,7 +2,6 @@ namespace Pecee\SimpleRouter\Route; use Pecee\Http\Request; -use Pecee\SimpleRouter\Exceptions\NotFoundHttpException; class RouteController extends LoadableRoute implements IControllerRoute { @@ -35,7 +34,7 @@ class RouteController extends LoadableRoute implements IControllerRoute $method = substr($name, strrpos($name, '.') + 1); $newName = substr($name, 0, strrpos($name, '.')); - if (in_array($method, $this->names) === true && strtolower($this->name) === strtolower($newName)) { + if (in_array($method, $this->names, false) === true && strtolower($this->name) === strtolower($newName)) { return true; } } @@ -52,7 +51,7 @@ class RouteController extends LoadableRoute implements IControllerRoute public function findUrl($method = null, $parameters = null, $name = null) { if (strpos($name, '.') !== false) { - $found = array_search(substr($name, strrpos($name, '.') + 1), $this->names); + $found = array_search(substr($name, strrpos($name, '.') + 1), $this->names, false); if ($found !== false) { $method = $found; } @@ -61,14 +60,10 @@ class RouteController extends LoadableRoute implements IControllerRoute $url = ''; $parameters = (array)$parameters; - /* Remove requestType from method-name, if it exists */ if ($method !== null) { - $max = count(static::$requestTypes); - - for ($i = 0; $i < $max; $i++) { - - $requestType = static::$requestTypes[$i]; + /* Remove requestType from method-name, if it exists */ + foreach(static::$requestTypes as $requestType) { if (stripos($method, $requestType) === 0) { $method = substr($method, strlen($requestType)); @@ -88,37 +83,16 @@ class RouteController extends LoadableRoute implements IControllerRoute return '/' . trim($url, '/') . '/'; } - public function renderRoute(Request $request) - { - if ($this->getCallback() !== null && is_callable($this->getCallback())) { - - // When the callback is a function - call_user_func_array($this->getCallback(), $this->getParameters()); - } else { - // When the callback is a method - $controller = explode('@', $this->getCallback()); - $className = $this->getNamespace() . '\\' . $controller[0]; - - $class = $this->loadClass($className); - $method = $request->getMethod() . ucfirst($controller[1]); - - if (!method_exists($class, $method)) { - throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404); - } - - call_user_func_array([$class, $method], $this->getParameters()); - - return $class; - } - - return null; - } - public function matchRoute(Request $request) { $url = parse_url(urldecode($request->getUri()), PHP_URL_PATH); $url = rtrim($url, '/') . '/'; + /* Match global regular-expression for route */ + if($this->matchRegex($request, $url) === true) { + return true; + } + if (stripos($url, $this->url) === 0 && strtolower($url) === strtolower($this->url)) { $strippedUrl = trim(str_ireplace($this->url, '/', $url), '/'); @@ -130,9 +104,10 @@ class RouteController extends LoadableRoute implements IControllerRoute $method = (!isset($path[0]) || trim($path[0]) === '') ? $this->defaultMethod : $path[0]; $this->method = $method; - array_shift($path); + //array_shift($path); + //$this->parameters = $path; - $this->parameters = $path; + $this->setParameters(array_slice($path, 1)); // Set callback $this->setCallback($this->controller . '@' . $this->method); @@ -141,7 +116,7 @@ class RouteController extends LoadableRoute implements IControllerRoute } } - return null; + return false; } /** diff --git a/src/Pecee/SimpleRouter/Route/RouteGroup.php b/src/Pecee/SimpleRouter/Route/RouteGroup.php index f55567d..c466749 100644 --- a/src/Pecee/SimpleRouter/Route/RouteGroup.php +++ b/src/Pecee/SimpleRouter/Route/RouteGroup.php @@ -18,26 +18,24 @@ class RouteGroup extends Route implements IGroupRoute */ public function matchDomain(Request $request) { - if (count($this->domains) > 0) { - - $max = count($this->domains) - 1; - - for ($i = $max; $i >= 0; $i--) { - - $domain = $this->domains[$i]; - $parameters = $this->parseParameters($domain, $request->getHost(), '.*'); - - if ($parameters !== null && count($parameters) > 0) { - $this->parameters = array_merge($this->parameters, $parameters); - - return true; - } - } - - return false; + if (count($this->domains) === 0) { + return true; } - return true; + foreach($this->domains as $domain) { + + $parameters = $this->parseParameters($domain, $request->getHost(), '.*'); + + if ($parameters !== null && count($parameters) > 0) { + + $this->setParameters($parameters); + //$this->parameters = array_merge($this->parameters, $parameters); + + return true; + } + } + + return false; } /** @@ -48,7 +46,7 @@ class RouteGroup extends Route implements IGroupRoute */ public function matchRoute(Request $request) { - // Skip if prefix doesn't match + /* Skip if prefix doesn't match */ if ($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) { return false; } diff --git a/src/Pecee/SimpleRouter/Route/RouteResource.php b/src/Pecee/SimpleRouter/Route/RouteResource.php index a4ea2b3..2efdbd6 100644 --- a/src/Pecee/SimpleRouter/Route/RouteResource.php +++ b/src/Pecee/SimpleRouter/Route/RouteResource.php @@ -2,7 +2,6 @@ namespace Pecee\SimpleRouter\Route; use Pecee\Http\Request; -use Pecee\SimpleRouter\Exceptions\NotFoundHttpException; class RouteResource extends LoadableRoute implements IControllerRoute { @@ -70,34 +69,9 @@ class RouteResource extends LoadableRoute implements IControllerRoute return $this->url; } - public function renderRoute(Request $request) - { - if ($this->getCallback() !== null && is_callable($this->getCallback())) { - // When the callback is a function - call_user_func_array($this->getCallback(), $this->getParameters()); - } else { - // When the callback is a method - $controller = explode('@', $this->getCallback()); - $className = $this->getNamespace() . '\\' . $controller[0]; - $class = $this->loadClass($className); - $method = strtolower($controller[1]); - - if (!method_exists($class, $method)) { - throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404); - } - - call_user_func_array([$class, $method], $this->getParameters()); - - return $class; - } - - return null; - } - - protected function call($method, $parameters) + protected function call($method) { $this->setCallback($this->controller . '@' . $method); - $this->parameters = $parameters; return true; } @@ -107,54 +81,58 @@ class RouteResource extends LoadableRoute implements IControllerRoute $url = parse_url(urldecode($request->getUri()), PHP_URL_PATH); $url = rtrim($url, '/') . '/'; + /* Match global regular-expression for route */ + if($this->matchRegex($request, $url) === true) { + return true; + } + $route = rtrim($this->url, '/') . '/{id?}/{action?}'; $parameters = $this->parseParameters($route, $url); - if ($parameters !== null) { - - $parameters = array_merge($this->parameters, (array)$parameters); - - $action = isset($parameters['action']) ? $parameters['action'] : null; - unset($parameters['action']); - - $method = $request->getMethod(); - - // Delete - if ($method === static::REQUEST_TYPE_DELETE && isset($parameters['id'])) { - return $this->call($this->methodNames['destroy'], $parameters); - } - - // Update - if (isset($parameters['id']) && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT])) { - return $this->call($this->methodNames['update'], $parameters); - } - - // Edit - if ($method === static::REQUEST_TYPE_GET && isset($parameters['id']) && strtolower($action) === 'edit') { - return $this->call($this->methodNames['edit'], $parameters); - } - - // Create - if ($method === static::REQUEST_TYPE_GET && strtolower($action) === 'create') { - return $this->call($this->methodNames['create'], $parameters); - } - - // Save - if ($method === static::REQUEST_TYPE_POST) { - return $this->call($this->methodNames['store'], $parameters); - } - - // Show - if ($method === static::REQUEST_TYPE_GET && isset($parameters['id'])) { - return $this->call($this->methodNames['show'], $parameters); - } - - // Index - return $this->call($this->methodNames['index'], $parameters); + if ($parameters === null) { + return false; } - return null; + $this->setParameters((array)$parameters); + + $action = isset($this->parameters['action']) ? $this->parameters['action'] : null; + unset($this->parameters['action']); + + $method = $request->getMethod(); + + // Delete + if ($method === static::REQUEST_TYPE_DELETE && isset($this->parameters['id'])) { + return $this->call($this->methodNames['destroy']); + } + + // Update + if (isset($this->parameters['id']) && in_array($method, [ static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT ])) { + return $this->call($this->methodNames['update']); + } + + // Edit + if ($method === static::REQUEST_TYPE_GET && isset($this->parameters['id']) && strtolower($action) === 'edit') { + return $this->call($this->methodNames['edit']); + } + + // Create + if ($method === static::REQUEST_TYPE_GET && strtolower($action) === 'create') { + return $this->call($this->methodNames['create']); + } + + // Save + if ($method === static::REQUEST_TYPE_POST) { + return $this->call($this->methodNames['store']); + } + + // Show + if ($method === static::REQUEST_TYPE_GET && isset($this->parameters['id'])) { + return $this->call($this->methodNames['show']); + } + + // Index + return $this->call($this->methodNames['index']); } /** diff --git a/src/Pecee/SimpleRouter/Route/RouteUrl.php b/src/Pecee/SimpleRouter/Route/RouteUrl.php index baa2329..ff9be14 100644 --- a/src/Pecee/SimpleRouter/Route/RouteUrl.php +++ b/src/Pecee/SimpleRouter/Route/RouteUrl.php @@ -16,34 +16,24 @@ class RouteUrl extends LoadableRoute $url = parse_url(urldecode($request->getUri()), PHP_URL_PATH); $url = rtrim($url, '/') . '/'; - // Match on custom defined regular expression - if ($this->regex !== null) { - $parameters = []; - if (preg_match($this->regex, $request->getHost() . $url, $parameters)) { - /* Remove global match */ - if (count($parameters) > 1) { - array_shift($parameters); - $this->parameters = $parameters; - } - - return true; - } - - return null; + /* Match global regular-expression for route */ + if($this->matchRegex($request, $url) === true) { + return true; } - // Make regular expression based on route + /* Make regular expression based on route */ $route = rtrim($this->url, '/') . '/'; $parameters = $this->parseParameters($route, $url); if ($parameters !== null) { - $this->parameters = array_merge($this->parameters, $parameters); + $this->setParameters($parameters); + //$this->parameters = array_merge($this->parameters, $parameters); return true; } - return null; + return false; } } \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/Router.php b/src/Pecee/SimpleRouter/Router.php index e031431..7b8a9f2 100644 --- a/src/Pecee/SimpleRouter/Router.php +++ b/src/Pecee/SimpleRouter/Router.php @@ -167,7 +167,7 @@ class Router $route->renderRoute($this->request); $this->processingRoute = false; - if ($route->matchRoute($this->request)) { + if ($route->matchRoute($this->request) === true) { /* Add exception handlers */ if (count($route->getExceptionHandlers()) > 0) { @@ -220,7 +220,6 @@ class Router $routeNotAllowed = false; try { - /* Initialize boot-managers */ if (count($this->bootManagers) > 0) { @@ -246,7 +245,7 @@ class Router if ($this->csrfVerifier !== null) { - // Verify csrf token for request + /* Verify csrf token for request */ $this->csrfVerifier->handle($this->request); } @@ -261,10 +260,10 @@ class Router $route = $this->processedRoutes[$i]; /* If the route matches */ - if ($route->matchRoute($this->request)) { + if ($route->matchRoute($this->request) === true) { /* Check if request method matches */ - if (count($route->getRequestMethods()) > 0 && in_array($this->request->getMethod(), $route->getRequestMethods()) === false) { + if (count($route->getRequestMethods()) > 0 && in_array($this->request->getMethod(), $route->getRequestMethods(), false) === false) { $routeNotAllowed = true; continue; }