diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index 3830137..34e97bc 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -14,15 +14,18 @@ class RouterBase { protected $backstack; protected $requestUri; protected $requestMethod; - protected $loadedClass; + protected $loadedRoute; protected $defaultNamespace; + // TODO: make interface for controller routers, so they can be easily detected + // TODO: clean up - cut some of the methods down to smaller pieces + public function __construct() { $this->routes = array(); $this->backstack = array(); $this->controllerUrlMap = array(); $this->requestUri = $_SERVER['REQUEST_URI']; - $this->requestMethod = ($_SERVER['REQUEST_METHOD'] != 'GET') ? 'post' : 'get'; + $this->requestMethod = (isset($_POST['_method'])) ? strtolower($_POST['_method']) : strtolower($_SERVER['REQUEST_METHOD']); } public function addRoute(RouterEntry $route) { @@ -33,11 +36,11 @@ class RouterBase { } } - protected function processRoutes(array $routes, array &$settings = array(), array &$prefixes = array(), $match = false, $backstack = false) { + protected function processRoutes(array $routes, array $settings = array(), array $prefixes = array(), $backstack = false) { // Loop through each route-request /* @var $route RouterEntry */ - foreach($routes as $i => $route) { + foreach($routes as $route) { if($this->defaultNamespace) { $namespace = null; @@ -51,54 +54,51 @@ class RouterBase { $route->setNamespace($namespace); } - $settings = array_merge($settings, $route->getMergeableSettings()); + $newPrefixes = $prefixes; + $mergedSettings = array_merge($settings, $route->getMergeableSettings()); if($route->getPrefix()) { - array_push($prefixes, $route->getPrefix()); + array_push($newPrefixes, rtrim($route->getPrefix(), '/')); + } + $route->addSettings($mergedSettings); + + if(!($route instanceof RouterGroup) && is_array($newPrefixes) && count($newPrefixes) && $backstack) { + $route->setUrl( join('/', $newPrefixes) . $route->getUrl() ); } - $route->setSettings($settings); - - if(($route instanceof RouterRoute || $route instanceof RouterController)) { - if(is_array($prefixes) && count($prefixes)) { - $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); - } - } + $this->controllerUrlMap[] = $route; $this->currentRoute = $route; - - if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) { - $this->controllerUrlMap[] = $route; - } else if($route instanceof RouterController) { - $this->controllerUrlMap[] = $route; - } - - $routeMatch = $route->matchRoute($this->requestMethod, rtrim($this->requestUri, '/') . '/'); - - if($routeMatch && $match) { - $this->loadedClass = $routeMatch->renderRoute($this->requestMethod); + if($route instanceof RouterGroup && is_callable($route->getCallback())) { + $route->renderRoute($this->requestMethod); } + $this->currentRoute = null; if(count($this->backstack)) { - - if($backstack) { - array_shift($this->backstack); - } + $backstack = $this->backstack; + $this->backstack = array(); // Route any routes added to the backstack - $this->processRoutes($this->backstack, $settings, $prefixes, $match, true); + $this->processRoutes($backstack, $mergedSettings, $newPrefixes, true); } - } } public function routeRequest() { // Loop through each route-request - $settings = array(); - $prefixes = array(); - $this->processRoutes($this->routes, $settings, $prefixes, true); + $this->processRoutes($this->routes); - if(!$this->loadedClass) { + foreach($this->controllerUrlMap as $route) { + $routeMatch = $route->matchRoute($this->requestMethod, rtrim($this->requestUri, '/') . '/'); + + if($routeMatch && !($routeMatch instanceof RouterGroup)) { + $this->loadedRoute = $routeMatch; + $routeMatch->renderRoute($this->requestMethod); + break; + } + } + + if(!$this->loadedRoute) { throw new RouterException(sprintf('Route not found: %s', $this->requestUri), 404); } } @@ -149,10 +149,7 @@ class RouterBase { * @return RouterEntry */ public function getCurrentRoute(){ - if($this->currentRoute !== null && !($this->currentRoute instanceof RouterGroup)) { - return $this->currentRoute; - } - return null; + return $this->currentRoute; } /** @@ -169,12 +166,12 @@ class RouterBase { $url .= $method . '/'; } - if($route instanceof RouterController) { + if($route instanceof RouterController || $route instanceof RouterRessource) { if(count($parameters)) { $url .= join('/', $parameters); } - } else { + /* @var $route RouterEntry */ $params = $route->getParameters(); if(count($params)) { $i = 0; @@ -187,7 +184,7 @@ class RouterBase { } $p = ''; - if($getParams !== null) { + if($getParams !== null && count($getParams)) { $p = '?'.Url::arrayToParams($getParams); } @@ -197,6 +194,15 @@ class RouterBase { } public function getRoute($controller = null, $parameters = null, $getParams = null) { + + if($parameters !== null && !is_array($parameters)) { + throw new \InvalidArgumentException('Invalid type for parameter. Must be array or null'); + } + + if($getParams !== null && !is_array($getParams)) { + throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null'); + } + $c = ''; $method = null; @@ -205,7 +211,7 @@ class RouterBase { if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) { $c = $route->getCallback(); - } else if($route instanceof RouterController) { + } else if($route instanceof RouterController || $route instanceof RouterRessource) { $c = $route->getController(); } @@ -228,7 +234,7 @@ class RouterBase { $c = $tmp[0]; } - } else if($route instanceof RouterController) { + } else if($route instanceof RouterController || $route instanceof RouterRessource) { $c = $route->getController(); } @@ -243,6 +249,14 @@ class RouterBase { } } + // Nothing found - return current route + if($this->loadedRoute) { + $getParams = ($getParams === null) ? array() : $getParams; + $params = ($this->loadedRoute->getParameters() == null) ? array() : $this->loadedRoute->getParameters(); + $parameters = ($parameters === null) ? array() : $parameters; + return $this->processUrl($this->loadedRoute, null, array_merge($params, $parameters), array_merge($_GET, $getParams)); + } + return '/'; } diff --git a/src/Pecee/SimpleRouter/RouterController.php b/src/Pecee/SimpleRouter/RouterController.php index fe1a9f4..59a7d02 100644 --- a/src/Pecee/SimpleRouter/RouterController.php +++ b/src/Pecee/SimpleRouter/RouterController.php @@ -8,13 +8,11 @@ class RouterController extends RouterEntry { protected $url; protected $controller; protected $method; - protected $parameters; public function __construct($url, $controller) { parent::__construct(); $this->url = $url; $this->controller = $controller; - $this->parameters; } public function matchRoute($requestMethod, $url) { @@ -22,7 +20,7 @@ class RouterController extends RouterEntry { $url = parse_url($url); $url = $url['path']; - if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) !== false) { + if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) { $strippedUrl = trim(str_ireplace($this->url, '/', $url), '/'); @@ -60,20 +58,6 @@ class RouterController extends RouterEntry { $this->url = $url; } - /** - * @return array - */ - public function getParameters() { - return $this->parameters; - } - - /** - * @param array $parameters - */ - public function setParameters($parameters) { - $this->parameters = $parameters; - } - /** * @return string */ diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index d91ecb4..70cfe7f 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -70,7 +70,7 @@ abstract class RouterEntry { * @return self */ public function setPrefix($prefix) { - $this->prefix = trim($prefix, '/'); + $this->prefix = '/' . trim($prefix, '/') . '/'; return $this; } @@ -139,12 +139,26 @@ abstract class RouterEntry { return $settings; } + /** + * @param array $settings + * @return self + */ + public function addSettings(array $settings) { + array_merge($this->settings, $settings); + return $this; + } + /** * @param array $settings * @return self */ public function setSettings($settings) { $this->settings = $settings; + + if($settings['prefix']) { + $this->setPrefix($settings['prefix']); + } + return $this; } diff --git a/src/Pecee/SimpleRouter/RouterGroup.php b/src/Pecee/SimpleRouter/RouterGroup.php index 8ea3d1f..2624706 100644 --- a/src/Pecee/SimpleRouter/RouterGroup.php +++ b/src/Pecee/SimpleRouter/RouterGroup.php @@ -11,7 +11,22 @@ class RouterGroup extends RouterEntry { public function matchRoute($requestMethod, $url) { // Check if request method is allowed - if(count($this->method) === 0 || strtolower($this->method) == strtolower($requestMethod) || is_array($this->method) && in_array($this->method, self::$allowedRequestTypes)) { + if(strtolower($url) == strtolower($this->prefix) || stripos($url, $this->prefix) === 0) { + + $hasAccess = (!$this->method); + + if($this->method) { + if(is_array($this->method)) { + $hasAccess = (in_array($requestMethod, $this->method)); + } else { + $hasAccess = strtolower($this->method) == strtolower($requestMethod); + } + } + + if(!$hasAccess) { + throw new RouterException('Method not allowed'); + } + return $this; } diff --git a/src/Pecee/SimpleRouter/RouterRessource.php b/src/Pecee/SimpleRouter/RouterRessource.php index dc61ad5..359617d 100644 --- a/src/Pecee/SimpleRouter/RouterRessource.php +++ b/src/Pecee/SimpleRouter/RouterRessource.php @@ -8,15 +8,13 @@ class RouterRessource extends RouterEntry { protected $url; protected $controller; protected $method; - protected $parameters; protected $postMethod; public function __construct($url, $controller) { parent::__construct(); $this->url = $url; $this->controller = $controller; - $this->parameters; - $this->postMethod = strtoupper(isset($_POST['_method']) ? $_POST['_method'] : $_SERVER['REQUEST_METHOD']); + $this->postMethod = strtolower(($_SERVER['REQUEST_METHOD'] != 'GET') ? 'post' : 'get'); } public function renderRoute($requestMethod) { @@ -26,7 +24,6 @@ class RouterRessource extends RouterEntry { } if(is_object($this->getCallback()) && is_callable($this->getCallback())) { - // When the callback is a function call_user_func_array($this->getCallback(), $this->getParameters()); } else { @@ -58,7 +55,7 @@ class RouterRessource extends RouterEntry { $url = parse_url($url); $url = $url['path']; - if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) !== false) { + if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url . '/') === 0) { $url = rtrim($url, '/'); $strippedUrl = trim(substr($url, strlen($this->url)), '/'); @@ -75,32 +72,32 @@ class RouterRessource extends RouterEntry { if (count($path)) { // Delete - if($this->postMethod === 'DELETE' && $requestMethod === self::REQUEST_TYPE_POST) { + if($requestMethod === self::REQUEST_TYPE_DELETE && $this->postMethod === self::REQUEST_TYPE_POST) { return $this->call('destroy', $args); } // Update - if(in_array($this->postMethod, array('PUT', 'PATCH')) && $requestMethod === self::REQUEST_TYPE_POST) { + if(in_array($requestMethod, array('put', 'patch')) && $this->postMethod === self::REQUEST_TYPE_POST) { return $this->call('update', array_merge(array($action), $args)); } // Edit - if(isset($args[0]) && strtolower($args[0]) === 'edit' && $requestMethod === self::REQUEST_TYPE_GET) { + if(isset($args[0]) && strtolower($args[0]) === 'edit' && $this->postMethod === self::REQUEST_TYPE_GET) { return $this->call('edit', array_merge(array($action), array_slice($args, 1))); } // Create - if(strtolower($action) === 'create' && $this->postMethod === 'GET') { + if(strtolower($action) === 'create' && $requestMethod === self::REQUEST_TYPE_GET) { return $this->call('create', $args); } // Save - if($requestMethod === self::REQUEST_TYPE_POST) { + if($this->postMethod === self::REQUEST_TYPE_POST) { return $this->call('store', $args); } // Show - if($action && $requestMethod === self::REQUEST_TYPE_GET) { + if($action && $this->postMethod === self::REQUEST_TYPE_GET) { return $this->call('show', array_merge(array($action), $args)); } @@ -112,4 +109,47 @@ class RouterRessource extends RouterEntry { return null; } + /** + * @return string + */ + public function getUrl() { + return $this->url; + } + + /** + * @param string $url + */ + public function setUrl($url) { + $url = rtrim($url, '/') . '/'; + $this->url = $url; + } + + /** + * @return string + */ + public function getController() { + return $this->controller; + } + + /** + * @param string $controller + */ + public function setController($controller) { + $this->controller = $controller; + } + + /** + * @return string + */ + public function getMethod() { + return $this->method; + } + + /** + * @param string $method + */ + public function setMethod($method) { + $this->method = $method; + } + } \ No newline at end of file