From f528ec05d2c197daf96cde79583bdf293132fe58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 18:51:47 +0200 Subject: [PATCH 01/29] [TASK] Added composer.json --- composer.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..bc787f9 --- /dev/null +++ b/composer.json @@ -0,0 +1,29 @@ +{ + "name": "pecee/simple-router", + "description": "Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.", + "keywords": [ "router", "routing", "laravel", "pecee" ], + "license": "MIT", + "support": { + "source": "https://github.com/skipperbent/simple-php-router/issues" + }, + "authors": [ + { + "name": "Simon Sessingø", + "email": "simon.sessingoe@gmail.com" + } + ], + "require": { + + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "autoload": { + "psr-4": { + "Pecee\\": "src/Pecee/" + } + }, + "config": { + "preferred-install": "dist" + } +} \ No newline at end of file From a0e05782e2ec50f67062258eeb53ec3b1556dcf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 19:08:44 +0200 Subject: [PATCH 02/29] [TASK] Updated composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bc787f9..392cfdd 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ }, "require-dev": { - "phpunit/phpunit": "4.*" + "phpunit/phpunit": "4.7.7" }, "autoload": { "psr-4": { From 291f7117d668a280e1ba4fb6947147fd3004ea7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 19:20:05 +0200 Subject: [PATCH 03/29] [TASK] Updated composer.json --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 392cfdd..aa22e5d 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,5 @@ "psr-4": { "Pecee\\": "src/Pecee/" } - }, - "config": { - "preferred-install": "dist" } } \ No newline at end of file From d4f0046283760191011148248a61a604f7dcdbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 19:41:55 +0200 Subject: [PATCH 04/29] =?UTF-8?q?[TASK]=C2=A0Updated=20composer.json,=20ad?= =?UTF-8?q?ded=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ composer.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..005d2e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +composer.lock \ No newline at end of file diff --git a/composer.json b/composer.json index aa22e5d..e7c280b 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ }, "autoload": { "psr-4": { - "Pecee\\": "src/Pecee/" + "Pecee\\": "src/" } } } \ No newline at end of file From 05a89c368d5967f379c7bb07319197766cabce69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 19:55:17 +0200 Subject: [PATCH 05/29] =?UTF-8?q?[TASK]=C2=A0Updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pecee/Router.php | 6 ++++++ src/Pecee/Router/RouterRoute.php | 3 --- src/Pecee/Router/SimpleRouter.php | 9 --------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Pecee/Router.php b/src/Pecee/Router.php index 0755832..d3a5c72 100644 --- a/src/Pecee/Router.php +++ b/src/Pecee/Router.php @@ -9,10 +9,16 @@ namespace Pecee; +use Pecee\Router\RouterGroup; +use Pecee\Router\RouterRoute; use Pecee\Router\SimpleRouter; class Router { + public static function init() { + SimpleRouter::GetInstance()->routeRequest(); + } + public static function get($url, $callback) { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_GET); diff --git a/src/Pecee/Router/RouterRoute.php b/src/Pecee/Router/RouterRoute.php index c3bd5ea..5766ef5 100644 --- a/src/Pecee/Router/RouterRoute.php +++ b/src/Pecee/Router/RouterRoute.php @@ -15,9 +15,6 @@ class RouterRoute extends RouterEntry { $this->callback = $callback; $this->settings['aliases'] = array(); - - // Set default namespace - $this->namespace = Registry::GetInstance()->get(SimpleRouter::SETTINGS_APPNAME, false) . '\\' . 'Controller'; } public function getRoute($requestMethod, &$url) { diff --git a/src/Pecee/Router/SimpleRouter.php b/src/Pecee/Router/SimpleRouter.php index 328a222..d1481e0 100644 --- a/src/Pecee/Router/SimpleRouter.php +++ b/src/Pecee/Router/SimpleRouter.php @@ -3,8 +3,6 @@ namespace Pecee\Router; class SimpleRouter { - const SETTINGS_APPNAME = 'AppName'; - protected static $instance; protected $currentRoute; @@ -13,15 +11,8 @@ class SimpleRouter { protected $requestUri; protected $requestMethod; protected $loadedClass; - protected $appName; public function __construct() { - - $this->appName = Registry::GetInstance()->get(self::SETTINGS_APPNAME, false); - if (!$this->appName) { - throw new RouterException('"AppName" registry key not defined!', 2); - } - $this->routes = array(); $this->backstack = array(); $this->requestUri = rtrim($_SERVER['REQUEST_URI'], '/'); From c9f3cc93293591329b96f781c6ffe7f33b1e123f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 20:16:59 +0200 Subject: [PATCH 06/29] [TASK] - Renamed to avoid conflicts with other routers. - Updated documentation. --- README.md | 26 ++++---- src/Pecee/{Router.php => SimpleRouter.php} | 24 +++---- .../Router.php} | 66 ++++++++++++++++++- .../{Router => SimpleRouter}/RouterEntry.php | 0 .../RouterException.php | 0 .../{Router => SimpleRouter}/RouterGroup.php | 0 .../{Router => SimpleRouter}/RouterRoute.php | 2 +- 7 files changed, 92 insertions(+), 26 deletions(-) rename src/Pecee/{Router.php => SimpleRouter.php} (77%) rename src/Pecee/{Router/SimpleRouter.php => SimpleRouter/Router.php} (75%) rename src/Pecee/{Router => SimpleRouter}/RouterEntry.php (100%) rename src/Pecee/{Router => SimpleRouter}/RouterException.php (100%) rename src/Pecee/{Router => SimpleRouter}/RouterGroup.php (100%) rename src/Pecee/{Router => SimpleRouter}/RouterRoute.php (98%) diff --git a/README.md b/README.md index 23f2d5f..84dc879 100644 --- a/README.md +++ b/README.md @@ -22,13 +22,15 @@ In your ```index.php``` require your ```routes.php``` and call the ```routeReque This is an example of a basic ```index.php``` file: ```php +use \Pecee\SimpleRouter; + require_once 'routes.php'; // change this to whatever makes sense in your project - -// Initialise the router -$router = \Pecee\SimpleRouter::GetInstance(); - -// Do the actual routing -$router->routeRequest() + +// The apps default namespace (so we don't have to specify it each time we use MyController@home) +$defaultControllerNamespace = 'MyWebsite\\Controller'; + +// Do the routing +SimpleRouter::init($defaultControllerNamespace); ``` ## Adding routes @@ -39,7 +41,7 @@ This router is heavily inspired by the Laravel 5.* router, so anything you find ### Basic example ```php -using \Pecee\Router; +using \Pecee\SimpleRouter; /* * This route will match the url /v1/services/answers/1/ @@ -49,11 +51,11 @@ using \Pecee\Router; * the request, for instance if a user is not authenticated. */ -Router::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\SomeMiddlewareClass'], function() { +SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\SomeMiddlewareClass'], function() { - Router::group(['prefix' => 'services'], function() { + SimpleRouter::group(['prefix' => 'services'], function() { - Router::get('/answers/{id}', 'ControllerAnswers@show'); + SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show'); }); }); @@ -65,9 +67,9 @@ The ```Router``` class is just a simple helper class that knows how to communica ```php use \Pecee\SimpleRouter; -use \Pecee\Router\RouterRoute; +use \Pecee\SimpleRouter\Router; -$router = SimpleRouter::GetInstance(); +$router = Router::getInstance(); $route = new RouterRoute('/answer/1', function() { die('this callback will match /answer/1'); diff --git a/src/Pecee/Router.php b/src/Pecee/SimpleRouter.php similarity index 77% rename from src/Pecee/Router.php rename to src/Pecee/SimpleRouter.php index d3a5c72..3bb702b 100644 --- a/src/Pecee/Router.php +++ b/src/Pecee/SimpleRouter.php @@ -7,23 +7,25 @@ * This class is added so calls can be made staticly like Router::get() making the code look more pretty. */ -namespace Pecee; +namespace Pecee\SimpleRouter; use Pecee\Router\RouterGroup; use Pecee\Router\RouterRoute; -use Pecee\Router\SimpleRouter; +use Pecee\Router\Router; -class Router { +class SimpleRouter { - public static function init() { - SimpleRouter::GetInstance()->routeRequest(); + public static function init($defaultNamespace = null) { + $router = Router::GetInstance(); + $router->setDefaultControllerNamespace($defaultNamespace); + $router->routeRequest(); } public static function get($url, $callback) { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_GET); - $router = SimpleRouter::GetInstance(); + $router = Router::GetInstance(); $router->addRoute($route); return $route; @@ -33,7 +35,7 @@ class Router { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_POST); - $router = SimpleRouter::GetInstance(); + $router = Router::GetInstance(); $router->addRoute($route); return $route; @@ -43,7 +45,7 @@ class Router { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_PUT); - $router = SimpleRouter::GetInstance(); + $router = Router::GetInstance(); $router->addRoute($route); return $route; @@ -53,7 +55,7 @@ class Router { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_DELETE); - $router = SimpleRouter::GetInstance(); + $router = Router::GetInstance(); $router->addRoute($route); return $route; @@ -67,7 +69,7 @@ class Router { $group->setSettings($settings); } - $router = SimpleRouter::GetInstance(); + $router = Router::GetInstance(); $router->addRoute($group); return $group; @@ -79,7 +81,7 @@ class Router { $route->addRequestType($requestType); } - $router = SimpleRouter::GetInstance(); + $router = Router::GetInstance(); $router->addRoute($route); return $route; diff --git a/src/Pecee/Router/SimpleRouter.php b/src/Pecee/SimpleRouter/Router.php similarity index 75% rename from src/Pecee/Router/SimpleRouter.php rename to src/Pecee/SimpleRouter/Router.php index d1481e0..58c6170 100644 --- a/src/Pecee/Router/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/Router.php @@ -1,7 +1,7 @@ routes = array(); @@ -20,6 +21,11 @@ class SimpleRouter { } public function addRoute(RouterEntry $route) { + // Add default namespace + if(!$route->getNamespace() && $this->defaultControllerNamespace !== null) { + $route->setNamespace($this->defaultControllerNamespace); + } + if($this->currentRoute !== null) { $this->backstack[] = $route; } else { @@ -130,7 +136,63 @@ class SimpleRouter { } } - public static function GetInstance() { + /** + * @return string + */ + public function getDefaultControllerNamespace(){ + return $this->defaultControllerNamespace; + } + + /** + * @param string $defaultControllerNamespace + */ + public function setDefaultControllerNamespace($defaultControllerNamespace) { + $this->defaultControllerNamespace = $defaultControllerNamespace; + } + + /** + * @return RouterEntry + */ + public function getLoadedClass() { + return $this->loadedClass; + } + + /** + * @return string + */ + public function getRequestMethod() { + return $this->requestMethod; + } + + /** + * @return string + */ + public function getRequestUri() { + return $this->requestUri; + } + + /** + * @return array + */ + public function getBackstack() { + return $this->backstack; + } + + /** + * @return RouterEntry + */ + public function getCurrentRoute(){ + return $this->currentRoute; + } + + /** + * @return array + */ + public function getRoutes(){ + return $this->routes; + } + + public static function getInstance() { if(self::$instance === null) { self::$instance = new self(); } diff --git a/src/Pecee/Router/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php similarity index 100% rename from src/Pecee/Router/RouterEntry.php rename to src/Pecee/SimpleRouter/RouterEntry.php diff --git a/src/Pecee/Router/RouterException.php b/src/Pecee/SimpleRouter/RouterException.php similarity index 100% rename from src/Pecee/Router/RouterException.php rename to src/Pecee/SimpleRouter/RouterException.php diff --git a/src/Pecee/Router/RouterGroup.php b/src/Pecee/SimpleRouter/RouterGroup.php similarity index 100% rename from src/Pecee/Router/RouterGroup.php rename to src/Pecee/SimpleRouter/RouterGroup.php diff --git a/src/Pecee/Router/RouterRoute.php b/src/Pecee/SimpleRouter/RouterRoute.php similarity index 98% rename from src/Pecee/Router/RouterRoute.php rename to src/Pecee/SimpleRouter/RouterRoute.php index 5766ef5..f9a09f3 100644 --- a/src/Pecee/Router/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -3,7 +3,7 @@ namespace Pecee\Router; use Pecee\Registry; -use Pecee\SimpleRouter; +use Pecee\Router; class RouterRoute extends RouterEntry { From 266ebdf7d7938f2becbe7c83972086724aa92dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 18 Sep 2015 20:31:48 +0200 Subject: [PATCH 07/29] =?UTF-8?q?[TASK]=C2=A0Updated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Pecee/SimpleRouter.php | 8 ++++---- src/Pecee/SimpleRouter/Router.php | 2 +- src/Pecee/SimpleRouter/RouterEntry.php | 2 +- src/Pecee/SimpleRouter/RouterException.php | 2 +- src/Pecee/SimpleRouter/RouterGroup.php | 2 +- src/Pecee/SimpleRouter/RouterRoute.php | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Pecee/SimpleRouter.php b/src/Pecee/SimpleRouter.php index 3bb702b..327d709 100644 --- a/src/Pecee/SimpleRouter.php +++ b/src/Pecee/SimpleRouter.php @@ -7,11 +7,11 @@ * This class is added so calls can be made staticly like Router::get() making the code look more pretty. */ -namespace Pecee\SimpleRouter; +namespace Pecee; -use Pecee\Router\RouterGroup; -use Pecee\Router\RouterRoute; -use Pecee\Router\Router; +use Pecee\SimpleRouter\RouterGroup; +use Pecee\SimpleRouter\RouterRoute; +use Pecee\SimpleRouter\Router; class SimpleRouter { diff --git a/src/Pecee/SimpleRouter/Router.php b/src/Pecee/SimpleRouter/Router.php index 58c6170..eef39c2 100644 --- a/src/Pecee/SimpleRouter/Router.php +++ b/src/Pecee/SimpleRouter/Router.php @@ -1,5 +1,5 @@ Date: Fri, 18 Sep 2015 21:54:24 +0200 Subject: [PATCH 08/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84dc879..c5b1443 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Simple PHP router +# [WIP] Simple PHP router Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router. ## Installation From 61857726dd8ac9899515522ecc78a527b84d895a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sat, 19 Sep 2015 23:21:03 +0200 Subject: [PATCH 09/29] ... ... --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c5b1443..047d555 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ SimpleRouter::init($defaultControllerNamespace); ## Adding routes Remember the ```routes.php``` file you required in your ```index.php```? This file will contain all your custom rules for routing. - This router is heavily inspired by the Laravel 5.* router, so anything you find in the Laravel documentation should work here as well. ### Basic example From 4cc306a2ccad1e17bfd91fb19298878997475e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sun, 20 Sep 2015 12:26:16 +0200 Subject: [PATCH 10/29] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 047d555..5c4496b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # [WIP] Simple PHP router Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router. +**Please note: this project has just been added and is still a work in progress. Please use with caution until a stable release version is available :)** + ## Installation Add the latest version pf Simple PHP Router to your ```composer.json``` @@ -62,7 +64,7 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So ### Doing it the object oriented (hardcore) way -The ```Router``` class is just a simple helper class that knows how to communicate with the ```SimpleRouter``` class. If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you. +The ```SimpleRouter``` class is just a simple helper class that knows how to communicate with the ```Router``` class. If you are up for a challenge, want the full control or simply just want to create your own ```SimpleRouter``` helper class, this example is for you. ```php use \Pecee\SimpleRouter; From 85470bbbd77445d329cf78f4d27b89b0aa71582b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Mon, 21 Sep 2015 19:40:14 +0200 Subject: [PATCH 11/29] [TASK] Updated --- README.md | 83 +++++++++++++++- .../{Router.php => RouterBase.php} | 99 +++++++++++-------- src/Pecee/SimpleRouter/RouterEntry.php | 12 --- src/Pecee/SimpleRouter/RouterRoute.php | 37 ++++++- src/Pecee/{ => SimpleRouter}/SimpleRouter.php | 26 ++--- 5 files changed, 184 insertions(+), 73 deletions(-) rename src/Pecee/SimpleRouter/{Router.php => RouterBase.php} (70%) rename src/Pecee/{ => SimpleRouter}/SimpleRouter.php (78%) diff --git a/README.md b/README.md index 84dc879..a0d974c 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ This router is heavily inspired by the Laravel 5.* router, so anything you find ### Basic example ```php -using \Pecee\SimpleRouter; +use Pecee\SimpleRouter\SimpleRouter; /* * This route will match the url /v1/services/answers/1/ @@ -63,13 +63,14 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So ### Doing it the object oriented (hardcore) way -The ```Router``` class is just a simple helper class that knows how to communicate with the ```SimpleRouter``` class. If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you. +The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```RouterBase``` class. +If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you. ```php -use \Pecee\SimpleRouter; -use \Pecee\SimpleRouter\Router; +use \Pecee\SimpleRouter\RouterBase; +use \Pecee\SimpleRouter\RouterRoute; -$router = Router::getInstance(); +$router = RouterBase::getInstance(); $route = new RouterRoute('/answer/1', function() { die('this callback will match /answer/1'); @@ -83,6 +84,78 @@ $route->setPrefix('v1'); $router->addRoute($route); ``` +This is a simple example of an integration into a framework. + +The framework has it's own ```Router``` class which inherits from the ```SimpleRouter``` class. This allows the framework to add custom functionality. + +```php +namespace MyProject; + +use Pecee\Handler\ExceptionHandler; +use Pecee\SimpleRouter\SimpleRouter; + +class Router extends SimpleRouter { + + protected static $exceptionHandlers = array(); + + public static function start() { + + Debug::getInstance()->add('Router initialised.'); + + // Load routes.php + $file = $_ENV['basePath'] . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'routes.php'; + if(file_exists($file)) { + require_once $file; + } + + // Init locale settings + Locale::getInstance(); + + // Set default namespace + $defaultNamespace = '\\'.Registry::getInstance()->get('AppName') . '\\Controller'; + + // Handle exceptions + try { + parent::start($defaultNamespace); // TODO: Change the autogenerated stub + } catch(\Exception $e) { + /* @var $handler ExceptionHandler */ + foreach(self::$exceptionHandlers as $handler) { + $class = new $handler(); + $class->handleError($e); + } + + throw $e; + } + } + + public static function addExceptionHandler($handler) { + self::$exceptionHandlers[] = $handler; + } + +} +``` + +This is a basic example of a ```helper.php``` for generating urls. + +```php +use Pecee\SimpleRouter\RouterBase; +function url($controller, $parameters = null, $getParams = null) { + RouterBase::getInstance()->getRoute($controller, $parameters, $getParams); +} +``` + +In ```routes.php``` we have added this route: + +```Router::get('/item/{id}', 'myController@show');``` + +In the template we call: + +```url('myController@show', ['id' => 22], ['category' => 'shoes']);``` + +Result url is: + +```/item/22?category=shoes``` + ## Documentation While I work on a better documentation, please refer to the Laravel 5 routing documentation here: diff --git a/src/Pecee/SimpleRouter/Router.php b/src/Pecee/SimpleRouter/RouterBase.php similarity index 70% rename from src/Pecee/SimpleRouter/Router.php rename to src/Pecee/SimpleRouter/RouterBase.php index eef39c2..75e97c3 100644 --- a/src/Pecee/SimpleRouter/Router.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -1,12 +1,15 @@ routes = array(); $this->backstack = array(); + $this->controllerUrlMap = array(); $this->requestUri = rtrim($_SERVER['REQUEST_URI'], '/'); $this->requestMethod = strtolower(isset($_GET['_method']) ? $_GET['_method'] : $_SERVER['REQUEST_METHOD']); } public function addRoute(RouterEntry $route) { - // Add default namespace - if(!$route->getNamespace() && $this->defaultControllerNamespace !== null) { - $route->setNamespace($this->defaultControllerNamespace); - } - if($this->currentRoute !== null) { $this->backstack[] = $route; } else { @@ -33,12 +32,6 @@ class Router { } } - public function route($url, $callback) { - $route = new RouterRoute($url, $callback); - $this->addRoute($route); - return $route; - } - protected function loadClass($name) { if(!class_exists($name)) { throw new RouterException(sprintf('Class %s does not exist', $name)); @@ -55,6 +48,11 @@ class Router { $this->loadClass($route->getMiddleware()); } + // Add default namespace + if(!$route->getNamespace() && $this->defaultControllerNamespace !== null) { + $route->setNamespace($this->defaultControllerNamespace); + } + if(is_object($route->getCallback()) && is_callable($route->getCallback())) { // When the callback is a function @@ -64,6 +62,7 @@ class Router { // When the callback is a method $controller = explode('@', $route->getCallback()); + $class = $route->getNamespace() . '\\' . $controller[0]; $class = $this->loadClass($class); @@ -80,7 +79,7 @@ class Router { } } - protected function renderBackstack(array $routes, &$settings, &$prefixes) { + protected function processRoutes(array $routes, array &$settings = array(), array &$prefixes = array()) { // Loop through each route-request /* @var $route RouterEntry */ foreach($routes as $route) { @@ -90,10 +89,16 @@ class Router { array_push($prefixes, $route->getPrefix()); } - // If the route is a group + $route->setSettings($settings); + if($route instanceof RouterRoute) { - $route->setSettings($settings); - $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); + if(is_array($prefixes) && count($prefixes)) { + $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); + } + + if(stripos($route->getCallback(), '@') !== false) { + $this->controllerUrlMap[$route->getCallback()] = $route; + } } // Stop if the route matches @@ -102,38 +107,20 @@ class Router { $this->renderRoute($route); } - // Remove itself from backstack - array_shift($this->backstack); + if(count($this->backstack)) { + // Remove itself from backstack + array_shift($this->backstack); - // Route any routes added to the backstack - $this->renderBackstack($this->backstack, $settings, $prefixes); + // Route any routes added to the backstack + $this->processRoutes($this->backstack, $settings, $prefixes); + } } } public function routeRequest() { // Loop through each route-request - /* @var $route RouterEntry */ - foreach($this->routes as $route) { - // Reset variables - $settings = array(); - $prefixes = array(); - - $settings = array_merge($settings, $route->getMergeableSettings()); - - if($route->getPrefix()) { - array_push($prefixes, $route->getPrefix()); - } - - // Stop if the route matches - $route = $route->getRoute($this->requestMethod, $this->requestUri); - if($route) { - $this->renderRoute($route); - } - - // Route any routes added to the backstack - $this->renderBackstack($this->backstack, $settings, $prefixes); - } + $this->processRoutes($this->routes); } /** @@ -192,6 +179,36 @@ class Router { return $this->routes; } + public function getRoute($controller, $parameters = null, $getParams = null) { + /* @var $route RouterRoute */ + foreach($this->controllerUrlMap as $c => $route) { + $params = $route->getParameters(); + + if(strtolower($c) === strtolower($controller)) { + + $url = $route->getUrl(); + + $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); + } + + $url .= $p; + + return $url; + } + } + + return '/'; + } + public static function getInstance() { if(self::$instance === null) { self::$instance = new self(); diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 8e45f7b..2aabbbe 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -27,18 +27,6 @@ abstract class RouterEntry { $this->parameters = array(); } - protected function parseParameter($path) { - $parameters = array(); - - preg_match('/{([A-Za-z\-\_]*?)}/is', $path, $parameters); - - if(isset($parameters[1]) && count($parameters[1]) > 0) { - return $parameters[1]; - } - - return null; - } - /** * @param string $callback * @return self; diff --git a/src/Pecee/SimpleRouter/RouterRoute.php b/src/Pecee/SimpleRouter/RouterRoute.php index 25a48fc..9617f47 100644 --- a/src/Pecee/SimpleRouter/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -11,12 +11,36 @@ class RouterRoute extends RouterEntry { public function __construct($url, $callback) { parent::__construct(); - $this->url = $url; - $this->callback = $callback; + $this->setUrl($url); + $this->setCallback($callback); $this->settings['aliases'] = array(); } + protected function parseParameters($url) { + $parameters = array(); + + preg_match_all('/{([A-Za-z\-\_]*?)}/is', $url, $parameters); + + if(isset($parameters[1]) && count($parameters[1]) > 0) { + return $parameters[1]; + } + + return null; + } + + protected function parseParameter($path) { + $parameters = array(); + + preg_match('/{([A-Za-z\-\_]*?)}/is', $path, $parameters); + + if(isset($parameters[1]) && count($parameters[1]) > 0) { + return $parameters[1]; + } + + return null; + } + public function getRoute($requestMethod, &$url) { // Check if request method is allowed @@ -73,6 +97,15 @@ class RouterRoute extends RouterEntry { * @return self */ public function setUrl($url) { + + $parameters = $this->parseParameters($url); + + if($parameters !== null) { + foreach($parameters as $param) { + $this->parameters[$param] = ''; + } + } + $this->url = $url; return $this; } diff --git a/src/Pecee/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php similarity index 78% rename from src/Pecee/SimpleRouter.php rename to src/Pecee/SimpleRouter/SimpleRouter.php index 327d709..f441315 100644 --- a/src/Pecee/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -7,16 +7,12 @@ * This class is added so calls can be made staticly like Router::get() making the code look more pretty. */ -namespace Pecee; - -use Pecee\SimpleRouter\RouterGroup; -use Pecee\SimpleRouter\RouterRoute; -use Pecee\SimpleRouter\Router; +namespace Pecee\SimpleRouter; class SimpleRouter { - public static function init($defaultNamespace = null) { - $router = Router::GetInstance(); + public static function start($defaultNamespace = null) { + $router = RouterBase::GetInstance(); $router->setDefaultControllerNamespace($defaultNamespace); $router->routeRequest(); } @@ -25,7 +21,7 @@ class SimpleRouter { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_GET); - $router = Router::GetInstance(); + $router = RouterBase::getInstance(); $router->addRoute($route); return $route; @@ -35,7 +31,7 @@ class SimpleRouter { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_POST); - $router = Router::GetInstance(); + $router = RouterBase::getInstance(); $router->addRoute($route); return $route; @@ -45,7 +41,7 @@ class SimpleRouter { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_PUT); - $router = Router::GetInstance(); + $router = RouterBase::getInstance(); $router->addRoute($route); return $route; @@ -55,7 +51,7 @@ class SimpleRouter { $route = new RouterRoute($url, $callback); $route->addRequestType(RouterRoute::REQUEST_TYPE_DELETE); - $router = Router::GetInstance(); + $router = RouterBase::getInstance(); $router->addRoute($route); return $route; @@ -69,7 +65,7 @@ class SimpleRouter { $group->setSettings($settings); } - $router = Router::GetInstance(); + $router = RouterBase::getInstance(); $router->addRoute($group); return $group; @@ -81,10 +77,14 @@ class SimpleRouter { $route->addRequestType($requestType); } - $router = Router::GetInstance(); + $router = RouterBase::getInstance(); $router->addRoute($route); return $route; } + public static function ressource($controller, $settings = array()) { + // not yet implemented + } + } \ No newline at end of file From 46af0947e8808c817e43c2a2bc22fa5b27691bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Mon, 21 Sep 2015 19:40:58 +0200 Subject: [PATCH 12/29] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3b0f964..1cd7bb4 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ class Router extends SimpleRouter { } ``` -This is a basic example of a ```helper.php``` for generating urls. +This is a basic example of a helper function for generating urls. ```php use Pecee\SimpleRouter\RouterBase; @@ -149,13 +149,13 @@ In ```routes.php``` we have added this route: ```Router::get('/item/{id}', 'myController@show');``` -In the template we call: +In the template we then call: ```url('myController@show', ['id' => 22], ['category' => 'shoes']);``` Result url is: -```/item/22?category=shoes``` +```/item/22?category=shoes ``` ## Documentation While I work on a better documentation, please refer to the Laravel 5 routing documentation here: From a3c21d89958596c8e517ca0136acb01758c63164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Tue, 22 Sep 2015 11:30:56 +0200 Subject: [PATCH 13/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1cd7bb4..722381a 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ class Router extends SimpleRouter { // Handle exceptions try { - parent::start($defaultNamespace); // TODO: Change the autogenerated stub + parent::start($defaultNamespace); } catch(\Exception $e) { /* @var $handler ExceptionHandler */ foreach(self::$exceptionHandlers as $handler) { From 67c3479a3ea406e31d6f4eea60c6e443a05bc587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Tue, 22 Sep 2015 13:39:17 +0200 Subject: [PATCH 14/29] [FEATURE] - Added RouterController class. - Added Router::controller functionality to SimpleRouter class. - Bugfixes and optimisations. --- src/Pecee/SimpleRouter/RouterBase.php | 37 ++++-- src/Pecee/SimpleRouter/RouterController.php | 126 ++++++++++++++++++++ src/Pecee/SimpleRouter/RouterEntry.php | 25 ---- src/Pecee/SimpleRouter/RouterGroup.php | 26 ++++ src/Pecee/SimpleRouter/RouterRoute.php | 28 +++++ src/Pecee/SimpleRouter/SimpleRouter.php | 16 +++ 6 files changed, 223 insertions(+), 35 deletions(-) create mode 100644 src/Pecee/SimpleRouter/RouterController.php diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index 75e97c3..a1f5d3a 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -20,7 +20,7 @@ class RouterBase { $this->routes = array(); $this->backstack = array(); $this->controllerUrlMap = array(); - $this->requestUri = rtrim($_SERVER['REQUEST_URI'], '/'); + $this->requestUri = $_SERVER['REQUEST_URI']; $this->requestMethod = strtolower(isset($_GET['_method']) ? $_GET['_method'] : $_SERVER['REQUEST_METHOD']); } @@ -48,31 +48,26 @@ class RouterBase { $this->loadClass($route->getMiddleware()); } - // Add default namespace - if(!$route->getNamespace() && $this->defaultControllerNamespace !== null) { - $route->setNamespace($this->defaultControllerNamespace); - } - if(is_object($route->getCallback()) && is_callable($route->getCallback())) { // When the callback is a function - call_user_func_array($route->getCallback(), $route->getParameters()); + 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()); - $class = $route->getNamespace() . '\\' . $controller[0]; + $className = $route->getNamespace() . '\\' . $controller[0]; - $class = $this->loadClass($class); + $class = $this->loadClass($className); $this->loadedClass = $class; $method = $controller[1]; if(!method_exists($class, $method)) { - throw new RouterException(sprintf('Method %s does not exist', $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()); @@ -84,6 +79,18 @@ class RouterBase { /* @var $route RouterEntry */ foreach($routes as $route) { + if($this->defaultControllerNamespace) { + $namespace = null; + + if ($route->getNamespace()) { + $namespace = $this->defaultControllerNamespace . '\\' . $route->getNamespace(); + } else { + $namespace = $this->defaultControllerNamespace; + } + + $route->setNamespace($namespace); + } + $settings = array_merge($settings, $route->getMergeableSettings()); if($route->getPrefix()) { array_push($prefixes, $route->getPrefix()); @@ -101,7 +108,17 @@ class RouterBase { } } + if($route instanceof RouterController) { + + if(is_array($prefixes) && count($prefixes)) { + $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); + } + + $this->controllerUrlMap[$route->getController()] = $route; + } + // Stop if the route matches + $route = $route->getRoute($this->requestMethod, $this->requestUri); if($route) { $this->renderRoute($route); diff --git a/src/Pecee/SimpleRouter/RouterController.php b/src/Pecee/SimpleRouter/RouterController.php new file mode 100644 index 0000000..81736d9 --- /dev/null +++ b/src/Pecee/SimpleRouter/RouterController.php @@ -0,0 +1,126 @@ +url = $url; + $this->controller = $controller; + $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) { + + $url = parse_url($url); + $url = $url['path']; + + if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) !== false) { + + $strippedUrl = trim(str_ireplace($this->url, '/', $url), '/'); + + $path = explode('/', $strippedUrl); + + if(count($path)) { + + $method = (!isset($path[0]) || trim($path[0]) === '') ? self::DEFAULT_METHOD : $path[0]; + + $this->method = $requestMethod . ucfirst($method); + + array_shift($path); + + $this->parameters = $path; + + $this->loadClass(); + } + + } + + } + + /** + * @return string + */ + public function getUrl() { + return $this->url; + } + + /** + * @param string $url + */ + public function setUrl($url) { + $this->url = $url; + } + + /** + * @return array + */ + public function getParameters() { + return $this->parameters; + } + + /** + * @param array $parameters + */ + public function setParameters($parameters) { + $this->parameters = $parameters; + } + + /** + * @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 diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 2aabbbe..6492d99 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -17,13 +17,11 @@ abstract class RouterEntry { ); protected $settings; - protected $requestTypes; protected $callback; protected $parameters; public function __construct() { $this->settings = array(); - $this->requestTypes = array(); $this->parameters = array(); } @@ -43,29 +41,6 @@ abstract class RouterEntry { return $this->callback; } - /** - * 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; - } - /** * @return mixed */ diff --git a/src/Pecee/SimpleRouter/RouterGroup.php b/src/Pecee/SimpleRouter/RouterGroup.php index 018afe2..ed227c3 100644 --- a/src/Pecee/SimpleRouter/RouterGroup.php +++ b/src/Pecee/SimpleRouter/RouterGroup.php @@ -4,8 +4,11 @@ namespace Pecee\SimpleRouter; class RouterGroup extends RouterEntry { + protected $requestTypes; + public function __construct() { parent::__construct(); + $this->requestTypes = array(); } public function getRoute($requestMethod, &$url) { @@ -18,4 +21,27 @@ 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 9617f47..dfd7917 100644 --- a/src/Pecee/SimpleRouter/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -8,6 +8,7 @@ use Pecee\Router; class RouterRoute extends RouterEntry { protected $url; + protected $requestTypes; public function __construct($url, $callback) { parent::__construct(); @@ -15,6 +16,7 @@ class RouterRoute extends RouterEntry { $this->setCallback($callback); $this->settings['aliases'] = array(); + $this->requestTypes = array(); } protected function parseParameters($url) { @@ -46,6 +48,9 @@ class RouterRoute extends RouterEntry { // Check if request method is allowed if(count($this->requestTypes) === 0 || in_array($requestMethod, $this->requestTypes)) { + $url = parse_url($url); + $url = $url['path']; + $url = explode('/', trim($url, '/')); $route = explode('/', trim($this->url, '/')); @@ -133,4 +138,27 @@ class RouterRoute extends RouterEntry { public function getAliases() { $this->aliases; } + + /** + * 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/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index f441315..02f0207 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -83,6 +83,22 @@ class SimpleRouter { return $route; } + public static function all($url, $callback) { + $route = new RouterRoute($url, $callback); + $router = RouterBase::getInstance(); + $router->addRoute($route); + + return $route; + } + + public static function controller($url, $controller) { + $route = new RouterController($url, $controller); + $router = RouterBase::getInstance(); + $router->addRoute($route); + + return $route; + } + public static function ressource($controller, $settings = array()) { // not yet implemented } From 1c765476b54f9f85bf5cd81732e64373d22b7ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Fri, 25 Sep 2015 00:00:29 +0200 Subject: [PATCH 15/29] [BUGFIXES] Bugfixes --- src/Pecee/SimpleRouter/RouterBase.php | 47 +++++++++++-------------- src/Pecee/SimpleRouter/SimpleRouter.php | 2 +- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index a1f5d3a..bb4bfbd 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -14,7 +14,7 @@ class RouterBase { protected $requestUri; protected $requestMethod; protected $loadedClass; - protected $defaultControllerNamespace; + protected $defaultNamespace; public function __construct() { $this->routes = array(); @@ -25,6 +25,15 @@ 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 { @@ -43,7 +52,7 @@ class RouterBase { public function renderRoute(RouterEntry $route) { $this->currentRoute = $route; - // Load middlewares if any + // Load middlewares if($route->getMiddleware()) { $this->loadClass($route->getMiddleware()); } @@ -79,13 +88,13 @@ class RouterBase { /* @var $route RouterEntry */ foreach($routes as $route) { - if($this->defaultControllerNamespace) { + if($this->defaultNamespace) { $namespace = null; if ($route->getNamespace()) { - $namespace = $this->defaultControllerNamespace . '\\' . $route->getNamespace(); + $namespace = $this->defaultNamespace . '\\' . $route->getNamespace(); } else { - $namespace = $this->defaultControllerNamespace; + $namespace = $this->defaultNamespace; } $route->setNamespace($namespace); @@ -98,27 +107,13 @@ class RouterBase { $route->setSettings($settings); - if($route instanceof RouterRoute) { + if($route instanceof RouterRoute || $route instanceof RouterController) { if(is_array($prefixes) && count($prefixes)) { $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); } - - if(stripos($route->getCallback(), '@') !== false) { - $this->controllerUrlMap[$route->getCallback()] = $route; - } - } - - if($route instanceof RouterController) { - - if(is_array($prefixes) && count($prefixes)) { - $route->setUrl( '/' . join('/', $prefixes) . $route->getUrl() ); - } - - $this->controllerUrlMap[$route->getController()] = $route; } // Stop if the route matches - $route = $route->getRoute($this->requestMethod, $this->requestUri); if($route) { $this->renderRoute($route); @@ -143,15 +138,15 @@ class RouterBase { /** * @return string */ - public function getDefaultControllerNamespace(){ - return $this->defaultControllerNamespace; + public function getDefaultNamespace(){ + return $this->defaultNamespace; } /** - * @param string $defaultControllerNamespace + * @param string $defaultNamespace */ - public function setDefaultControllerNamespace($defaultControllerNamespace) { - $this->defaultControllerNamespace = $defaultControllerNamespace; + public function setDefaultNamespace($defaultNamespace) { + $this->defaultNamespace = $defaultNamespace; } /** @@ -201,7 +196,7 @@ class RouterBase { foreach($this->controllerUrlMap as $c => $route) { $params = $route->getParameters(); - if(strtolower($c) === strtolower($controller)) { + if(strtolower($c) === strtolower($controller) || stripos($c, $controller) === 0) { $url = $route->getUrl(); diff --git a/src/Pecee/SimpleRouter/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index 02f0207..62dfcbb 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -13,7 +13,7 @@ class SimpleRouter { public static function start($defaultNamespace = null) { $router = RouterBase::GetInstance(); - $router->setDefaultControllerNamespace($defaultNamespace); + $router->setDefaultNamespace($defaultNamespace); $router->routeRequest(); } From 6354c3c766b10e7f6d6620524e282dc100b65f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Tue, 6 Oct 2015 16:08:42 +0200 Subject: [PATCH 16/29] =?UTF-8?q?[TASK]=C2=A0Bugfixes=20and=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Most routes now works along with getRoute() method. --- src/Pecee/SimpleRouter/RouterBase.php | 179 +++++++++++--------- src/Pecee/SimpleRouter/RouterController.php | 34 +--- src/Pecee/SimpleRouter/RouterEntry.php | 42 ++++- src/Pecee/SimpleRouter/RouterGroup.php | 31 +--- src/Pecee/SimpleRouter/RouterRoute.php | 2 +- src/Pecee/SimpleRouter/SimpleRouter.php | 4 + 6 files changed, 160 insertions(+), 132 deletions(-) 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 From cbe1af0ab934eae9fdc02c1de76911026b75d325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Tue, 6 Oct 2015 19:46:07 +0200 Subject: [PATCH 17/29] [FEATURE] Added ressource controller type --- src/Pecee/SimpleRouter/RouterBase.php | 2 +- src/Pecee/SimpleRouter/RouterController.php | 5 -- src/Pecee/SimpleRouter/RouterEntry.php | 5 +- src/Pecee/SimpleRouter/RouterRessource.php | 91 +++++++++++++++++++++ src/Pecee/SimpleRouter/SimpleRouter.php | 8 +- 5 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 src/Pecee/SimpleRouter/RouterRessource.php diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index b1bc66a..3830137 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -22,7 +22,7 @@ class RouterBase { $this->backstack = array(); $this->controllerUrlMap = array(); $this->requestUri = $_SERVER['REQUEST_URI']; - $this->requestMethod = strtolower(isset($_GET['_method']) ? $_GET['_method'] : $_SERVER['REQUEST_METHOD']); + $this->requestMethod = ($_SERVER['REQUEST_METHOD'] != 'GET') ? 'post' : 'get'; } public function addRoute(RouterEntry $route) { diff --git a/src/Pecee/SimpleRouter/RouterController.php b/src/Pecee/SimpleRouter/RouterController.php index 856cfce..fe1a9f4 100644 --- a/src/Pecee/SimpleRouter/RouterController.php +++ b/src/Pecee/SimpleRouter/RouterController.php @@ -31,11 +31,9 @@ class RouterController extends RouterEntry { if(count($path)) { $method = (!isset($path[0]) || trim($path[0]) === '') ? self::DEFAULT_METHOD : $path[0]; - $this->method = $method; array_shift($path); - $this->parameters = $path; // Set callback @@ -43,11 +41,8 @@ class RouterController extends RouterEntry { return $this; } - } - return null; - } /** diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index cd1e893..6a8d373 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -181,12 +181,9 @@ abstract class RouterEntry { } 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]); + $method = strtolower($requestMethod) . ucfirst($controller[1]); if (!method_exists($class, $method)) { throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404); diff --git a/src/Pecee/SimpleRouter/RouterRessource.php b/src/Pecee/SimpleRouter/RouterRessource.php new file mode 100644 index 0000000..be6797e --- /dev/null +++ b/src/Pecee/SimpleRouter/RouterRessource.php @@ -0,0 +1,91 @@ +url = $url; + $this->controller = $controller; + $this->parameters; + $this->postMethod = strtoupper(isset($_POST['_method']) ? $_POST['_method'] : $_SERVER['REQUEST_METHOD']); + } + + public function renderRoute($requestMethod) { + return parent::renderRoute($requestMethod); + } + + protected function call($method, $parameters) { + $this->setCallback($this->controller . '@' . $method); + $this->parameters = $parameters; + return $this; + } + + public function matchRoute($requestMethod, $url) { + $url = parse_url($url); + $url = $url['path']; + + if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) !== false) { + $url = rtrim($url, '/'); + + $strippedUrl = trim(substr($url, strlen($this->url)), '/'); + $path = explode('/', $strippedUrl); + + $args = $path; + $action = ''; + + if(count($args)) { + $action = $args[0]; + array_shift($args); + } + + if (count($path)) { + + // Delete + if($this->postMethod == 'DELETE' && $requestMethod == self::REQUEST_TYPE_POST) { + return $this->call('destroy', $args); + } + + // Update + if(in_array($this->postMethod, array('PUT', 'PATCH')) && $requestMethod == 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) { + return $this->call('edit', array_merge(array($action), array_slice($args, 1))); + } + + // Create + if(strtolower($action) == 'create' && $this->postMethod == 'GET') { + return $this->call('create', $args); + } + + // Save + if($requestMethod == 'POST') { + return $this->call('store', $args); + } + + // Show + if($action && $requestMethod == 'GET') { + return $this->call('show', array_merge(array($action), $args)); + } + + // Index + return $this->call('index', $args); + + } + } + + return null; + } + +} \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index f30c046..e99671d 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -99,8 +99,12 @@ class SimpleRouter { return $route; } - public static function ressource($controller, $settings = array()) { - // not yet implemented + public static function ressource($url, $controller) { + $route = new RouterRessource($url, $controller); + $router = RouterBase::getInstance(); + $router->addRoute($route); + + return $route; } public function getRoute($controller = null, $parameters = null, $getParams = null) { From 02a874d01c08f2c20fd8fe33ecbe384c798aa6a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Tue, 6 Oct 2015 20:36:24 +0200 Subject: [PATCH 18/29] [TASK] More fixes to the RouterRessource router. --- src/Pecee/SimpleRouter/RouterEntry.php | 2 +- src/Pecee/SimpleRouter/RouterRessource.php | 40 +++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 6a8d373..d91ecb4 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -183,7 +183,7 @@ abstract class RouterEntry { $controller = explode('@', $this->getCallback()); $className = $this->getNamespace() . '\\' . $controller[0]; $class = $this->loadClass($className); - $method = strtolower($requestMethod) . ucfirst($controller[1]); + $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); diff --git a/src/Pecee/SimpleRouter/RouterRessource.php b/src/Pecee/SimpleRouter/RouterRessource.php index be6797e..dc61ad5 100644 --- a/src/Pecee/SimpleRouter/RouterRessource.php +++ b/src/Pecee/SimpleRouter/RouterRessource.php @@ -20,7 +20,32 @@ class RouterRessource extends RouterEntry { } public function renderRoute($requestMethod) { - return parent::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 = strtolower($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; } protected function call($method, $parameters) { @@ -50,38 +75,37 @@ class RouterRessource extends RouterEntry { if (count($path)) { // Delete - if($this->postMethod == 'DELETE' && $requestMethod == self::REQUEST_TYPE_POST) { + if($this->postMethod === 'DELETE' && $requestMethod === 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($this->postMethod, array('PUT', 'PATCH')) && $requestMethod === 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' && $requestMethod === 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' && $this->postMethod === 'GET') { return $this->call('create', $args); } // Save - if($requestMethod == 'POST') { + if($requestMethod === self::REQUEST_TYPE_POST) { return $this->call('store', $args); } // Show - if($action && $requestMethod == 'GET') { + if($action && $requestMethod === self::REQUEST_TYPE_GET) { return $this->call('show', array_merge(array($action), $args)); } // Index return $this->call('index', $args); - } } From 2ff88f9ed4e7e6084fdaa82ea6647b6fe7656ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Wed, 7 Oct 2015 00:14:59 +0200 Subject: [PATCH 19/29] [BUGFIX] Bugfixes --- src/Pecee/SimpleRouter/RouterBase.php | 100 +++++++++++--------- src/Pecee/SimpleRouter/RouterController.php | 18 +--- src/Pecee/SimpleRouter/RouterEntry.php | 16 +++- src/Pecee/SimpleRouter/RouterGroup.php | 17 +++- src/Pecee/SimpleRouter/RouterRessource.php | 62 +++++++++--- 5 files changed, 140 insertions(+), 73 deletions(-) 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 From a1271f1c895c8ba14e1958ef446820d79d75428b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Wed, 7 Oct 2015 13:26:41 +0200 Subject: [PATCH 20/29] [BUGFIX] Fixed router not loading show method --- src/Pecee/SimpleRouter/RouterRessource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pecee/SimpleRouter/RouterRessource.php b/src/Pecee/SimpleRouter/RouterRessource.php index 359617d..5d4d608 100644 --- a/src/Pecee/SimpleRouter/RouterRessource.php +++ b/src/Pecee/SimpleRouter/RouterRessource.php @@ -55,7 +55,7 @@ class RouterRessource extends RouterEntry { $url = parse_url($url); $url = $url['path']; - if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url . '/') === 0) { + if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) { $url = rtrim($url, '/'); $strippedUrl = trim(substr($url, strlen($this->url)), '/'); From 2a97e013905187529181c2dae6938364826a9846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sun, 11 Oct 2015 10:42:13 +0200 Subject: [PATCH 21/29] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 722381a..39c0810 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [WIP] Simple PHP router +# Simple PHP router Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router. **Please note: this project has just been added and is still a work in progress. Please use with caution until a stable release version is available :)** From 3c3dcdf8df0df143b217fdb9646f80a0ad0560a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sun, 11 Oct 2015 10:43:35 +0200 Subject: [PATCH 22/29] =?UTF-8?q?[FEATURE]=C2=A0Added=20getIdentifier=20me?= =?UTF-8?q?thod=20to=20RouterBase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed getter for getLoadedRoute --- src/Pecee/SimpleRouter/RouterBase.php | 7 +++++-- src/Pecee/SimpleRouter/RouterEntry.php | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index 34e97bc..1a85a2d 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -120,8 +120,11 @@ class RouterBase { /** * @return RouterEntry */ - public function getLoadedClass() { - return $this->loadedClass; + public function getLoadedRoute() { + if(!($this->loadedRoute instanceof RouterGroup)) { + return $this->loadedRoute; + } + return null; } /** diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 70cfe7f..79d402f 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -33,6 +33,20 @@ abstract class RouterEntry { 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 + * when using translations etc. + * + * @return string + */ + public function getIdentifier() { + if(strpos($this->callback, '@') !== false) { + return $this->callback; + } + return 'function_' . md5($this->callback); + } + /** * @param string $callback * @return self; From 624df047e72062806a0e4759c278b6a3f11b78e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sun, 11 Oct 2015 10:44:46 +0200 Subject: [PATCH 23/29] Update README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 39c0810..7252bf2 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,17 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So SimpleRouter::group(['prefix' => 'services'], function() { SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show'); + + // Resetful ressource + Router::ressource('/rest', 'ControllerRessource'); + + // Load the entire controller (where url matches method names - getIndex(), postIndex() etc) + Router::controller('/controller', 'ControllerDefault'); + + // Example of providing callback instead of Controller + SimpleRouter::get('/something', function() { + die('Callback example'); + }); }); }); From 8d4e765556baf787bc26fa0685e95f62428d0c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sun, 11 Oct 2015 10:45:46 +0200 Subject: [PATCH 24/29] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7252bf2..e822709 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,10 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show'); // Resetful ressource - Router::ressource('/rest', 'ControllerRessource'); + SimpleRouter::ressource('/rest', 'ControllerRessource'); // Load the entire controller (where url matches method names - getIndex(), postIndex() etc) - Router::controller('/controller', 'ControllerDefault'); + SimpleRouter::controller('/controller', 'ControllerDefault'); // Example of providing callback instead of Controller SimpleRouter::get('/something', function() { @@ -158,7 +158,7 @@ function url($controller, $parameters = null, $getParams = null) { In ```routes.php``` we have added this route: -```Router::get('/item/{id}', 'myController@show');``` +```SimpleRouter::get('/item/{id}', 'myController@show');``` In the template we then call: From 5c81da7b77a1b061ef3c45c18f61d28539ed4c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sun, 11 Oct 2015 11:35:56 +0200 Subject: [PATCH 25/29] [BUGFIX] Bugfixes - Made sure that urls are always presented in the correct order - Ignored RouterGroup in controllerUrlMap --- src/Pecee/SimpleRouter/RouterBase.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Pecee/SimpleRouter/RouterBase.php b/src/Pecee/SimpleRouter/RouterBase.php index 1a85a2d..bbe1ba0 100644 --- a/src/Pecee/SimpleRouter/RouterBase.php +++ b/src/Pecee/SimpleRouter/RouterBase.php @@ -61,11 +61,13 @@ class RouterBase { } $route->addSettings($mergedSettings); - if(!($route instanceof RouterGroup) && is_array($newPrefixes) && count($newPrefixes) && $backstack) { - $route->setUrl( join('/', $newPrefixes) . $route->getUrl() ); - } + if(!($route instanceof RouterGroup)) { + if(is_array($newPrefixes) && count($newPrefixes) && $backstack) { + $route->setUrl( join('/', $newPrefixes) . $route->getUrl() ); + } - $this->controllerUrlMap[] = $route; + $this->controllerUrlMap[] = $route; + } $this->currentRoute = $route; if($route instanceof RouterGroup && is_callable($route->getCallback())) { @@ -88,6 +90,11 @@ class RouterBase { $this->processRoutes($this->routes); + // Make sure the urls is in the right order when comparing + usort($this->controllerUrlMap, function($a, $b) { + return strcmp($b->getUrl(), $a->getUrl()); + }); + foreach($this->controllerUrlMap as $route) { $routeMatch = $route->matchRoute($this->requestMethod, rtrim($this->requestUri, '/') . '/'); From aec1f5f10cc31f5ddc65998d915eee12351c999f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Wed, 14 Oct 2015 13:54:53 +0200 Subject: [PATCH 26/29] =?UTF-8?q?[FEATURE]=C2=A0Features=20and=20optimisat?= =?UTF-8?q?ions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added where method to RouterRoute to support custom regular expression matches on routes. - Moved parameters property to RouterRoute class. - Added IRouteEntry class. --- src/Pecee/SimpleRouter/IRouteEntry.php | 7 ++++ src/Pecee/SimpleRouter/RouterEntry.php | 18 ---------- src/Pecee/SimpleRouter/RouterRoute.php | 48 ++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 src/Pecee/SimpleRouter/IRouteEntry.php diff --git a/src/Pecee/SimpleRouter/IRouteEntry.php b/src/Pecee/SimpleRouter/IRouteEntry.php new file mode 100644 index 0000000..d13e752 --- /dev/null +++ b/src/Pecee/SimpleRouter/IRouteEntry.php @@ -0,0 +1,7 @@ +settings = array(); - $this->parameters = array(); } protected function loadClass($name) { @@ -63,22 +61,6 @@ abstract class RouterEntry { return $this->callback; } - /** - * @return mixed - */ - public function getParameters(){ - return $this->parameters; - } - - /** - * @param mixed $parameters - * @return self - */ - public function setParameters($parameters) { - $this->parameters = $parameters; - return $this; - } - /** * @param string $prefix * @return self diff --git a/src/Pecee/SimpleRouter/RouterRoute.php b/src/Pecee/SimpleRouter/RouterRoute.php index 9498037..3944c25 100644 --- a/src/Pecee/SimpleRouter/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -9,6 +9,8 @@ class RouterRoute extends RouterEntry { protected $url; protected $requestTypes; + protected $parameters; + protected $parametersRegex; public function __construct($url, $callback) { parent::__construct(); @@ -17,6 +19,8 @@ class RouterRoute extends RouterEntry { $this->settings['aliases'] = array(); $this->requestTypes = array(); + $this->parameters = array(); + $this->parametersRegex = array(); } protected function parseParameters($url) { @@ -73,7 +77,21 @@ class RouterRoute extends RouterEntry { // Save parameter if we have one if($parameter) { - $parameters[$parameter] = $url[$i]; + $parameterValue = $url[$i]; + $regex = (isset($this->parametersRegex[$parameter]) ? $this->parametersRegex[$parameter] : null); + + if($regex !== null) { + // Use the regular expression rule provided to filter the value + $matches = array(); + preg_match('/'.$regex.'/is', $url[$i], $matches); + + if(count($matches)) { + $parameterValue = $matches[0]; + } + } + + // Add parameter value + $parameters[$parameter] = $parameterValue; } } @@ -82,7 +100,6 @@ class RouterRoute extends RouterEntry { $this->parameters = $parameters; return $this; } - } } @@ -161,4 +178,31 @@ class RouterRoute extends RouterEntry { public function getRequestTypes() { return $this->requestTypes; } + + /** + * @return mixed + */ + public function getParameters(){ + return $this->parameters; + } + + /** + * @param mixed $parameters + * @return self + */ + public function setParameters($parameters) { + $this->parameters = $parameters; + return $this; + } + + /** + * Add regular expression parameter match + * + * @param array $options + * @return self + */ + public function where(array $options) { + $this->parametersRegex = array_merge($this->parametersRegex, $options); + return $this; + } } \ No newline at end of file From 93d8c26416a181aa6942adaa758b9e0ef47ecabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Wed, 14 Oct 2015 19:55:05 +0200 Subject: [PATCH 27/29] [BUGFIX] Fixed router for controller and ressources not matching /something? --- src/Pecee/SimpleRouter/RouterController.php | 3 +-- src/Pecee/SimpleRouter/RouterRessource.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Pecee/SimpleRouter/RouterController.php b/src/Pecee/SimpleRouter/RouterController.php index 59a7d02..d97c3bd 100644 --- a/src/Pecee/SimpleRouter/RouterController.php +++ b/src/Pecee/SimpleRouter/RouterController.php @@ -16,9 +16,8 @@ class RouterController extends RouterEntry { } public function matchRoute($requestMethod, $url) { - $url = parse_url($url); - $url = $url['path']; + $url = rtrim($url['path'], '/') . '/'; if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) { diff --git a/src/Pecee/SimpleRouter/RouterRessource.php b/src/Pecee/SimpleRouter/RouterRessource.php index 5d4d608..683400c 100644 --- a/src/Pecee/SimpleRouter/RouterRessource.php +++ b/src/Pecee/SimpleRouter/RouterRessource.php @@ -53,7 +53,7 @@ class RouterRessource extends RouterEntry { public function matchRoute($requestMethod, $url) { $url = parse_url($url); - $url = $url['path']; + $url = rtrim($url['path'], '/') . '/'; if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) { $url = rtrim($url, '/'); From b6f0f6899aaa0ea0413400a7736468e8594bb687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Wed, 14 Oct 2015 20:48:17 +0200 Subject: [PATCH 28/29] [TASK] Moved parameter stuff to RouterEntry class. --- src/Pecee/SimpleRouter/RouterEntry.php | 31 ++++++++++++++++++++++++++ src/Pecee/SimpleRouter/RouterRoute.php | 31 -------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Pecee/SimpleRouter/RouterEntry.php b/src/Pecee/SimpleRouter/RouterEntry.php index 1148725..3dffcb5 100644 --- a/src/Pecee/SimpleRouter/RouterEntry.php +++ b/src/Pecee/SimpleRouter/RouterEntry.php @@ -18,9 +18,13 @@ abstract class RouterEntry { protected $settings; protected $callback; + protected $parameters; + protected $parametersRegex; public function __construct() { $this->settings = array(); + $this->parameters = array(); + $this->parametersRegex = array(); } protected function loadClass($name) { @@ -116,6 +120,33 @@ abstract class RouterEntry { return $this->settings; } + /** + * @return mixed + */ + public function getParameters(){ + return $this->parameters; + } + + /** + * @param mixed $parameters + * @return self + */ + public function setParameters($parameters) { + $this->parameters = $parameters; + return $this; + } + + /** + * Add regular expression parameter match + * + * @param array $options + * @return self + */ + public function where(array $options) { + $this->parametersRegex = array_merge($this->parametersRegex, $options); + return $this; + } + /** * Get settings that are allowed to be inherited by child routes. * diff --git a/src/Pecee/SimpleRouter/RouterRoute.php b/src/Pecee/SimpleRouter/RouterRoute.php index 3944c25..580a94c 100644 --- a/src/Pecee/SimpleRouter/RouterRoute.php +++ b/src/Pecee/SimpleRouter/RouterRoute.php @@ -9,8 +9,6 @@ class RouterRoute extends RouterEntry { protected $url; protected $requestTypes; - protected $parameters; - protected $parametersRegex; public function __construct($url, $callback) { parent::__construct(); @@ -19,8 +17,6 @@ class RouterRoute extends RouterEntry { $this->settings['aliases'] = array(); $this->requestTypes = array(); - $this->parameters = array(); - $this->parametersRegex = array(); } protected function parseParameters($url) { @@ -178,31 +174,4 @@ class RouterRoute extends RouterEntry { public function getRequestTypes() { return $this->requestTypes; } - - /** - * @return mixed - */ - public function getParameters(){ - return $this->parameters; - } - - /** - * @param mixed $parameters - * @return self - */ - public function setParameters($parameters) { - $this->parameters = $parameters; - return $this; - } - - /** - * Add regular expression parameter match - * - * @param array $options - * @return self - */ - public function where(array $options) { - $this->parametersRegex = array_merge($this->parametersRegex, $options); - return $this; - } } \ No newline at end of file From 4edf6aaa6e0b711ded0fdf3677353f316429bc28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Sessing=C3=B8?= Date: Sat, 17 Oct 2015 21:53:20 +0200 Subject: [PATCH 29/29] Update README.md --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e822709..3c2d319 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,16 @@ Add the latest version pf Simple PHP Router to your ```composer.json``` } ``` +## Notes + +### Features currently "in-the-works" + +- Global Constraints +- Named Routes +- Sub-Domain Routing +- CSRF Protection +- Optinal/required parameters + ## Initialising the router In your ```index.php``` require your ```routes.php``` and call the ```routeRequest()``` method when all your custom routes has been loaded. This will trigger and do the actual routing of the requests. @@ -56,7 +66,8 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So SimpleRouter::group(['prefix' => 'services'], function() { - SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show'); + SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show') + ->where(['id' => '[0-9]+'); // Resetful ressource SimpleRouter::ressource('/rest', 'ControllerRessource');