diff --git a/README.md b/README.md index d09578f..0aeb668 100644 --- a/README.md +++ b/README.md @@ -422,7 +422,7 @@ Route groups allow you to share route attributes, such as middleware or namespac To assign middleware to all routes within a group, you may use the middleware key in the group attribute array. Middleware are executed in the order they are listed in the array: ```php -SimpleRouter::group(['middleware' => '\Demo\Middleware\Auth'], function () { +SimpleRouter::group(['middleware' => \Demo\Middleware\Auth::class], function () { SimpleRouter::get('/', function () { // Uses Auth Middleware }); @@ -437,6 +437,11 @@ SimpleRouter::group(['middleware' => '\Demo\Middleware\Auth'], function () { Another common use-case for route groups is assigning the same PHP namespace to a group of controllers using the `namespace` parameter in the group array: +#### Note +Group namespaces will only be added to routes with relative callbacks. +For example if your route has an absolute callback like `\Demo\Controller\DefaultController@home`, the namespace from the route will not be prepended. +To fix this you can make the callback relative by removing the `\` in the beginning of the callback. + ```php SimpleRouter::group(['namespace' => 'Admin'], function () { // Controllers Within The "App\Http\Controllers\Admin" Namespace @@ -495,7 +500,7 @@ use Pecee\SimpleRouter\SimpleRouter; /* Adding custom csrfVerifier here */ SimpleRouter::csrfVerifier(new \Demo\Middlewares\CsrfVerifier()); -SimpleRouter::group(['middleware' => '\Demo\Middlewares\Site', 'exceptionHandler' => 'Handlers\CustomExceptionHandler'], function() { +SimpleRouter::group(['middleware' => \Demo\Middlewares\Site::class, 'exceptionHandler' => \Demo\Handlers\CustomExceptionHandler::class], function() { SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' => ['id' => '[0-9]+']]); @@ -505,7 +510,7 @@ SimpleRouter::group(['middleware' => '\Demo\Middlewares\Site', 'exceptionHandler * Restful resource (see IRestController interface for available methods) */ - SimpleRouter::resource('/rest', 'ControllerRessource'); + SimpleRouter::resource('/rest', ControllerRessource::class); /** @@ -521,7 +526,7 @@ SimpleRouter::group(['middleware' => '\Demo\Middlewares\Site', 'exceptionHandler * etc. */ - SimpleRouter::controller('/animals', 'ControllerAnimals'); + SimpleRouter::controller('/animals', ControllerAnimals::class); }); @@ -678,7 +683,7 @@ url('product', null, ['category' => 'shoes']); ### Get by name (controller route) ```php -SimpleRouter::controller('/images', 'ImagesController', ['as' => 'picture']); +SimpleRouter::controller('/images', ImagesController::class, ['as' => 'picture']); url('picture@getView', null, ['category' => 'shoes']); url('picture', 'getView', ['category' => 'shoes']); @@ -707,7 +712,7 @@ url('ImagesController@getImage', null, ['id' => 22]); ### Using custom names for methods on a controller/resource route ```php -SimpleRouter::controller('gadgets', 'GadgetsController', ['names' => ['getIphoneInfo' => 'iphone']]); +SimpleRouter::controller('gadgets', GadgetsController::class, ['names' => ['getIphoneInfo' => 'iphone']]); url('gadgets.iphone'); @@ -718,7 +723,7 @@ url('gadgets.iphone'); ### Getting REST/resource controller urls ```php -SimpleRouter::resource('/phones', 'PhonesController'); +SimpleRouter::resource('/phones', PhonesController::class); url('phones'); url('phones.index'); @@ -1045,8 +1050,8 @@ If you are up for a challenge, want the full control or simply just want to crea use \Pecee\SimpleRouter\Router; use \Pecee\SimpleRouter\Route\RouteUrl; -/* Grap the router instance */ -$router = Router::getInstance(); +/* Create new Router instance */ +$router = new Router(); $route = new RouteUrl('/answer/1', function() { @@ -1054,7 +1059,7 @@ $route = new RouteUrl('/answer/1', function() { }); -$route->setMiddleware('\Demo\Middlewares\AuthMiddleware'); +$route->setMiddleware(\Demo\Middlewares\AuthMiddleware::class); $route->setNamespace('\Demo\Controllers'); $route->setPrefix('v1'); diff --git a/composer.json b/composer.json index 7468967..3412fd4 100644 --- a/composer.json +++ b/composer.json @@ -1,26 +1,32 @@ { - "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": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "4.7.7" - }, - "autoload": { - "psr-4": { - "Pecee\\": "src/Pecee/" - } + "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", + "route" + ], + "license": "MIT", + "support": { + "source": "https://github.com/skipperbent/simple-php-router/issues" + }, + "authors": [ + { + "name": "Simon Sessingø", + "email": "simon.sessingoe@gmail.com" } + ], + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "4.7.7" + }, + "autoload": { + "psr-4": { + "Pecee\\": "src/Pecee/" + } + } } \ No newline at end of file diff --git a/src/Pecee/Http/Input/IInputItem.php b/src/Pecee/Http/Input/IInputItem.php index c35f2ec..5a56f84 100644 --- a/src/Pecee/Http/Input/IInputItem.php +++ b/src/Pecee/Http/Input/IInputItem.php @@ -12,6 +12,8 @@ interface IInputItem public function setName($name); + public function getValue(); + public function __toString(); } \ No newline at end of file diff --git a/src/Pecee/Http/Input/InputFile.php b/src/Pecee/Http/Input/InputFile.php index 7ad4744..ac78ecf 100644 --- a/src/Pecee/Http/Input/InputFile.php +++ b/src/Pecee/Http/Input/InputFile.php @@ -43,8 +43,8 @@ class InputFile implements IInputItem ], $values); return (new static($values['index'])) - ->setError($values['error']) ->setSize($values['size']) + ->setError($values['error']) ->setType($values['type']) ->setTmpName($values['tmp_name']) ->setFilename($values['name']); @@ -199,7 +199,7 @@ class InputFile implements IInputItem } /** - * Return true if an upload error occured. + * Return true if an upload error occurred. * * @return bool */ @@ -256,6 +256,11 @@ class InputFile implements IInputItem return $this->getTmpName(); } + public function getValue() + { + return $this->getFilename(); + } + public function toArray() { return [ diff --git a/src/Pecee/Http/Request.php b/src/Pecee/Http/Request.php index bac9d76..371e0af 100644 --- a/src/Pecee/Http/Request.php +++ b/src/Pecee/Http/Request.php @@ -125,6 +125,17 @@ class Request return $this->getHeader('remote-addr'); } + /** + * Get remote address/ip + * + * @alias static::getIp + * @return string + */ + public function getRemoteAddr() + { + return $this->getIp(); + } + /** * Get referer * @return string @@ -240,7 +251,7 @@ class Request $callback = $route->getCallback(); /* Only add default namespace on relative callbacks */ - if($callback === null || $callback[0] !== '\\') { + if ($callback === null || $callback[0] !== '\\') { $namespace = SimpleRouter::getDefaultNamespace(); diff --git a/src/Pecee/SimpleRouter/Route/LoadableRoute.php b/src/Pecee/SimpleRouter/Route/LoadableRoute.php index c40e704..ec4676f 100644 --- a/src/Pecee/SimpleRouter/Route/LoadableRoute.php +++ b/src/Pecee/SimpleRouter/Route/LoadableRoute.php @@ -81,7 +81,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute $regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]); - if (preg_match_all('/' . $regex . '/is', $this->url, $matches)) { + if (preg_match_all('/' . $regex . '/', $this->url, $matches)) { $this->parameters = array_fill_keys($matches[1], null); } } @@ -145,8 +145,6 @@ abstract class LoadableRoute extends Route implements ILoadableRoute $url .= join('/', $unknownParams); - - return rtrim($url, '/') . '/'; } diff --git a/src/Pecee/SimpleRouter/Route/Route.php b/src/Pecee/SimpleRouter/Route/Route.php index e756acf..c54637d 100644 --- a/src/Pecee/SimpleRouter/Route/Route.php +++ b/src/Pecee/SimpleRouter/Route/Route.php @@ -71,7 +71,7 @@ abstract class Route implements IRoute $namespace = $this->getNamespace(); - $className = ($namespace !== null) ? $namespace . '\\' . $controller[0] : $controller[0]; + $className = ($namespace !== null && $controller[0][0] !== '\\') ? $namespace . '\\' . $controller[0] : $controller[0]; $class = $this->loadClass($className); $method = $controller[1]; @@ -98,15 +98,17 @@ abstract class Route implements IRoute { $regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]); - if (preg_match_all('/' . $regex . '/is', $route, $parameters)) { + $parameters = []; - $urlParts = preg_split('/((\-?\/?)\{[^}]+\})/is', rtrim($route, '/')); + if (preg_match_all('/' . $regex . '/', $route, $parameters)) { + + $urlParts = preg_split('/((\-?\/?)\{[^}]+\})/', rtrim($route, '/')); foreach ($urlParts as $key => $t) { $regex = ''; - if ($key < (count($parameters[1]))) { + if ($key < count($parameters[1])) { $name = $parameters[1][$key]; $regex = isset($this->where[$name]) ? $this->where[$name] : $parameterRegex; @@ -123,13 +125,16 @@ abstract class Route implements IRoute $urlRegex = preg_quote($route, '/'); } - if (preg_match('/^' . $urlRegex . '(\/?)$/is', $url, $matches) > 0) { + if (preg_match('/^' . $urlRegex . '(\/?)$/', $url, $matches) > 0) { $values = []; - /* Only take matched parameters with name */ - foreach ($parameters[1] as $name) { - $values[$name] = (isset($matches[$name]) && $matches[$name] !== '') ? $matches[$name] : null; + if (isset($parameters[1])) { + + /* Only take matched parameters with name */ + foreach ($parameters[1] as $name) { + $values[$name] = (isset($matches[$name]) && $matches[$name] !== '') ? $matches[$name] : null; + } } return $values; diff --git a/src/Pecee/SimpleRouter/Route/RouteController.php b/src/Pecee/SimpleRouter/Route/RouteController.php index 13adfa6..58c1a63 100644 --- a/src/Pecee/SimpleRouter/Route/RouteController.php +++ b/src/Pecee/SimpleRouter/Route/RouteController.php @@ -89,28 +89,26 @@ class RouteController extends LoadableRoute implements IControllerRoute $url = rtrim($url, '/') . '/'; /* Match global regular-expression for route */ - if ($this->matchRegex($request, $url) === true) { - return true; + $regexMatch = $this->matchRegex($request, $url); + + if ($regexMatch === false || stripos($url, $this->url) !== 0 || strtolower($url) !== strtolower($this->url)) { + return false; } - if (stripos($url, $this->url) === 0 && strtolower($url) === strtolower($this->url)) { + $strippedUrl = trim(str_ireplace($this->url, '/', $url), '/'); + $path = explode('/', $strippedUrl); - $strippedUrl = trim(str_ireplace($this->url, '/', $url), '/'); + if (count($path) > 0) { - $path = explode('/', $strippedUrl); + $method = (isset($path[0]) === false || trim($path[0]) === '') ? $this->defaultMethod : $path[0]; + $this->method = $request->getMethod() . ucfirst($method); - if (count($path) > 0) { + $this->parameters = array_slice($path, 1); - $method = (!isset($path[0]) || trim($path[0]) === '') ? $this->defaultMethod : $path[0]; - $this->method = $method; + // Set callback + $this->setCallback($this->controller . '@' . $this->method); - $this->parameters = array_slice($path, 1); - - // Set callback - $this->setCallback($this->controller . '@' . $this->method); - - return true; - } + return true; } return false; diff --git a/src/Pecee/SimpleRouter/Route/RouteResource.php b/src/Pecee/SimpleRouter/Route/RouteResource.php index 461c6dc..8d6e27a 100644 --- a/src/Pecee/SimpleRouter/Route/RouteResource.php +++ b/src/Pecee/SimpleRouter/Route/RouteResource.php @@ -82,9 +82,10 @@ class RouteResource extends LoadableRoute implements IControllerRoute $url = rtrim($url, '/') . '/'; /* Match global regular-expression for route */ - $domainMatch = $this->matchRegex($request, $url); - if ($domainMatch !== null) { - return $domainMatch; + $regexMatch = $this->matchRegex($request, $url); + + if ($regexMatch === false || stripos($url, $this->url) !== 0 || strtolower($url) !== strtolower($this->url)) { + return false; } $route = rtrim($this->url, '/') . '/{id?}/{action?}'; diff --git a/src/Pecee/SimpleRouter/Route/RouteUrl.php b/src/Pecee/SimpleRouter/Route/RouteUrl.php index 4243c04..b71b482 100644 --- a/src/Pecee/SimpleRouter/Route/RouteUrl.php +++ b/src/Pecee/SimpleRouter/Route/RouteUrl.php @@ -17,9 +17,9 @@ class RouteUrl extends LoadableRoute $url = rtrim($url, '/') . '/'; /* Match global regular-expression for route */ - $domainMatch = $this->matchRegex($request, $url); - if ($domainMatch !== null) { - return $domainMatch; + $regexMatch = $this->matchRegex($request, $url); + if ($regexMatch === false) { + return false; } /* Make regular expression based on route */ @@ -31,7 +31,6 @@ class RouteUrl extends LoadableRoute $this->setParameters($parameters); return true; - } } \ No newline at end of file diff --git a/src/Pecee/SimpleRouter/Router.php b/src/Pecee/SimpleRouter/Router.php index ec1d818..808e376 100644 --- a/src/Pecee/SimpleRouter/Router.php +++ b/src/Pecee/SimpleRouter/Router.php @@ -69,20 +69,7 @@ class Router */ protected $exceptionHandlers; - /** - * Get current router instance - * @return static - */ - public static function getInstance() - { - if (static::$instance === null) { - static::$instance = new static(); - } - - return static::$instance; - } - - protected function __construct() + public function __construct() { $this->reset(); } @@ -187,7 +174,7 @@ class Router if (count($this->routeStack) > 0) { - /* Pop and grap the routes added when executing group callback earlier */ + /* Pop and grab the routes added when executing group callback earlier */ $stack = $this->routeStack; $this->routeStack = []; @@ -199,6 +186,29 @@ class Router $this->exceptionHandlers = array_unique(array_merge($exceptionHandlers, $this->exceptionHandlers)); } + /** + * Load routes + * @throws NotFoundHttpException + * @return void + */ + public function loadRoutes() + { + /* Initialize boot-managers */ + if (count($this->bootManagers) > 0) { + + $max = count($this->bootManagers) - 1; + + /* @var $manager IRouterBootManager */ + for ($i = $max; $i >= 0; $i--) { + $manager = $this->bootManagers[$i]; + $manager->boot($this->request); + } + } + + /* Loop through each route-request */ + $this->processRoutes($this->routes); + } + public function routeRequest($rewrite = false) { $routeNotAllowed = false; @@ -206,21 +216,7 @@ class Router try { if ($rewrite === false) { - - /* Initialize boot-managers */ - if (count($this->bootManagers) > 0) { - - $max = count($this->bootManagers) - 1; - - /* @var $manager IRouterBootManager */ - for ($i = $max; $i >= 0; $i--) { - $manager = $this->bootManagers[$i]; - $manager->boot($this->request); - } - } - - /* Loop through each route-request */ - $this->processRoutes($this->routes); + $this->loadRoutes(); if ($this->csrfVerifier !== null) { diff --git a/src/Pecee/SimpleRouter/SimpleRouter.php b/src/Pecee/SimpleRouter/SimpleRouter.php index 213ee97..dd4de09 100644 --- a/src/Pecee/SimpleRouter/SimpleRouter.php +++ b/src/Pecee/SimpleRouter/SimpleRouter.php @@ -33,6 +33,8 @@ class SimpleRouter */ protected static $response; + protected static $router; + /** * Start/route request * @@ -349,7 +351,11 @@ class SimpleRouter */ public static function router() { - return Router::getInstance(); + if(static::$router === null) { + static::$router = new Router(); + } + + return static::$router; } /** @@ -365,7 +371,7 @@ class SimpleRouter $callback = $route->getCallback(); /* Only add default namespace on relative callbacks */ - if($callback === null || $callback[0] !== '\\') { + if ($callback === null || $callback[0] !== '\\') { $namespace = static::$defaultNamespace;