diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index bb4bfbd..b1bc66a 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -9,6 +9,7 @@ class RouterBase { protected $currentRoute; protected $routes; + protected $processedRoutes; protected $controllerUrlMap; protected $backstack; protected $requestUri; @@ -25,15 +26,6 @@ class RouterBase { } public function addRoute(RouterEntry $route) { - - if($route instanceof RouterRoute && stripos($route->getCallback(), '@') !== false) { - $this->controllerUrlMap[$route->getCallback()] = $route; - } else if($route instanceof RouterController) { - $this->controllerUrlMap[$route->getController()] = $route; - } else if($route instanceof RouterGroup) { - $this->renderRoute($route); - } - if($this->currentRoute !== null) { $this->backstack[] = $route; } else { @@ -41,52 +33,11 @@ class RouterBase { } } - protected function loadClass($name) { - if(!class_exists($name)) { - throw new RouterException(sprintf('Class %s does not exist', $name)); - } - - return new $name(); - } - - public function renderRoute(RouterEntry $route) { - $this->currentRoute = $route; - - // Load middlewares - if($route->getMiddleware()) { - $this->loadClass($route->getMiddleware()); - } - - if(is_object($route->getCallback()) && is_callable($route->getCallback())) { - - // When the callback is a function - call_user_func_array($route->getCallback(), $route->getParameters(), 404); - - } else if(stripos($route->getCallback(), '@') > 0) { - // When the callback is a method - - $controller = explode('@', $route->getCallback()); - - $className = $route->getNamespace() . '\\' . $controller[0]; - - $class = $this->loadClass($className); - - $this->loadedClass = $class; - - $method = $controller[1]; - - if(!method_exists($class, $method)) { - throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404); - } - - call_user_func_array(array($class, $method), $route->getParameters()); - } - } - - protected function processRoutes(array $routes, array &$settings = array(), array &$prefixes = array()) { + protected function processRoutes(array $routes, array &$settings = array(), array &$prefixes = array(), $match = false, $backstack = false) { // Loop through each route-request + /* @var $route RouterEntry */ - foreach($routes as $route) { + foreach($routes as $i => $route) { if($this->defaultNamespace) { $namespace = null; @@ -107,32 +58,49 @@ class RouterBase { $route->setSettings($settings); - if($route instanceof RouterRoute || $route instanceof RouterController) { + if(($route instanceof RouterRoute || $route instanceof RouterController)) { if(is_array($prefixes) && count($prefixes)) { $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); } } - // Stop if the route matches - $route = $route->getRoute($this->requestMethod, $this->requestUri); - if($route) { - $this->renderRoute($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(count($this->backstack)) { - // Remove itself from backstack - array_shift($this->backstack); + + if($backstack) { + array_shift($this->backstack); + } // Route any routes added to the backstack - $this->processRoutes($this->backstack, $settings, $prefixes); + $this->processRoutes($this->backstack, $settings, $prefixes, $match, true); } + } } public function routeRequest() { // Loop through each route-request + $settings = array(); + $prefixes = array(); - $this->processRoutes($this->routes); + $this->processRoutes($this->routes, $settings, $prefixes, true); + + if(!$this->loadedClass) { + throw new RouterException(sprintf('Route not found: %s', $this->requestUri), 404); + } } /** @@ -181,7 +149,10 @@ class RouterBase { * @return RouterEntry */ public function getCurrentRoute(){ - return $this->currentRoute; + if($this->currentRoute !== null && !($this->currentRoute instanceof RouterGroup)) { + return $this->currentRoute; + } + return null; } /** @@ -191,30 +162,84 @@ class RouterBase { return $this->routes; } - public function getRoute($controller, $parameters = null, $getParams = null) { - /* @var $route RouterRoute */ - foreach($this->controllerUrlMap as $c => $route) { + protected function processUrl($route, $method = null, $parameters = null, $getParams = null) { + $url = rtrim($route->getUrl(), '/') . '/'; + + if($method !== null) { + $url .= $method . '/'; + } + + if($route instanceof RouterController) { + if(count($parameters)) { + $url .= join('/', $parameters); + } + + } else { $params = $route->getParameters(); - - if(strtolower($c) === strtolower($controller) || stripos($c, $controller) === 0) { - - $url = $route->getUrl(); - + if(count($params)) { $i = 0; foreach($params as $param => $value) { $value = (isset($parameters[$param])) ? $parameters[$param] : $value; $url = str_ireplace('{' . $param. '}', $value, $route->getUrl()); $i++; } + } + } - $p = ''; - if($getParams !== null) { - $p = '?'.Url::arrayToParams($getParams); + $p = ''; + if($getParams !== null) { + $p = '?'.Url::arrayToParams($getParams); + } + + $url .= $p; + + return $url; + } + + public function getRoute($controller = null, $parameters = null, $getParams = null) { + $c = ''; + $method = null; + + /* @var $route RouterRoute */ + foreach($this->controllerUrlMap as $route) { + + if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) { + $c = $route->getCallback(); + } else if($route instanceof RouterController) { + $c = $route->getController(); + } + + if($c === $controller || strpos($c, $controller) === 0) { + if(stripos($c, '@') !== false) { + $tmp = explode('@', $route->getCallback()); + $method = strtolower($tmp[1]); + } + return $this->processUrl($route, $method, $parameters, $getParams); + } + } + + // No match has yet been found, let's try to guess what url that should be returned + foreach($this->controllerUrlMap as $route) { + if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) { + $c = $route->getCallback(); + + if(stripos($controller, '@') !== false) { + $tmp = explode('@', $controller); + $c = $tmp[0]; } - $url .= $p; + } else if($route instanceof RouterController) { + $c = $route->getController(); + } - return $url; + if(stripos($controller, '@') !== false) { + $tmp = explode('@', $controller); + $controller = $tmp[0]; + $method = $tmp[1]; + } + + if($controller == $c) { + return $this->processUrl($route, $method, $parameters, $getParams); } } @@ -223,7 +248,7 @@ class RouterBase { public static function getInstance() { if(self::$instance === null) { - self::$instance = new self(); + self::$instance = new static(); } return self::$instance; } diff --git a/src/Pecee/SimpleRouter/RouterController.php b/src/Pecee/SimpleRouter/RouterController.php index 81736d9..856cfce 100644 --- a/src/Pecee/SimpleRouter/RouterController.php +++ b/src/Pecee/SimpleRouter/RouterController.php @@ -17,29 +17,7 @@ class RouterController extends RouterEntry { $this->parameters; } - protected function loadClass() { - - if($this->getNamespace()) { - $className = $this->getNamespace() . '\\' . $this->controller; - } else { - $className = $this->controller; - } - - if(!class_exists($className)) { - throw new RouterException(sprintf('Controller %s not found', $className), 404); - } - - // Call controller - $class = new $className(); - - if(!method_exists($class, $this->method)) { - throw new RouterException(sprintf('Method %s not found in controller %s', $this->method, $className), 404); - } - - call_user_func_array(array($class, $this->method), $this->parameters); - } - - public function getRoute($requestMethod, &$url) { + public function matchRoute($requestMethod, $url) { $url = parse_url($url); $url = $url['path']; @@ -54,17 +32,22 @@ class RouterController extends RouterEntry { $method = (!isset($path[0]) || trim($path[0]) === '') ? self::DEFAULT_METHOD : $path[0]; - $this->method = $requestMethod . ucfirst($method); + $this->method = $method; array_shift($path); $this->parameters = $path; - $this->loadClass(); + // Set callback + $this->setCallback($this->controller . '@' . $this->method); + + return $this; } } + return null; + } /** @@ -78,6 +61,7 @@ class RouterController extends RouterEntry { * @param string $url */ public function setUrl($url) { + $url = rtrim($url, '/') . '/'; $this->url = $url; } diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 6492d99..cd1e893 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -25,6 +25,14 @@ abstract class RouterEntry { $this->parameters = array(); } + protected function loadClass($name) { + if(!class_exists($name)) { + throw new RouterException(sprintf('Class %s does not exist', $name)); + } + + return new $name(); + } + /** * @param string $callback * @return self; @@ -160,6 +168,38 @@ abstract class RouterEntry { $this->settings[$name] = $value; } - abstract function getRoute($requestMethod, &$url); + public function renderRoute($requestMethod) { + // Load middleware + if($this->getMiddleware()) { + $this->loadClass($this->getMiddleware()); + } + + if(is_object($this->getCallback()) && 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 = $requestMethod . ucfirst($controller[1]); + + if (!method_exists($class, $method)) { + throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404); + } + + call_user_func_array(array($class, $method), $this->getParameters()); + + return $class; + } + + return null; + } + + abstract function matchRoute($requestMethod, $url); } \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/RouterGroup.php b/src/Pecee/SimpleRouter/RouterGroup.php index ed227c3..8ea3d1f 100644 --- a/src/Pecee/SimpleRouter/RouterGroup.php +++ b/src/Pecee/SimpleRouter/RouterGroup.php @@ -4,16 +4,14 @@ namespace Pecee\SimpleRouter; class RouterGroup extends RouterEntry { - protected $requestTypes; - public function __construct() { parent::__construct(); - $this->requestTypes = array(); } - public function getRoute($requestMethod, &$url) { + public function matchRoute($requestMethod, $url) { // Check if request method is allowed - if(count($this->requestTypes) === 0 || in_array($requestMethod, $this->requestTypes)) { + + if(count($this->method) === 0 || strtolower($this->method) == strtolower($requestMethod) || is_array($this->method) && in_array($this->method, self::$allowedRequestTypes)) { return $this; } @@ -21,27 +19,4 @@ class RouterGroup extends RouterEntry { return null; } - /** - * Add request type - * - * @param $type - * @return self - * @throws RouterException - */ - public function addRequestType($type) { - if(!in_array($type, self::$allowedRequestTypes)) { - throw new RouterException('Invalid request method: ' . $type); - } - - $this->requestTypes[] = $type; - return $this; - } - - /** - * @return mixed - */ - public function getRequestTypes() { - return $this->requestTypes; - } - } \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/RouterRoute.php b/src/Pecee/SimpleRouter/RouterRoute.php index dfd7917..9498037 100644 --- a/src/Pecee/SimpleRouter/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -43,7 +43,7 @@ class RouterRoute extends RouterEntry { return null; } - public function getRoute($requestMethod, &$url) { + public function matchRoute($requestMethod, $url) { // Check if request method is allowed if(count($this->requestTypes) === 0 || in_array($requestMethod, $this->requestTypes)) { diff --git a/src/Pecee/SimpleRouter/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index 62dfcbb..f30c046 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -103,4 +103,8 @@ class SimpleRouter { // not yet implemented } + public function getRoute($controller = null, $parameters = null, $getParams = null) { + return RouterBase::getInstance()->getRoute($controller, $parameters, $getParams); + } + } \ No newline at end of file