Compare commits

...

36 Commits

Author SHA1 Message Date
Simon Sessingø 5c36e9c652 Merge pull request #31 from skipperbent/development
[BUGFIX] Fixed support for urls like /path/{param}/path
2015-11-20 07:18:31 +01:00
Simon Sessingø b930c06683 [BUGFIX] Fixed support for urls like /path/{param}/path 2015-11-20 07:17:49 +01:00
Simon Sessingø 0f8bba7c32 Merge pull request #30 from skipperbent/development
[FEATURE] Added getIsSecure method to Request class.
2015-11-18 19:20:11 +01:00
Simon Sessingø 19dc295199 [FEATURE] Added getIsSecure method to Request class. 2015-11-18 19:19:15 +01:00
Simon Sessingø c93e0f2ce6 Merge pull request #29 from skipperbent/development
[BUGFIX] Group will now always be rendered no matter of what prefix is.
2015-11-17 00:56:28 +01:00
Simon Sessingø 388c027d04 [BUGFIX] Group will now always be rendered no matter of what prefix is. 2015-11-17 00:55:59 +01:00
Simon Sessingø 2c8e65f25b Merge pull request #28 from skipperbent/development
[BUGFIX] Fixed routeMatch in RouterEntry not matching routes with multiple  arguments.
2015-11-14 22:22:00 +01:00
Simon Sessingø eb93584d85 [BUGFIX] Fixed routeMatch in RouterEntry not matching routes with multiple
arguments.
2015-11-14 22:21:11 +01:00
Simon Sessingø bd5d17b6fb Merge pull request #27 from skipperbent/development
[TASK] Removed Pecee folder.
2015-11-02 08:09:43 +01:00
Simon Sessingø 7c0ac390fd [TASK] Undid changes to composer.json 2015-11-02 08:09:13 +01:00
Simon Sessingø 3fc81b6492 [TASK] Readded Pecee folder. 2015-11-02 08:08:49 +01:00
Simon Sessingø b400b86322 [TASK] Removed Pecee folder. 2015-11-02 08:06:49 +01:00
Simon Sessingø 1d338e9aa9 Merge pull request #26 from skipperbent/development
[OPTIMISATION] Fixed Group only loading middleware when initialised.
2015-11-01 10:24:51 +01:00
Simon Sessingø 889ceaa37f [OPTIMISATION] Fixed Group only loading middleware when initialised. 2015-11-01 10:24:05 +01:00
Simon Sessingø 363338c92f Merge pull request #25 from skipperbent/development
Development
2015-11-01 10:14:57 +01:00
Simon Sessingø 3dd9dba029 [FEATURE] All headers in Request class now has lowercased keys. 2015-11-01 10:13:00 +01:00
Simon Sessingø be277f276f [FEATURE] Added support for patch.
- Put now also allow patch request types.
2015-11-01 09:21:47 +01:00
Simon Sessingø f215eaa9cf [BUGFIX] Bugfixes and optimisations
- Fixed support for multiple middlewares using array.
- Fixed match and parameters-match not not being merged when used on group.
2015-11-01 09:11:17 +01:00
Simon Sessingø 933f2370fe Merge pull request #24 from skipperbent/development
Development
2015-11-01 08:29:19 +01:00
Simon Sessingø b3f8910cab [TASK] Removed Middleware class. 2015-11-01 08:28:28 +01:00
Simon Sessingø 8557741083 [FEATURE] Bugfixes and optimisations
- Changed Middleware to interface - as it's easier to inherit and use in
  other frameworks/projects.

- RouterController now loads method based on request-method.

- Changed references to old Middleware abstract class.

- Middleware must now be instance of IMiddleware instead of Middleware
  class.
2015-11-01 08:23:46 +01:00
Simon Sessingø c60d7d81c1 Merge pull request #23 from skipperbent/development
[BUGFIX] Optimised getRoute for custom urls.
2015-11-01 07:49:21 +01:00
Simon Sessingø 637b998f02 [TASK] Made RouterBase use singleton HttpRequest class. 2015-11-01 07:48:29 +01:00
Simon Sessingø aca7d3d503 [FEATURE] Added magic method getters and setters, and made request a
singleton applied configuration can be availible from everywhere.
2015-11-01 07:44:13 +01:00
Simon Sessingø 846c9e6584 [BUGFIX] Optimised getRoute for custom urls. 2015-11-01 07:36:13 +01:00
Simon Sessingø 0df469184c Merge pull request #22 from skipperbent/development
[BUGFIX] Fixed Exceptions due to route null value.
2015-10-30 02:28:40 +01:00
Simon Sessingø 649ed28a91 [BUGFIX] Fixed Exceptions due to route null value. 2015-10-30 02:27:44 +01:00
Simon Sessingø 5cb7086e96 Merge pull request #21 from skipperbent/development
Development
2015-10-28 05:04:45 +01:00
Simon Sessingø a2edc1504c [BUGFIX] Fixed regular expression matching after last release. 2015-10-28 05:04:11 +01:00
Simon Sessingø d31cda8e70 Merge pull request #20 from skipperbent/master
Latest master
2015-10-27 17:49:08 +01:00
Simon Sessingø 921f050a31 Update README.md 2015-10-27 17:48:35 +01:00
Simon Sessingø dcbf59b305 Merge pull request #19 from skipperbent/development
Development
2015-10-27 17:46:10 +01:00
Simon Sessingø bc16388613 [OPTIMISATION] Optimised middleware loading and routes. 2015-10-27 17:35:56 +01:00
Simon Sessingø d3ed3a61b5 [BUGFIX] Middlewares are no longer loaded on invalid routes 2015-10-27 16:42:39 +01:00
Simon Sessingø 969b64650e Merge pull request #18 from skipperbent/development
[OPTIMISATION] Optimised router handling - router will now use the or…
2015-10-27 14:02:57 +01:00
Simon Sessingø c2cf2334e7 [OPTIMISATION] Optimised router handling - router will now use the order provided when loading routes. 2015-10-27 14:01:19 +01:00
12 changed files with 126 additions and 70 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
# Simple PHP router
Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the Laravel router.
## Installation
Add the latest version pf Simple PHP Router to your ```composer.json```
@@ -33,7 +33,7 @@ Add the latest version pf Simple PHP Router to your ```composer.json```
- Global Constraints
- Sub-Domain Routing
- Required parameters
- Optional parameters
## Initialising the router
@@ -5,7 +5,7 @@ use Pecee\CsrfToken;
use Pecee\Exception\TokenMismatchException;
use Pecee\Http\Request;
class BaseCsrfVerifier extends Middleware {
class BaseCsrfVerifier implements IMiddleware {
const POST_KEY = 'csrf-token';
const HEADER_KEY = 'X-CSRF-TOKEN';
@@ -0,0 +1,8 @@
<?php
namespace Pecee\Http\Middleware;
use Pecee\Http\Request;
interface IMiddleware {
public function handle(Request $request);
}
-11
View File
@@ -1,11 +0,0 @@
<?php
namespace Pecee\Http\Middleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
abstract class Middleware
{
abstract function handle(Request $request);
}
+29 -2
View File
@@ -3,16 +3,35 @@ namespace Pecee\Http;
class Request {
protected static $instance;
protected $data;
protected $uri;
protected $host;
protected $method;
protected $headers;
/**
* Return new instance
* @return static
*/
public static function getInstance() {
if(self::$instance === null) {
self::$instance = new static();
}
return self::$instance;
}
public function __construct() {
$this->data = array();
$this->host = $_SERVER['HTTP_HOST'];
$this->uri = $_SERVER['REQUEST_URI'];
$this->method = (isset($_POST['_method'])) ? strtolower($_POST['_method']) : strtolower($_SERVER['REQUEST_METHOD']);
$this->headers = getallheaders();
$this->headers = array_change_key_case(getallheaders(), CASE_LOWER);
}
public function getIsSecure() {
return isset($_SERVER['HTTPS']) ? true : (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] === 443);
}
/**
@@ -90,7 +109,7 @@ class Request {
* @return string|null
*/
public function getHeader($name) {
return (isset($this->headers[$name])) ? $this->headers[$name] : null;
return (isset($this->headers[strtolower($name)])) ? $this->headers[strtolower($name)] : null;
}
/**
@@ -103,4 +122,12 @@ class Request {
return (isset($_REQUEST[$name]) ? $_REQUEST[$name] : $defaultValue);
}
public function __set($name, $value = null) {
$this->data[$name] = $value;
}
public function __get($name) {
return isset($this->data[$name]) ? $this->data[$name] : null;
}
}
+11 -11
View File
@@ -27,7 +27,7 @@ class RouterBase {
$this->routes = array();
$this->backstack = array();
$this->controllerUrlMap = array();
$this->request = new Request();
$this->request = Request::getInstance();
$this->baseCsrfVerifier = new BaseCsrfVerifier();
}
@@ -58,6 +58,7 @@ class RouterBase {
$newPrefixes = $prefixes;
$mergedSettings = array_merge($settings, $route->getMergeableSettings());
if($route->getPrefix()) {
array_push($newPrefixes, rtrim($route->getPrefix(), '/'));
}
@@ -100,14 +101,6 @@ class RouterBase {
// Loop through each route-request
$this->processRoutes($this->routes);
// Make sure the urls is in the right order when comparing
usort($this->controllerUrlMap, function($a, $b) {
if(stripos($b->getUrl(), '{') !== false) {
return $a->getUrl();
}
return strcmp($b->getUrl(), $a->getUrl());
});
$routeNotAllowed = false;
/* @var $route RouterEntry */
@@ -124,6 +117,7 @@ class RouterBase {
$routeNotAllowed = false;
$this->loadedRoute = $routeMatch;
$routeMatch->loadMiddleware($this->request);
$routeMatch->renderRoute($this->request);
break;
}
@@ -260,7 +254,7 @@ class RouterBase {
throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null');
}
if($controller === null && $parameters === null) {
if($controller === null && $parameters === null && $this->loadedRoute !== null) {
return $this->processUrl($this->loadedRoute, null, $getParams);
}
@@ -314,7 +308,13 @@ class RouterBase {
ArrayUtil::append($url, $parameters);
}
return '/' . join('/', $url);
$url = '/' . trim(join('/', $url), '/') . '/';
if(is_array($getParams)) {
$url .= '?' . Url::arrayToParams($getParams);
}
return $url;
}
public static function getInstance() {
@@ -17,6 +17,29 @@ class RouterController extends RouterEntry {
$this->controller = $controller;
}
public function renderRoute(Request $request) {
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 = $request->getMethod() . 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;
}
}
public function matchRoute(Request $request) {
$url = parse_url($request->getUri());
$url = rtrim($url['path'], '/') . '/';
+27 -17
View File
@@ -2,7 +2,7 @@
namespace Pecee\SimpleRouter;
use Pecee\Http\Middleware\Middleware;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
abstract class RouterEntry {
@@ -10,26 +10,26 @@ abstract class RouterEntry {
const REQUEST_TYPE_POST = 'post';
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_PUT = 'put';
const REQUEST_TYPE_PATCH = 'patch';
const REQUEST_TYPE_DELETE = 'delete';
public static $allowedRequestTypes = array(
self::REQUEST_TYPE_DELETE,
self::REQUEST_TYPE_GET,
self::REQUEST_TYPE_POST,
self::REQUEST_TYPE_PUT
self::REQUEST_TYPE_PUT,
self::REQUEST_TYPE_PATCH
);
protected $settings;
protected $callback;
protected $parameters;
protected $parametersRegex;
protected $regexMatch;
public function __construct() {
$this->settings = array();
$this->settings['requestMethods'] = array();
$this->settings['parametersRegex'] = array();
$this->parameters = array();
$this->parametersRegex = array();
}
/**
@@ -179,9 +179,9 @@ abstract class RouterEntry {
public function getMergeableSettings() {
$settings = $this->settings;
if(isset($settings['middleware'])) {
/*if(isset($settings['middleware'])) {
unset($settings['middleware']);
}
}*/
if(isset($settings['prefix'])) {
unset($settings['prefix']);
@@ -208,7 +208,7 @@ abstract class RouterEntry {
public function setSettings($settings) {
$this->settings = $settings;
if($settings['prefix']) {
if(isset($settings['prefix'])) {
$this->setPrefix($settings['prefix']);
}
@@ -243,21 +243,31 @@ abstract class RouterEntry {
return new $name();
}
protected function loadMiddleware(Request $request) {
public function loadMiddleware(Request $request) {
if($this->getMiddleware()) {
$middleware = $this->loadClass($this->getMiddleware());
if (!($middleware instanceof Middleware)) {
throw new RouterException($this->getMiddleware() . ' must be instance of Middleware');
}
if(is_array($this->getMiddleware())) {
foreach($this->getMiddleware() as $middleware) {
$middleware = $this->loadClass($middleware);
if (!($middleware instanceof IMiddleware)) {
throw new RouterException($middleware . ' must be instance of Middleware');
}
/* @var $class Middleware */
$middleware->handle($request);
/* @var $class Middleware */
$middleware->handle($request);
}
} else {
$middleware = $this->loadClass($this->getMiddleware());
if (!($middleware instanceof IMiddleware)) {
throw new RouterException($this->getMiddleware() . ' must be instance of Middleware');
}
/* @var $class Middleware */
$middleware->handle($request);
}
}
}
public function renderRoute(Request $request) {
// Load middleware
$this->loadMiddleware($request);
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
+15 -18
View File
@@ -10,29 +10,26 @@ class RouterGroup extends RouterEntry {
parent::__construct();
}
public function matchRoute(Request $request) {
public function renderRoute(Request $request) {
// Check if request method is allowed
$hasAccess = (!$this->method);
if(strtolower($request->getUri()) == strtolower($this->prefix) || stripos($request->getUri(), $this->prefix) === 0) {
$hasAccess = (!$this->method);
if($this->method) {
if(is_array($this->method)) {
$hasAccess = (in_array($request->getMethod(), $this->getRequestMethods()));
} else {
$hasAccess = strtolower($this->getRequestMethods()) == strtolower($request->getMethod());
}
if($this->method) {
if(is_array($this->method)) {
$hasAccess = (in_array($request->getMethod(), $this->getRequestMethods()));
} else {
$hasAccess = strtolower($this->getRequestMethods()) == strtolower($request->getMethod());
}
if(!$hasAccess) {
throw new RouterException('Method not allowed');
}
return $this;
}
// No match here, move on...
if(!$hasAccess) {
throw new RouterException('Method not allowed');
}
return parent::renderRoute($request);
}
public function matchRoute(Request $request) {
return null;
}
@@ -20,9 +20,6 @@ class RouterResource extends RouterEntry {
}
public function renderRoute(Request $request) {
// Load middleware
$this->loadMiddleware($request);
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
// When the callback is a function
call_user_func_array($this->getCallback(), $this->getParameters());
+9 -4
View File
@@ -42,12 +42,15 @@ class RouterRoute extends RouterEntry {
$url = parse_url($request->getUri());
$url = $url['path'];
$route = $this->url;
$route = rtrim($this->url, '/') . '/';
$routeMatch = preg_replace('/'.self::PARAMETERS_REGEX_MATCH.'/is', '', $route);
$routeMatch = preg_replace('/\/{0,1}'.self::PARAMETERS_REGEX_MATCH.'\/{0,1}/is', '', $route);
$tmp = explode('/', $route);
$tmp2 = explode('/', $url);
// Check if url parameter count matches
if(stripos($url, $routeMatch) === 0) {
if(stripos($url, $routeMatch) === 0 || count($tmp) === count($tmp2)) {
$matches = true;
@@ -61,8 +64,10 @@ class RouterRoute extends RouterEntry {
} else {
$matches = (count(explode('/', rtrim($url, '/'))) == count(explode('/', rtrim($route, '/'))));
$url = explode('/', $url);
$route = explode('/', $route);
$route = explode('/', rtrim($route, '/'));
$parameters = array();
+1 -1
View File
@@ -57,7 +57,7 @@ class SimpleRouter {
public static function put($url, $callback, array $settings = null) {
$route = new RouterRoute($url, $callback);
$route->addSettings($settings);
$route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_PUT));
$route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_PUT, RouterRoute::REQUEST_TYPE_PATCH));
$router = RouterBase::getInstance();
$router->addRoute($route);