Development

- Fixed updatae causing middlewares to sometimes load on wrong routes.
- Converted project to PSR/2.
- Updated InputCollection class and added get method for easy access to values.
- Complete refactor of RouterBase.
- Added findRoute method to RouterBase.
- It's now possible to change parameter modifiers and symbol by overwriting properties on RouterBase.
- Added RouterUrlTest unit-test for testing route-urls.
- Added IRestController that can be easily implemented in custom ResourceController-classes.
- It's now possible to use "-" instead of "_" when using getHeader method in Request class.
- Added PHPDocs.
- Fixed "/" route sometimes returning "//" as url.
- Optimisations and bugfixes.
This commit is contained in:
Simon Sessingø
2016-11-19 02:48:19 +01:00
parent a4447313f6
commit ed1ac74e7a
41 changed files with 2813 additions and 2318 deletions
+13 -9
View File
@@ -29,8 +29,8 @@ The goal of this project is to create a router that is 100% compatible with the
- CSRF protection. - CSRF protection.
- Optional parameters - Optional parameters
- Sub-domain routing - Sub-domain routing
- Custom boot managers to redirect urls to other routes - Custom boot managers to rewrite urls to "nicer" ones.
- Input manager; to manage `GET`, `POST` params. - Input manager; easily manage `GET`, `POST` and `FILE` values.
## Installation and demo ## Installation and demo
@@ -71,6 +71,7 @@ This router is heavily inspired by the Laravel 5.* router, so anything you find
- ExceptionsHandlers must implement the `IExceptionHandler` interface. - ExceptionsHandlers must implement the `IExceptionHandler` interface.
- Middlewares must implement the `IMiddleware` interface. - Middlewares must implement the `IMiddleware` interface.
- Resource controllers can inherit the `IRestController` interface, but is not required.
```php ```php
use Pecee\SimpleRouter\SimpleRouter; use Pecee\SimpleRouter\SimpleRouter;
@@ -103,7 +104,7 @@ SimpleRouter::group(['prefix' => '/v1', 'middleware' => '\MyWebsite\Middleware\S
*/ */
SimpleRouter::all('/ajax', 'ControllerAjax@process')->match('.*?\\/ajax\\/([A-Za-z0-9\\/]+)'); SimpleRouter::all('/ajax', 'ControllerAjax@process')->match('.*?\\/ajax\\/([A-Za-z0-9\\/]+)');
// Restful resource // Restful resource (see IRestController interface for available methods)
SimpleRouter::resource('/rest', 'ControllerRessource'); SimpleRouter::resource('/rest', 'ControllerRessource');
// Load the entire controller (where url matches method names - getIndex(), postIndex() etc) // Load the entire controller (where url matches method names - getIndex(), postIndex() etc)
@@ -146,11 +147,10 @@ class CustomExceptionHandler implements IExceptionHandler {
// Output error as json if on api path. // Output error as json if on api path.
if(stripos($request->getUri(), '/api') !== false) { if(stripos($request->getUri(), '/api') !== false) {
response()->json(['error' => $error->getMessage()]); response()->json([ 'error' => $error->getMessage() ]);
} }
// Otherwise default exception will be thrown by the router. // Otherwise default exception will be thrown by the router.
} }
} }
@@ -210,7 +210,7 @@ class Router extends SimpleRouter {
require_once 'routes.php'; require_once 'routes.php';
// change default namespace for all routes // change default namespace for all routes
parent::setDefaultNamespace('\Demo\Controllers'); parent::setDefaultNamespace('\Demo');
// Do initial stuff // Do initial stuff
parent::start(); parent::start();
@@ -449,6 +449,12 @@ $object = input()->getObject('name');
$object = input()->get->name; $object = input()->get->name;
$object = input()->post->name; $object = input()->post->name;
$object = input()->file->name; $object = input()->file->name;
// -- or --
$object = input()->get->get($key, $defaultValue);
$object = input()->post->get($key, $defaultValue);
$object = input()->file->get($key, $defaultValue);
``` ```
**Return all parameters:** **Return all parameters:**
@@ -464,6 +470,7 @@ $values = input()->all([
``` ```
All object inherits from `InputItem` class and will always contain these methods: All object inherits from `InputItem` class and will always contain these methods:
- `getValue()` - returns the value of the input. - `getValue()` - returns the value of the input.
- `getIndex()` - returns the index/key of the input. - `getIndex()` - returns the index/key of the input.
- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc). - `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).
@@ -476,9 +483,6 @@ All object inherits from `InputItem` class and will always contain these methods
- `getType()` - get mime-type for file. - `getType()` - get mime-type for file.
- `getError()` - get file upload error. - `getError()` - get file upload error.
### Easy access to methods
Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation. Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation.
```php ```php
+10 -14
View File
@@ -1,20 +1,16 @@
<?php <?php
namespace Demo\Controllers; namespace Demo\Controllers;
use Pecee\SimpleRouter\SimpleRouter; class ApiController
{
public function index()
{
// The variable authenticated is set to true in the ApiVerification middleware class.
header('content-type: application/json');
class ApiController { echo json_encode([
'authenticated' => request()->authenticated
public function index() { ]);
}
// The variable authenticated is set to true in the ApiVerification middleware class.
header('content-type: application/json');
echo json_encode([
'authenticated' => request()->authenticated
]);
}
} }
@@ -1,29 +1,27 @@
<?php <?php
namespace Demo\Controllers; namespace Demo\Controllers;
class DefaultController { class DefaultController
{
public function index()
{
// implement
echo sprintf('DefaultController -> index (?fun=%s)', input()->get('fun'));
}
public function index() { public function contact()
{
echo 'DefaultController -> contact';
}
// implement public function companies($id = null)
echo sprintf('DefaultController -> index (?fun=%s)', input()->get('fun')); {
echo 'DefaultController -> companies -> id: ' . $id;
}
} public function notFound()
{
public function contact() { echo 'Page not found';
}
echo 'DefaultController -> contact';
}
public function companies($id = null) {
echo 'DefaultController -> companies -> id: ' . $id;
}
public function notFound() {
echo 'Page not found';
}
} }
@@ -5,30 +5,30 @@ use Pecee\Handler\IExceptionHandler;
use Pecee\Http\Request; use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry; use Pecee\SimpleRouter\RouterEntry;
class CustomExceptionHandler implements IExceptionHandler { class CustomExceptionHandler implements IExceptionHandler
{
public function handleError(Request $request, RouterEntry &$route = null, \Exception $error)
{
// Return json errors if we encounter an error on /api.
if (stripos($request->getUri(), '/api') !== false) {
header('content-type: application/json');
echo json_encode([
'error' => $error->getMessage(),
'code' => $error->getCode()
]);
die();
}
public function handleError( Request $request, RouterEntry &$route = null, \Exception $error) { // else we just throw the error
if ($error->getCode() == 404) {
// Return json errors if we encounter an error on /api. // Return 404 path
if(stripos($request->getUri(), '/api') !== false) { $request->setUri('/404');
header('content-type: application/json'); return $request;
echo json_encode([
'error' => $error->getMessage(),
'code' => $error->getCode()
]);
die();
}
// else we just throw the error }
if($error->getCode() == 404) {
// Return 404 path throw $error;
$request->setUri('/404'); }
return $request;
}
throw $error;
}
} }
@@ -5,15 +5,14 @@ use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request; use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry; use Pecee\SimpleRouter\RouterEntry;
class ApiVerification implements IMiddleware { class ApiVerification implements IMiddleware
{
public function handle(Request $request, RouterEntry &$route)
{
// Do authentication
$request->authenticated = true;
public function handle(Request $request, RouterEntry &$route) { return $request;
}
// Do authentication
$request->authenticated = true;
return $request;
}
} }
@@ -3,11 +3,11 @@ namespace Demo\Middlewares;
use Pecee\Http\Middleware\BaseCsrfVerifier; use Pecee\Http\Middleware\BaseCsrfVerifier;
class CsrfVerifier extends BaseCsrfVerifier { class CsrfVerifier extends BaseCsrfVerifier
{
/** /**
* CSRF validation will be ignored on the following urls. * CSRF validation will be ignored on the following urls.
*/ */
protected $except = ['/api/*']; protected $except = ['/api/*'];
} }
+12 -15
View File
@@ -1,29 +1,26 @@
<?php <?php
/** /**
* Custom router which handles default middlewares, default exceptions and things * Custom router which handles default middlewares, default exceptions and things
* that should be happen before and after the router is initialised. * that should be happen before and after the router is initialised.
*/ */
namespace Demo; namespace Demo;
use Pecee\SimpleRouter\SimpleRouter; use Pecee\SimpleRouter\SimpleRouter;
class Router extends SimpleRouter { class Router extends SimpleRouter
{
public static function start($defaultNamespace = null)
{
// Load our helpers
require_once 'helpers.php';
public static function start($defaultNamespace = null) { // Load our custom routes
require_once 'routes.php';
// Load our helpers parent::setDefaultNamespace('\Demo');
require_once 'helpers.php';
// Load our custom routes // Do initial stuff
require_once 'routes.php'; parent::start();
}
parent::setDefaultNamespace('\Demo\Controllers');
// Do initial stuff
parent::start();
}
} }
+16 -11
View File
@@ -1,39 +1,44 @@
<?php <?php
use Pecee\SimpleRouter\SimpleRouter; use Pecee\SimpleRouter\SimpleRouter;
function url($controller, $parameters = null, $getParams = null) { function url($controller, $parameters = null, $getParams = null)
SimpleRouter::getRoute($controller, $parameters, $getParams); {
SimpleRouter::getRoute($controller, $parameters, $getParams);
} }
/** /**
* Get current csrf-token * Get current csrf-token
* @return null|string * @return null|string
*/ */
function csrf_token() { function csrf_token()
$token = new \Pecee\CsrfToken(); {
return $token->getToken(); $token = new \Pecee\CsrfToken();
return $token->getToken();
} }
/** /**
* Get request object * Get request object
* @return \Pecee\Http\Request * @return \Pecee\Http\Request
*/ */
function request() { function request()
return SimpleRouter::request(); {
return SimpleRouter::request();
} }
/** /**
* Get response object * Get response object
* @return \Pecee\Http\Response * @return \Pecee\Http\Response
*/ */
function response() { function response()
return SimpleRouter::response(); {
return SimpleRouter::response();
} }
/** /**
* Get input class * Get input class
* @return \Pecee\Http\Input\Input * @return \Pecee\Http\Input\Input
*/ */
function input() { function input()
return SimpleRouter::request()->getInput(); {
return SimpleRouter::request()->getInput();
} }
+10 -10
View File
@@ -7,17 +7,17 @@ use Demo\Router;
Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier()); Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
Router::group(['exceptionHandler' => 'Demo\Handlers\CustomExceptionHandler'], function() { Router::group(['exceptionHandler' => 'Demo\Handlers\CustomExceptionHandler'], function () {
Router::get('/', 'DefaultController@index')->setAlias('home'); Router::get('/', 'DefaultController@index')->setAlias('home');
Router::get('/contact', 'DefaultController@contact')->setAlias('contact'); Router::get('/contact', 'DefaultController@contact')->setAlias('contact');
Router::get('/404', 'DefaultController@notFound')->setAlias('404'); Router::get('/404', 'DefaultController@notFound')->setAlias('404');
Router::basic('/companies', 'DefaultController@companies')->setAlias('companies'); Router::basic('/companies', 'DefaultController@companies')->setAlias('companies');
Router::basic('/companies/{id}', 'DefaultController@companies')->setAlias('companies'); Router::basic('/companies/{id}', 'DefaultController@companies')->setAlias('companies');
// Api // Api
Router::group(['prefix' => '/api', 'middleware' => 'Demo\Middlewares\ApiVerification'], function() { Router::group(['prefix' => '/api', 'middleware' => 'Demo\Middlewares\ApiVerification'], function () {
Router::resource('/demo', 'ApiController'); Router::resource('/demo', 'ApiController');
}); });
}); });
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace Pecee\Controller;
interface IRestController {
/**
* @return void
*/
function index();
/**
* @param mixed $id
* @return void
*/
function show($id);
/**
* @return void
*/
function store();
/**
* @return void
*/
function create();
/**
* View
* @param mixed $id
* @return void
*/
function edit($id);
/**
* @param mixed $id
* @return void
*/
function update($id);
/**
* @param mixed $id
* @return void
*/
function destroy($id);
}
+57 -51
View File
@@ -1,62 +1,68 @@
<?php <?php
namespace Pecee; namespace Pecee;
class CsrfToken { class CsrfToken
{
const CSRF_KEY = 'XSRF-TOKEN';
const CSRF_KEY = 'XSRF-TOKEN'; protected $token;
protected $token; /**
* Generate random identifier for CSRF token
*
* @return string
*/
public static function generateToken()
{
if (function_exists('mcrypt_create_iv')) {
return bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
}
return bin2hex(openssl_random_pseudo_bytes(32));
}
/** /**
* Generate random identifier for CSRF token * Validate valid CSRF token
* @return string *
*/ * @param string $token
public static function generateToken() { * @return bool
if (function_exists('mcrypt_create_iv')) { */
return bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); public function validate($token)
} {
return bin2hex(openssl_random_pseudo_bytes(32)); if ($token !== null && $this->getToken() !== null) {
} return hash_equals($token, $this->getToken());
}
return false;
}
/** /**
* Validate valid CSRF token * Set csrf token cookie
* *
* @param string $token * @param $token
* @return bool */
*/ public function setToken($token)
public function validate($token) { {
if($token !== null && $this->getToken() !== null) { setcookie(static::CSRF_KEY, $token, time() + 60 * 120, '/');
return hash_equals($token, $this->getToken()); }
}
return false;
}
/** /**
* Set csrf token cookie * Get csrf token
* * @return string|null
* @param $token */
*/ public function getToken()
public function setToken($token) { {
setcookie(static::CSRF_KEY, $token, time() + 60 * 120, '/'); if ($this->hasToken()) {
} return $_COOKIE[static::CSRF_KEY];
}
return null;
}
/** /**
* Get csrf token * Returns whether the csrf token has been defined
* @return string|null * @return bool
*/ */
public function getToken(){ public function hasToken()
if($this->hasToken()) { {
return $_COOKIE[static::CSRF_KEY]; return isset($_COOKIE[static::CSRF_KEY]);
} }
return null;
}
/**
* Returns whether the csrf token has been defined
* @return bool
*/
public function hasToken() {
return isset($_COOKIE[static::CSRF_KEY]);
}
} }
+3 -1
View File
@@ -1,4 +1,6 @@
<?php <?php
namespace Pecee\Exception; namespace Pecee\Exception;
class RouterException extends \Exception { } class RouterException extends \Exception
{
}
@@ -1,4 +1,6 @@
<?php <?php
namespace Pecee\Exception; namespace Pecee\Exception;
class TokenMismatchException extends \Exception {} class TokenMismatchException extends \Exception
{
}
+8 -8
View File
@@ -4,14 +4,14 @@ namespace Pecee\Handler;
use Pecee\Http\Request; use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry; use Pecee\SimpleRouter\RouterEntry;
interface IExceptionHandler { interface IExceptionHandler
{
/** /**
* @param Request $request * @param Request $request
* @param RouterEntry|null $route * @param RouterEntry|null $route
* @param \Exception $error * @param \Exception $error
* @return Request|null * @return Request|null
*/ */
public function handleError(Request $request, RouterEntry &$route = null, \Exception $error); public function handleError(Request $request, RouterEntry &$route = null, \Exception $error);
} }
+160 -162
View File
@@ -3,211 +3,209 @@ namespace Pecee\Http\Input;
use Pecee\Http\Request; use Pecee\Http\Request;
class Input { class Input
{
/**
* @var \Pecee\Http\Input\InputCollection
*/
public $get;
/** /**
* @var \Pecee\Http\Input\InputCollection * @var \Pecee\Http\Input\InputCollection
*/ */
public $get; public $post;
/** /**
* @var \Pecee\Http\Input\InputCollection * @var \Pecee\Http\Input\InputCollection
*/ */
public $post; public $file;
/** /**
* @var \Pecee\Http\Input\InputCollection * @var Request
*/ */
public $file; protected $request;
/** public function __construct(Request $request)
* @var Request {
*/ $this->request = $request;
protected $request; $this->setGet();
$this->setPost();
$this->setFile();
}
public function __construct(Request $request) { /**
$this->request = $request; * Get all get/post items
$this->setGet(); * @param array|null $filter Only take items in filter
$this->setPost(); * @return array
$this->setFile(); */
} public function all(array $filter = null)
{
$output = $_POST;
/** if ($this->request->getMethod() === 'post') {
* Get all get/post items
* @param array|null $filter Only take items in filter
* @return array
*/
public function all(array $filter = null) {
$output = $_POST; $contents = file_get_contents('php://input');
if($this->request->getMethod() === 'post') { if (stripos(trim($contents), '{') === 0) {
$output = json_decode($contents, true);
if ($output === false) {
$output = array();
}
}
}
$contents = file_get_contents('php://input'); $output = array_merge($_GET, $output);
if (stripos(trim($contents), '{') === 0) { if ($filter !== null) {
$output = json_decode($contents, true); $output = array_filter($output, function ($key) use ($filter) {
if($output === false) { if (in_array($key, $filter)) {
$output = array(); return true;
} }
}
}
$output = array_merge($_GET, $output); return false;
}, ARRAY_FILTER_USE_KEY);
}
if($filter !== null) { return $output;
$output = array_filter($output, function ($key) use ($filter) { }
if (in_array($key, $filter)) {
return true;
}
return false; public function getObject($index, $default = null)
}, ARRAY_FILTER_USE_KEY); {
} $key = (strpos($index, '[') > -1) ? substr($index, strpos($index, '[') + 1, strpos($index, ']') - strlen($index)) : null;
$index = (strpos($index, '[') > -1) ? substr($index, 0, strpos($index, '[')) : $index;
return $output; $element = $this->get->findFirst($index);
}
public function getObject($index, $default = null) { if ($element !== null) {
$key = (strpos($index, '[') > -1) ? substr($index, strpos($index, '[')+1, strpos($index, ']') - strlen($index)) : null; return ($key !== null) ? $element[$key] : $element;
$index = (strpos($index, '[') > -1) ? substr($index, 0, strpos($index, '[')) : $index; }
$element = $this->get->findFirst($index); if ($this->request->getMethod() !== 'get') {
if($element !== null) { $element = $this->post->findFirst($index);
return ($key !== null) ? $element[$key] : $element; if ($element !== null) {
} return ($key !== null) ? $element[$key] : $element;
}
if($this->request->getMethod() !== 'get') { $element = $this->file->findFirst($index);
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
}
$element = $this->post->findFirst($index); return $default;
}
if ($element !== null) { /**
return ($key !== null) ? $element[$key] : $element; * Get input element value matching index
} * @param string $index
* @param string|null $default
* @return string|null
*/
public function get($index, $default = null)
{
$item = $this->getObject($index);
$element = $this->file->findFirst($index); if ($item !== null) {
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
}
return $default; if ($item instanceof InputCollection || $item instanceof InputFile) {
} return $item;
}
/** return (trim($item->getValue()) === '') ? $default : $item->getValue();
* Get input element value matching index }
* @param string $index
* @param string|null $default
* @return string|null
*/
public function get($index, $default = null) {
$item = $this->getObject($index); return $default;
}
if($item !== null) { public function exists($index)
{
return ($this->getObject($index) !== null);
}
if($item instanceof InputCollection || $item instanceof InputFile) { public function setGet()
return $item; {
} $this->get = new InputCollection();
return (trim($item->getValue()) === '') ? $default : $item->getValue(); if (count($_GET) > 0) {
} foreach ($_GET as $key => $get) {
if (is_array($get) === false) {
$this->get->{$key} = new InputItem($key, $get);
continue;
}
return $default; $output = new InputCollection();
}
public function exists($index) { foreach ($get as $k => $g) {
return ($this->getObject($index) !== null); $output->{$k} = new InputItem($k, $g);
} }
public function setGet() { $this->get->{$key} = $output;
$this->get = new InputCollection(); }
}
}
if(count($_GET)) { public function setPost()
foreach($_GET as $key => $get) { {
if(!is_array($get)) { $this->post = new InputCollection();
$this->get->{$key} = new InputItem($key, $get);
continue;
}
$output = new InputCollection(); $postVars = $_POST;
foreach($get as $k => $g) { if (in_array($this->request->getMethod(), ['put', 'patch', 'delete']) === true) {
$output->{$k} = new InputItem($k, $g); parse_str(file_get_contents('php://input'), $postVars);
} }
$this->get->{$key} = $output; if (count($postVars) > 0) {
}
}
}
public function setPost() { foreach ($postVars as $key => $post) {
$this->post = new InputCollection(); if (is_array($post) === false) {
$this->post->{strtolower($key)} = new InputItem($key, $post);
continue;
}
$postVars = $_POST; $output = new InputCollection();
if(in_array($this->request->getMethod(), ['put', 'patch', 'delete'])) { foreach ($post as $k => $p) {
parse_str(file_get_contents('php://input'), $postVars); $output->{$k} = new InputItem($k, $p);
} }
if(count($postVars)) { $this->post->{strtolower($key)} = $output;
}
}
}
foreach($postVars as $key => $post) { public function setFile()
if(!is_array($post)) { {
$this->post->{strtolower($key)} = new InputItem($key, $post); $this->file = new InputCollection();
continue;
}
$output = new InputCollection(); if (count($_FILES) > 0) {
foreach ($_FILES as $key => $values) {
foreach($post as $k => $p) { // Handle array input
$output->{$k} = new InputItem($k, $p); if (is_array($values['name']) === false && trim($values['error']) !== '4') {
} $values['index'] = $key;
$this->file->{strtolower($key)} = InputFile::createFromArray($values);
continue;
}
$this->post->{strtolower($key)} = $output; $output = new InputCollection();
}
}
}
public function setFile() { foreach ($values['name'] as $k => $val) {
$this->file = new InputCollection(); if (trim($val['error'][$k]) !== '4') {
$output->{$k} = InputFile::createFromArray([
'index' => $k,
'error' => $val['error'][$k],
'tmp_name' => $val['tmp_name'][$k],
'type' => $val['type'][$k],
'size' => $val['size'][$k],
'name' => $val['name'][$k]
]);
}
}
if(count($_FILES)) { $this->file->{strtolower($key)} = $output;
foreach($_FILES as $key => $value) { }
// Multiple files }
if(!is_array($value['name'])) { }
// Strip empty values
if($value['error'] != '4') {
$file = new InputFile($key);
$file->setName($value['name']);
$file->setSize($value['size']);
$file->setType($value['type']);
$file->setTmpName($value['tmp_name']);
$file->setError($value['error']);
$this->file->{strtolower($key)} = $file;
}
continue;
}
$output = new InputCollection();
foreach($value['name'] as $k=>$val) {
// Strip empty values
if($value['error'][$k] != '4') {
$file = new InputFile($k);
$file->setName($value['name'][$k]);
$file->setSize($value['size'][$k]);
$file->setType($value['type'][$k]);
$file->setTmpName($value['tmp_name'][$k]);
$file->setError($value['error'][$k]);
$output->{$k} = $file;
}
}
$this->file->{strtolower($key)} = $output;
}
}
}
} }
+76 -67
View File
@@ -1,85 +1,94 @@
<?php <?php
namespace Pecee\Http\Input; namespace Pecee\Http\Input;
class InputCollection implements \IteratorAggregate { class InputCollection implements \IteratorAggregate
{
protected $data = array();
protected $data = array(); /**
* Search for input element matching index.
*
* @param string $index
* @param string|null $default
* @return InputItem
*/
public function findFirst($index, $default = null)
{
if (count($this->data) > 0) {
/** if (isset($this->data[$index])) {
* Search for input element matching index. return $this->data[$index];
* Useful for searching for finding items where $index doesn't contain form name. }
*
* @param string $index
* @param string|null $defaultValue
* @return mixed
*/
public function findFirst($index, $defaultValue = null) {
if(count($this->data)) {
if(isset($this->data[$index])) { foreach ($this->data as $key => $input) {
return $this->data[$index]; if (strtolower($index) === strtolower($key)) {
} return $input;
}
}
}
foreach($this->data as $key => $value) { return $default;
if(strtolower($index) === strtolower($key)) { }
return $value;
}
}
}
return $defaultValue; /**
} * Get input element value matching index
*
* @param string $index
* @param string|null $default
* @return string|null
*/
public function get($index, $default = null)
{
$input = $this->findFirst($index);
public function getValue($index, $defaultValue = null) { if($input !== null) {
if(count($this->data)) { if(trim($input->getValue()) === '') {
return $default;
}
if(isset($this->data[$index])) { return $input;
return $this->data[$index]->getValue(); }
}
foreach($this->data as $key => $value) { return $default;
if(strtolower($index) === strtolower($key)) { }
return $value->getValue();
}
}
}
return $defaultValue; /**
} * @param string $index
* @throws \InvalidArgumentException
* @return InputItem
*/
public function __get($index)
{
$item = $this->findFirst($index);
// Ensure that item are always available
if ($item === null) {
$this->data[$index] = new InputItem($index, null);
return $this->data[$index];
}
/** return $item;
* @param $index }
* @throws \InvalidArgumentException
* @return InputItem
*/
public function __get($index) {
$item = $this->findFirst($index);
// Ensure that item are always available
if($item === null) {
$this->data[$index] = new InputItem($index, null);
return $this->data[$index];
}
return $item; public function __set($index, $value)
} {
$this->data[$index] = $value;
}
public function __set($index, $value) { public function getData()
$this->data[$index] = $value; {
} return $this->data;
}
public function getData() { /**
return $this->data; * Retrieve an external iterator
} * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
* @return \Traversable An instance of an object implementing <b>Iterator</b> or
/** * <b>Traversable</b>
* Retrieve an external iterator * @since 5.0.0
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php */
* @return \Traversable An instance of an object implementing <b>Iterator</b> or public function getIterator()
* <b>Traversable</b> {
* @since 5.0.0 return new \ArrayIterator($this->data);
*/ }
public function getIterator() {
return new \ArrayIterator($this->data);
}
} }
+68 -27
View File
@@ -1,68 +1,109 @@
<?php <?php
namespace Pecee\Http\Input; namespace Pecee\Http\Input;
class InputFile extends InputItem { class InputFile extends InputItem
{
protected $name; public $size;
protected $size; public $type;
protected $type; public $error;
protected $error; public $tmpName;
protected $tmpName;
/** /**
* @return string * @return string
*/ */
public function getSize() { public function getSize()
{
return $this->size; return $this->size;
} }
/** /**
* @return string * @return string
*/ */
public function getType() { public function getType()
{
return $this->type; return $this->type;
} }
/** /**
* @return string * @return string
*/ */
public function getError() { public function getError()
{
return $this->error; return $this->error;
} }
public function getMime()
{
return $this->getType();
}
/** /**
* @return string * @return string
*/ */
public function getTmpName() { public function getTmpName()
{
return $this->tmpName; return $this->tmpName;
} }
public function getExtension() { public function getExtension()
{
return pathinfo($this->getName(), PATHINFO_EXTENSION); return pathinfo($this->getName(), PATHINFO_EXTENSION);
} }
public function move($destination) { public function move($destination)
{
return move_uploaded_file($this->tmpName, $destination); return move_uploaded_file($this->tmpName, $destination);
} }
public function getContents() { public function getContents()
{
return file_get_contents($this->tmpName); return file_get_contents($this->tmpName);
} }
public function setTmpName($name) { public function setTmpName($name)
$this->tmpName = $name; {
} $this->tmpName = $name;
}
public function setSize($size) { public function setSize($size)
$this->size = $size; {
} $this->size = $size;
}
public function setType($type) { public function setType($type)
$this->type = $type; {
} $this->type = $type;
}
public function setError($error) { public function setError($error)
$this->error = $error; {
} $this->error = $error;
}
/**
* Create from array
* @param array $values
* @return static
*/
public static function createFromArray(array $values)
{
if(!isset($values['index'])) {
throw new \InvalidArgumentException('Index key is required');
}
$input = new static($values['index']);
$input->setTmpName((isset($values['error']) ? $values['error'] : null));
$input->setName((isset($values['name']) ? $values['name'] : null));
$input->setSize((isset($values['size']) ? $values['size'] : null));
$input->setType((isset($values['type']) ? $values['type'] : null));
$input->setError((isset($values['tmp_name']) ? $values['tmp_name'] : null));
return $input;
}
public function __toString()
{
return (string)$this->tmpName;
}
} }
+57 -50
View File
@@ -1,63 +1,70 @@
<?php <?php
namespace Pecee\Http\Input; namespace Pecee\Http\Input;
class InputItem { class InputItem
{
public $index;
public $name;
public $value;
protected $index; public function __construct($index, $value = null)
protected $name; {
protected $value; $this->index = $index;
$this->value = $value;
public function __construct($index, $value = null) { // Make the name human friendly, by replace _ with space
$this->index = $index; $this->name = ucfirst(str_replace('_', ' ', $this->index));
$this->value = $value; }
// Make the name human friendly, by replace _ with space /**
$this->name = ucfirst(str_replace('_', ' ', $this->index)); * @return array
} */
public function getName()
{
return $this->name;
}
/** /**
* @return array * @return array
*/ */
public function getName() { public function getValue()
return $this->name; {
} return $this->value;
}
/** /**
* @return array * @return string
*/ */
public function getValue() { public function getIndex()
return $this->value; {
} return $this->index;
}
/** /**
* @return string * Set input name
*/ * @param string $name
public function getIndex() { * @return static $this
return $this->index; */
} public function setName($name)
{
$this->name = $name;
return $this;
}
/** /**
* Set input name * Set input value
* @param string $name * @param string $value
* @return static $this * @return static $this
*/ */
public function setName($name) { public function setValue($value)
$this->name = $name; {
return $this; $this->value = $value;
} return $this;
}
/** public function __toString()
* Set input value {
* @param string $value return (string)$this->value;
* @return static $this }
*/
public function setValue($value) {
$this->value = $value;
return $this;
}
public function __toString() {
return (string)$this->getValue();
}
} }
+67 -62
View File
@@ -6,85 +6,90 @@ use Pecee\Exception\TokenMismatchException;
use Pecee\Http\Request; use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry; use Pecee\SimpleRouter\RouterEntry;
class BaseCsrfVerifier implements IMiddleware { class BaseCsrfVerifier implements IMiddleware
{
const POST_KEY = 'csrf-token';
const HEADER_KEY = 'X-CSRF-TOKEN';
const POST_KEY = 'csrf-token'; protected $except;
const HEADER_KEY = 'X-CSRF-TOKEN'; protected $csrfToken;
protected $token;
protected $except; public function __construct()
protected $csrfToken; {
protected $token; $this->csrfToken = new CsrfToken();
public function __construct() { // Generate or get the CSRF-Token from Cookie.
$this->csrfToken = new CsrfToken(); $this->token = (!$this->hasToken()) ? $this->generateToken() : $this->csrfToken->getToken();
}
// Generate or get the CSRF-Token from Cookie. /**
$this->token = (!$this->hasToken()) ? $this->generateToken() : $this->csrfToken->getToken(); * Check if the url matches the urls in the except property
} * @param Request $request
* @return bool
*/
protected function skip(Request $request)
{
if ($this->except === null || is_array($this->except) === false) {
return false;
}
/** foreach ($this->except as $url) {
* Check if the url matches the urls in the except property $url = rtrim($url, '/');
* @param Request $request if ($url[strlen($url) - 1] === '*') {
* @return bool $url = rtrim($url, '*');
*/ $skip = (stripos($request->getUri(), $url) === 0);
protected function skip(Request $request) { } else {
$skip = ($url === rtrim($request->getUri(), '/'));
}
if($this->except === null || !is_array($this->except)) { if ($skip) {
return false; return true;
} }
}
foreach($this->except as $url) { return false;
$url = rtrim($url, '/'); }
if($url[strlen($url)-1] === '*') {
$url = rtrim($url, '*');
$skip = (stripos($request->getUri(), $url) === 0);
} else {
$skip = ($url === rtrim($request->getUri(), '/'));
}
if($skip) { public function handle(Request $request, RouterEntry &$route = null)
return true; {
}
}
return false; if ($request->getMethod() !== 'get' && !$this->skip($request)) {
}
public function handle(Request $request, RouterEntry &$route = null) { $token = $request->getInput()->post->getValue(static::POST_KEY);
if($request->getMethod() !== 'get' && !$this->skip($request)) { // If the token is not posted, check headers for valid x-csrf-token
if ($token === null) {
$token = $request->getHeader(static::HEADER_KEY);
}
$token = $request->getInput()->post->getValue(static::POST_KEY); if (!$this->csrfToken->validate($token)) {
throw new TokenMismatchException('Invalid csrf-token.');
}
// If the token is not posted, check headers for valid x-csrf-token }
if($token === null) {
$token = $request->getHeader(static::HEADER_KEY);
}
if( !$this->csrfToken->validate($token) ) { }
throw new TokenMismatchException('Invalid csrf-token.');
}
} public function generateToken()
{
$token = $this->csrfToken->generateToken();
$this->csrfToken->setToken($token);
return $token;
}
} public function hasToken()
{
if ($this->token != null) {
return true;
}
public function generateToken() { return $this->csrfToken->hasToken();
$token = $this->csrfToken->generateToken(); }
$this->csrfToken->setToken($token);
return $token;
}
public function hasToken() { public function getToken()
if($this->token != null) { {
return true; return $this->token;
} }
return $this->csrfToken->hasToken();
}
public function getToken() {
return $this->token;
}
} }
+8 -8
View File
@@ -4,13 +4,13 @@ namespace Pecee\Http\Middleware;
use Pecee\Http\Request; use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry; use Pecee\SimpleRouter\RouterEntry;
interface IMiddleware { interface IMiddleware
{
/** /**
* @param Request $request * @param Request $request
* @param RouterEntry $route * @param RouterEntry $route
* @return Request|null * @return Request|null
*/ */
public function handle(Request $request, RouterEntry &$route); public function handle(Request $request, RouterEntry &$route);
} }
+174 -153
View File
@@ -3,184 +3,205 @@ namespace Pecee\Http;
use Pecee\Http\Input\Input; use Pecee\Http\Input\Input;
class Request { class Request
{
protected $data = array();
protected $headers;
protected $host;
protected $uri;
protected $method;
protected $input;
protected $data = array(); public function __construct()
protected $headers; {
protected $host; $this->parseHeaders();
protected $uri; $this->input = new Input($this);
protected $method;
protected $input;
$this->host = $this->getHeader('http-host');;
$this->uri = $this->getHeader('request-uri');
$this->method = strtolower($this->input->post->findFirst('_method', $this->getHeader('request-method')));
}
public function __construct() { protected function parseHeaders()
$this->parseHeaders(); {
$this->input = new Input($this); $this->headers = array();
$this->host = $this->getHeader('http_host');; foreach ($_SERVER as $name => $value) {
$this->uri = $this->getHeader('request_uri'); $this->headers[strtolower($name)] = $value;
$this->method = strtolower($this->input->post->findFirst('_method', $this->getHeader('request_method'))); $this->headers[strtolower(str_replace('_', '-', $name))] = $value;
} }
}
protected function parseHeaders() { public function isSecure()
$this->headers = array(); {
if ($this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || $this->getHeader('server-port') === 443) {
return true;
}
foreach ($_SERVER as $name => $value) { return false;
$this->headers[strtolower($name)] = $value; }
}
}
public function isSecure() { /**
if($this->getHeader('http_x_forwarded_proto') === 'https') { * @return string
return true; */
} public function getUri()
{
return $this->uri;
}
if($this->getHeader('https') !== null) { /**
return true; * @return string
} */
public function getHost()
{
return $this->host;
}
return ($this->getHeader('server_port') === 443); /**
} * @return string
*/
public function getMethod()
{
return $this->method;
}
/** /**
* @return string * Get http basic auth user
*/ * @return string|null
public function getUri() { */
return $this->uri; public function getUser()
} {
return $this->getHeader('php-auth-user');
}
/** /**
* @return string * Get http basic auth password
*/ * @return string|null
public function getHost() { */
return $this->host; public function getPassword()
} {
return $this->getHeader('php-auth-pw');
}
/** /**
* @return string * Get all headers
*/ * @return array
public function getMethod() { */
return $this->method; public function getHeaders()
} {
return $this->headers;
}
/** /**
* Get http basic auth user * Get id address
* @return string|null * @return string
*/ */
public function getUser() { public function getIp()
return $this->getHeader('php_auth_user'); {
} if ($this->getHeader('http-cf-connecting-ip') !== null) {
return $this->getHeader('http-cf-connecting-ip');
}
/** if ($this->getHeader('http-x-forwarded-for') !== null && strlen($this->getHeader('http-x-forwarded-for'))) {
* Get http basic auth password return $this->getHeader('http-x-forwarded_for');
* @return string|null }
*/
public function getPassword() {
return $this->getHeader('php_auth_pw');
}
/** return $this->getHeader('remote-addr');
* Get all headers }
* @return array
*/
public function getHeaders() {
return $this->headers;
}
/** /**
* Get id address * Get referer
* @return string * @return string
*/ */
public function getIp() { public function getReferer()
if($this->getHeader('http_cf_connecting_ip') !== null) { {
return $this->getHeader('http_cf_connecting_ip'); return $this->getHeader('http-referer');
} }
if($this->getHeader('http_x_forwarded_for') !== null && strlen($this->getHeader('http_x_forwarded_for'))) { /**
return $this->getHeader('http_x_forwarded_for'); * Get user agent
} * @return string
*/
public function getUserAgent()
{
return $this->getHeader('http-user-agent');
}
return $this->getHeader('remote_addr'); /**
} * Get header value by name
*
* @param string $name
* @param object|null $defaultValue
*
* @return string|null
*/
public function getHeader($name, $defaultValue = null)
{
return isset($this->headers[strtolower($name)]) ? $this->headers[strtolower($name)] : $defaultValue;
}
/** /**
* Get referer * Get input class
* @return string * @return Input
*/ */
public function getReferer() { public function getInput()
return $this->getHeader('http_referer'); {
} return $this->input;
}
/** /**
* Get user agent * Is format accepted
* @return string *
*/ * @param string $format
public function getUserAgent() { *
return $this->getHeader('http_user_agent'); * @return bool
} */
public function isFormatAccepted($format)
{
return ($this->getHeader('http-accept') !== null && stripos($this->getHeader('http-accept'), $format) > -1);
}
/** /**
* Get header value by name * Get accept formats
* @param string $name * @return array
* @param object|null $defaultValue */
* @return string|null public function getAcceptFormats()
*/ {
public function getHeader($name, $defaultValue = null) { return explode(',', $this->getHeader('http-accept'));
return isset($this->headers[strtolower($name)]) ? $this->headers[strtolower($name)] : $defaultValue; }
}
/** /**
* Get input class * @param string $uri
* @return Input */
*/ public function setUri($uri)
public function getInput() { {
return $this->input; $this->uri = $uri;
} }
/** /**
* Is format accepted * @param string $host
* @param string $format */
* @return bool public function setHost($host)
*/ {
public function isFormatAccepted($format) { $this->host = $host;
return ($this->getHeader('http_accept') !== null && stripos($this->getHeader('http_accept'), $format) > -1); }
}
/** /**
* Get accept formats * @param string $method
* @return array */
*/ public function setMethod($method)
public function getAcceptFormats() { {
return explode(',', $this->getHeader('http_accept')); $this->method = $method;
} }
/** public function __set($name, $value = null)
* @param string $uri {
*/ $this->data[$name] = $value;
public function setUri($uri) { }
$this->uri = $uri;
}
/** public function __get($name)
* @param string $host {
*/ return isset($this->data[$name]) ? $this->data[$name] : null;
public function setHost($host) { }
$this->host = $host;
}
/**
* @param string $method
*/
public function setMethod($method) {
$this->method = $method;
}
public function __set($name, $value = null) {
$this->data[$name] = $value;
}
public function __get($name) {
return isset($this->data[$name]) ? $this->data[$name] : null;
}
} }
+98 -89
View File
@@ -1,109 +1,118 @@
<?php <?php
namespace Pecee\Http; namespace Pecee\Http;
class Response { class Response
{
protected $request;
protected $request; public function __construct(Request $request)
{
$this->request = $request;
}
public function __construct(Request $request) { /**
$this->request = $request; * Set the http status code
} *
* @param int $code
* @return static
*/
public function httpCode($code)
{
http_response_code($code);
return $this;
}
/** /**
* Set the http status code * Redirect the response
* *
* @param int $code * @param string $url
* @return static * @param int $httpCode
*/ */
public function httpCode($code) { public function redirect($url, $httpCode = null)
http_response_code($code); {
return $this; if ($httpCode !== null) {
} $this->httpCode($httpCode);
}
/** $this->header('location: ' . $url);
* Redirect the response die();
* }
* @param string $url
* @param int $httpCode
*/
public function redirect($url, $httpCode = null) {
if($httpCode !== null) {
$this->httpCode($httpCode);
}
$this->header('location: ' . $url); public function refresh()
die(); {
} $this->redirect($this->request->getUri());
}
public function refresh() { /**
$this->redirect($this->request->getUri()); * Add http authorisation
} * @param string $name
* @return static
*/
public function auth($name = '')
{
$this->headers([
'WWW-Authenticate: Basic realm="' . $name . '"',
'HTTP/1.0 401 Unauthorized'
]);
return $this;
}
/** public function cache($eTag, $lastModified = 2592000)
* Add http authorisation {
* @param string $name
* @return static
*/
public function auth($name = '') {
$this->headers([
'WWW-Authenticate: Basic realm="' . $name . '"',
'HTTP/1.0 401 Unauthorized'
]);
return $this;
}
public function cache($eTag, $lastModified = 2592000) { $this->headers([
'Cache-Control: public',
'Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModified) . ' GMT',
'Etag: ' . $eTag
]);
$this->headers([ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $lastModified ||
'Cache-Control: public', isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $eTag
'Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModified) . ' GMT', ) {
'Etag: ' . $eTag
]);
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $lastModified || $this->headers([
isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $eTag) { 'HTTP/1.1 304 Not Modified'
]);
$this->headers([ exit();
'HTTP/1.1 304 Not Modified' }
]);
exit(); return $this;
} }
return $this; /**
} * Json encode array
* @param array $value
*/
public function json(array $value)
{
$this->header('Content-type: application/json');
echo json_encode($value);
die();
}
/** /**
* Json encode array * Add header to response
* @param array $value * @param string $value
*/ * @return static
public function json(array $value) { */
$this->header('Content-type: application/json'); public function header($value)
echo json_encode($value); {
die(); header($value);
} return $this;
}
/** /**
* Add header to response * Add multiple headers to response
* @param string $value * @param array $headers
* @return static * @return static
*/ */
public function header($value) { public function headers(array $headers)
header($value); {
return $this; foreach ($headers as $header) {
} header($header);
}
/** return $this;
* Add multiple headers to response }
* @param array $headers
* @return static
*/
public function headers(array $headers) {
foreach($headers as $header) {
header($header);
}
return $this;
}
} }
+7 -5
View File
@@ -1,11 +1,13 @@
<?php <?php
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
interface IControllerRoute { interface IControllerRoute
{
public function getController();
public function getController(); public function setController($controller);
public function setController($controller);
public function getMethod();
public function setMethod($method);
public function getMethod();
public function setMethod($method);
} }
+4 -4
View File
@@ -1,9 +1,9 @@
<?php <?php
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
interface ILoadableRoute { interface ILoadableRoute
{
public function getUrl(); public function getUrl();
public function setUrl($url);
public function setUrl($url);
} }
+73 -67
View File
@@ -1,84 +1,90 @@
<?php <?php
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
abstract class LoadableRoute extends RouterEntry implements ILoadableRoute { abstract class LoadableRoute extends RouterEntry implements ILoadableRoute
{
const PARAMETERS_REGEX_MATCH = '{([A-Za-z\-\_]*?)\?{0,1}}';
const PARAMETERS_REGEX_MATCH = '{([A-Za-z\-\_]*?)\?{0,1}}'; protected $url;
protected $alias;
protected $url; public function getUrl()
protected $alias; {
return $this->url;
}
public function getUrl() { /**
return $this->url; * Set url
} *
* @param string $url
* @return static
*/
public function setUrl($url)
{
$this->url = ($url === '/') ? '/' : '/' . trim($url, '/') . '/';
/** if (preg_match_all('/' . static::PARAMETERS_REGEX_MATCH . '/is', $this->url, $matches)) {
* Set url if (count($matches[1]) > 0) {
* foreach ($matches[1] as $key) {
* @param string $url $this->parameters[$key] = null;
* @return static }
*/ }
public function setUrl($url) { }
$this->url = '/' . trim($url, '/') . '/';
if(preg_match_all('/' . static::PARAMETERS_REGEX_MATCH . '/is', $this->url, $matches)) { return $this;
if (count($matches[1])) { }
foreach ($matches[1] as $key) {
$this->parameters[$key] = null;
}
}
}
return $this; /**
} * Get alias for the url which can be used when getting the url route.
* @return string|array
*/
public function getAlias()
{
return $this->alias;
}
/** /**
* Get alias for the url which can be used when getting the url route. * Check if route has given alias.
* @return string|array *
*/ * @param string $name
public function getAlias(){ * @return bool
return $this->alias; */
} public function hasAlias($name)
{
if ($this->getAlias() !== null) {
if (is_array($this->getAlias()) === true) {
foreach ($this->getAlias() as $alias) {
if (strtolower($alias) === strtolower($name)) {
return true;
}
}
}
return strtolower($this->getAlias()) === strtolower($name);
}
/** return false;
* Check if route has given alias. }
*
* @param string $name
* @return bool
*/
public function hasAlias($name) {
if ($this->getAlias() !== null) {
if (is_array($this->getAlias())) {
foreach ($this->getAlias() as $alias) {
if (strtolower($alias) === strtolower($name)) {
return true;
}
}
}
return strtolower($this->getAlias()) === strtolower($name);
}
return false; /**
} * Set the url alias for easier getting the url route.
* @param string|array $alias
* @return static
*/
public function setAlias($alias)
{
$this->alias = $alias;
return $this;
}
/** public function setData(array $settings)
* Set the url alias for easier getting the url route. {
* @param string|array $alias
* @return static
*/
public function setAlias($alias){
$this->alias = $alias;
return $this;
}
public function setData(array $settings) { // Change as to alias
if (isset($settings['as'])) {
$this->setAlias($settings['as']);
}
// Change as to alias return parent::setData($settings);
if(isset($settings['as'])) { }
$this->setAlias($settings['as']);
}
return parent::setData($settings);
}
} }
File diff suppressed because it is too large Load Diff
+3 -4
View File
@@ -3,8 +3,7 @@ namespace Pecee\SimpleRouter;
use Pecee\Http\Request; use Pecee\Http\Request;
abstract class RouterBootManager { abstract class RouterBootManager
{
abstract public function boot(Request $request); abstract public function boot(Request $request);
} }
+80 -73
View File
@@ -4,100 +4,107 @@ namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException; use Pecee\Exception\RouterException;
use Pecee\Http\Request; use Pecee\Http\Request;
class RouterController extends LoadableRoute implements IControllerRoute { class RouterController extends LoadableRoute implements IControllerRoute
{
protected $defaultMethod = 'index';
protected $controller;
protected $method;
const DEFAULT_METHOD = 'index'; public function __construct($url, $controller)
{
$this->setUrl($url);
$this->controller = $controller;
}
protected $controller; public function renderRoute(Request $request)
protected $method; {
if ($this->getCallback() !== null && is_callable($this->getCallback())) {
public function __construct($url, $controller) { // When the callback is a function
$this->setUrl($url); call_user_func_array($this->getCallback(), $this->getParameters());
$this->controller = $controller; } else {
} // When the callback is a method
$controller = explode('@', $this->getCallback());
$className = $this->getNamespace() . '\\' . $controller[0];
public function renderRoute(Request $request) { $class = $this->loadClass($className);
if($this->getCallback() !== null && is_callable($this->getCallback())) { $method = $request->getMethod() . ucfirst($controller[1]);
// When the callback is a function if (!method_exists($class, $method)) {
call_user_func_array($this->getCallback(), $this->getParameters()); throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
} else { }
// When the callback is a method
$controller = explode('@', $this->getCallback());
$className = $this->getNamespace() . '\\' . $controller[0];
$class = $this->loadClass($className); call_user_func_array(array($class, $method), $this->getParameters());
$method = $request->getMethod() . ucfirst($controller[1]);
if (!method_exists($class, $method)) { return $class;
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 null;
}
return $class; public function matchRoute(Request $request)
} {
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
return null; if (strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
}
public function matchRoute(Request $request) { $strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) { $path = explode('/', $strippedUrl);
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/'); if (count($path) > 0) {
$path = explode('/', $strippedUrl); $method = (!isset($path[0]) || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
$this->method = $method;
if(count($path)) { array_shift($path);
$this->parameters = $path;
$method = (!isset($path[0]) || trim($path[0]) === '') ? static::DEFAULT_METHOD : $path[0]; // Set callback
$this->method = $method; $this->setCallback($this->controller . '@' . $this->method);
array_shift($path); return true;
$this->parameters = $path; }
}
// Set callback return null;
$this->setCallback($this->controller . '@' . $this->method); }
return true; /**
} * @return string
} */
return null; public function getController()
} {
return $this->controller;
}
/** /**
* @return string * @param string $controller
*/ * @return static
public function getController() { */
return $this->controller; public function setController($controller)
} {
$this->controller = $controller;
return $this;
}
/** /**
* @param string $controller * @return string
* @return static */
*/ public function getMethod()
public function setController($controller) { {
$this->controller = $controller; return $this->method;
return $this; }
}
/** /**
* @return string * @param string $method
*/ * @return static
public function getMethod() { */
return $this->method; public function setMethod($method)
} {
$this->method = $method;
/** return $this;
* @param string $method }
* @return static
*/
public function setMethod($method) {
$this->method = $method;
return $this;
}
} }
+419 -396
View File
@@ -1,405 +1,428 @@
<?php <?php
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException; use Pecee\Exception\RouterException;
use Pecee\Http\Middleware\IMiddleware; use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request; use Pecee\Http\Request;
abstract class RouterEntry { abstract class RouterEntry
{
const REQUEST_TYPE_GET = 'get'; const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_POST = 'post'; const REQUEST_TYPE_POST = 'post';
const REQUEST_TYPE_PUT = 'put'; const REQUEST_TYPE_PUT = 'put';
const REQUEST_TYPE_PATCH = 'patch'; const REQUEST_TYPE_PATCH = 'patch';
const REQUEST_TYPE_OPTIONS = 'options'; const REQUEST_TYPE_OPTIONS = 'options';
const REQUEST_TYPE_DELETE = 'delete'; const REQUEST_TYPE_DELETE = 'delete';
public static $allowedRequestTypes = [ public static $requestTypes = [
self::REQUEST_TYPE_GET, self::REQUEST_TYPE_GET,
self::REQUEST_TYPE_POST, self::REQUEST_TYPE_POST,
self::REQUEST_TYPE_PUT, self::REQUEST_TYPE_PUT,
self::REQUEST_TYPE_PATCH, self::REQUEST_TYPE_PATCH,
self::REQUEST_TYPE_OPTIONS, self::REQUEST_TYPE_OPTIONS,
self::REQUEST_TYPE_DELETE, self::REQUEST_TYPE_DELETE,
]; ];
protected $parent; protected $parent;
protected $callback; protected $callback;
protected $namespace; protected $namespace;
protected $regex; protected $regex;
protected $requestMethods = array(); protected $requestMethods = array();
protected $where = array(); protected $where = array();
protected $parameters = array(); protected $parameters = array();
protected $middlewares = array(); protected $middlewares = array();
protected function loadClass($name) { protected function loadClass($name)
if(!class_exists($name)) { {
throw new RouterException(sprintf('Class %s does not exist', $name)); if (!class_exists($name)) {
} throw new RouterException(sprintf('Class %s does not exist', $name));
}
return new $name();
} return new $name();
}
protected function parseParameters($route, $url, $parameterRegex = '[\w]+') {
$parameterNames = array(); protected function parseParameters($route, $url, $parameterRegex = '[\w]+')
$regex = ''; {
$lastCharacter = ''; $parameterNames = array();
$isParameter = false; $regex = '';
$parameter = ''; $lastCharacter = '';
$isParameter = false;
$routeLength = strlen($route); $parameter = '';
for($i = 0; $i < $routeLength; $i++) {
$routeLength = strlen($route);
$character = $route[$i]; for ($i = 0; $i < $routeLength; $i++) {
if($character === '{') { $character = $route[$i];
// Remove "/" and "\" from regex
if(substr($regex, strlen($regex)-1) === '/') { if ($character === '{') {
$regex = substr($regex, 0, strlen($regex) - 2); // Remove "/" and "\" from regex
} if (substr($regex, strlen($regex) - 1) === '/') {
$regex = substr($regex, 0, strlen($regex) - 2);
$isParameter = true; }
} elseif($isParameter && $character === '}') {
$required = true; $isParameter = true;
// Check for optional parameter } elseif ($isParameter && $character === '}') {
$required = true;
// Use custom parameter regex if it exists
if(is_array($this->where) && isset($this->where[$parameter])) { // Check for optional parameter and use custom parameter regex if it exists
$parameterRegex = $this->where[$parameter]; if (is_array($this->where) === true && isset($this->where[$parameter])) {
} $parameterRegex = $this->where[$parameter];
}
if($lastCharacter === '?') {
$parameter = substr($parameter, 0, strlen($parameter)-1); if ($lastCharacter === '?') {
$regex .= '(?:\/?(?P<' . $parameter . '>'. $parameterRegex .')[^\/]?)?'; $parameter = substr($parameter, 0, strlen($parameter) - 1);
$required = false; $regex .= '(?:\/?(?P<' . $parameter . '>' . $parameterRegex . ')[^\/]?)?';
} else { $required = false;
$regex .= '\/?(?P<' . $parameter . '>'. $parameterRegex .')[^\/]?'; } else {
} $regex .= '\/?(?P<' . $parameter . '>' . $parameterRegex . ')[^\/]?';
}
$parameterNames[] = [
'name' => $parameter, $parameterNames[] = [
'required' => $required 'name' => $parameter,
]; 'required' => $required
];
$parameter = '';
$isParameter = false; $parameter = '';
$isParameter = false;
} elseif($isParameter) { } elseif ($isParameter) {
$parameter .= $character; $parameter .= $character;
} elseif($character === '/') { } elseif ($character === '/') {
$regex .= '\\' . $character; $regex .= '\\' . $character;
} else { } else {
$regex .= str_replace('.', '\\.', $character); $regex .= str_replace('.', '\\.', $character);
} }
$lastCharacter = $character; $lastCharacter = $character;
} }
$parameterValues = array(); $parameterValues = array();
if(preg_match('/^'.$regex.'\/?$/is', $url, $parameterValues)) { if (preg_match('/^' . $regex . '\/?$/is', $url, $parameterValues)) {
$parameters = array(); $parameters = array();
$max = count($parameterNames); foreach ($parameterNames as $name) {
$parameterValue = isset($parameterValues[$name['name']]) ? $parameterValues[$name['name']] : null;
for($i = 0; $i < $max; $i++) {
$name = $parameterNames[$i]; if ($name['required'] && $parameterValue === null) {
$parameterValue = isset($parameterValues[$name['name']]) ? $parameterValues[$name['name']] : null; throw new RouterException('Missing required parameter ' . $name['name'], 404);
}
if($name['required'] && $parameterValue === null) {
throw new RouterException('Missing required parameter ' . $name['name'], 404); if ($name['required'] === false && $parameterValue === null) {
} continue;
}
if(!$name['required'] && $parameterValue === null) {
continue; $parameters[$name['name']] = $parameterValue;
} }
$parameters[$name['name']] = $parameterValue; return $parameters;
} }
return $parameters; return null;
} }
return null; public function loadMiddleware(Request $request, RouterEntry &$route)
} {
if (count($this->getMiddlewares()) > 0) {
public function loadMiddleware(Request $request, RouterEntry &$route) { foreach ($this->getMiddlewares() as $middleware) {
if(count($this->getMiddlewares())) {
foreach($this->getMiddlewares() as $middleware) { $middleware = $this->loadClass($middleware);
$middleware = $this->loadClass($middleware); if (!($middleware instanceof IMiddleware)) {
if (!($middleware instanceof IMiddleware)) { throw new RouterException($middleware . ' must be instance of Middleware');
throw new RouterException($middleware . ' must be instance of Middleware'); }
}
/* @var $class IMiddleware */
/* @var $class IMiddleware */ $middleware->handle($request, $route);
$middleware->handle($request, $route);
} }
} }
} }
public function renderRoute(Request $request) { public function renderRoute(Request $request)
if($this->getCallback() !== null && is_callable($this->getCallback())) { {
// When the callback is a function if ($this->getCallback() !== null && is_callable($this->getCallback())) {
call_user_func_array($this->getCallback(), $this->getParameters());
} else { // When the callback is a function
// When the callback is a method call_user_func_array($this->getCallback(), $this->getParameters());
$controller = explode('@', $this->getCallback());
$className = $this->getNamespace() . '\\' . $controller[0]; } else {
$class = $this->loadClass($className); // When the callback is a method
$method = $controller[1]; $controller = explode('@', $this->getCallback());
$className = $this->getNamespace() . '\\' . $controller[0];
if (!method_exists($class, $method)) {
throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404); $class = $this->loadClass($className);
} $method = $controller[1];
$parameters = array_filter($this->getParameters(), function($var){ if (!method_exists($class, $method)) {
return ($var !== null); throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}); }
call_user_func_array(array($class, $method), $parameters); $parameters = array_filter($this->getParameters(), function ($var) {
return ($var !== null);
return $class; });
}
call_user_func_array(array($class, $method), $parameters);
return null;
} return $class;
}
/**
* Returns callback name/identifier for the current route based on the callback. return null;
* Useful if you need to get a unique identifier for the loaded route, for instance }
* when using translations etc.
* /**
* @return string * 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
public function getIdentifier() { * when using translations etc.
if(strpos($this->callback, '@') !== false) { *
return $this->callback; * @return string
} */
return 'function_' . md5($this->callback); public function getIdentifier()
} {
if (strpos($this->callback, '@') !== false) {
/** return $this->callback;
* Set allowed request methods }
* return 'function_' . md5($this->callback);
* @param array $methods }
* @return static $this
*/ /**
public function setRequestMethods(array $methods) { * Set allowed request methods
$this->requestMethods = $methods; *
return $this; * @param array $methods
} * @return static $this
*/
/** public function setRequestMethods(array $methods)
* Get allowed request methods {
* $this->requestMethods = $methods;
* @return array return $this;
*/ }
public function getRequestMethods() {
return $this->requestMethods; /**
} * Get allowed request methods
* @return array
/** */
* @return RouterEntry public function getRequestMethods()
*/ {
public function getParent() { return $this->requestMethods;
return $this->parent; }
}
/**
/** * @return RouterEntry
* Set parent route */
* @param RouterEntry $parent public function getParent()
* @return static $this {
*/ return $this->parent;
public function setParent(RouterEntry $parent) { }
$this->parent = $parent;
return $this; /**
} * Set parent route
*
/** * @param RouterEntry $parent
* @param string $callback * @return static $this
* @return static */
*/ public function setParent(RouterEntry $parent)
public function setCallback($callback) { {
$this->callback = $callback; $this->parent = $parent;
return $this; return $this;
} }
/** /**
* @return mixed * @param string $callback
*/ * @return static
public function getCallback() { */
return $this->callback; public function setCallback($callback)
} {
$this->callback = $callback;
public function getMethod() { return $this;
if(strpos($this->callback, '@') !== false) { }
$tmp = explode('@', $this->callback);
return $tmp[1]; /**
} * @return mixed
return null; */
} public function getCallback()
{
public function getClass() { return $this->callback;
if(strpos($this->callback, '@') !== false) { }
$tmp = explode('@', $this->callback);
return $tmp[0]; public function getMethod()
} {
return null; if (strpos($this->callback, '@') !== false) {
} $tmp = explode('@', $this->callback);
return $tmp[1];
public function setMethod($method) { }
$this->callback = sprintf('%s@%s', $this->getClass(), $method); return null;
return $this; }
}
public function getClass()
public function setClass($class) { {
$this->callback = sprintf('%s@%s', $class, $this->getMethod()); if (strpos($this->callback, '@') !== false) {
return $this; $tmp = explode('@', $this->callback);
} return $tmp[0];
}
/** return null;
* @param string $middleware }
* @return static
*/ public function setMethod($method)
public function setMiddleware($middleware) { {
$this->middlewares[] = $middleware; $this->callback = sprintf('%s@%s', $this->getClass(), $method);
return $this; return $this;
} }
public function setMiddlewares(array $middlewares) { public function setClass($class)
$this->middlewares = $middlewares; {
return $this; $this->callback = sprintf('%s@%s', $class, $this->getMethod());
} return $this;
}
/**
* @param string $namespace /**
* @return static * @param string $middleware
*/ * @return static
public function setNamespace($namespace) { */
$this->namespace = $namespace; public function setMiddleware($middleware)
return $this; {
} $this->middlewares[] = $middleware;
return $this;
/** }
* @return string|array
*/ public function setMiddlewares(array $middlewares)
public function getMiddlewares() { {
return $this->middlewares; $this->middlewares = $middlewares;
} return $this;
}
/**
* @return string /**
*/ * @param string $namespace
public function getNamespace() { * @return static
return $this->namespace; */
} public function setNamespace($namespace)
{
/** $this->namespace = $namespace;
* @return array return $this;
*/ }
public function getParameters(){
return $this->parameters; /**
} * @return string|array
*/
/** public function getMiddlewares()
* @param mixed $parameters {
* @return static return $this->middlewares;
*/ }
public function setParameters($parameters) {
$this->parameters = $parameters; /**
return $this; * @return string
} */
public function getNamespace()
/** {
* Add regular expression parameter match return $this->namespace;
* }
* @param array $options
* @return static /**
*/ * @return array
public function where(array $options) { */
$this->where = $options; public function getParameters()
return $this; {
} return $this->parameters;
}
/**
* Add regular expression match for url /**
* * @param mixed $parameters
* @param string $regex * @return static
* @return static */
*/ public function setParameters($parameters)
public function match($regex) { {
$this->regex = $regex; $this->parameters = $parameters;
return $this; return $this;
} }
/** /**
* Get arguments that can be inherited by child routes. * Add regular expression parameter match
* *
* @return array * @param array $options
*/ * @return static
public function getMergeableData() { */
public function where(array $options)
$output = array(); {
$this->where = $options;
if($this->namespace !== null) { return $this;
$output['namespace'] = $this->namespace; }
}
/**
if(count($this->middlewares)) { * Add regular expression match for url
$output['middleware'] = $this->middlewares; *
} * @param string $regex
* @return static
if(count($this->where)) { */
$output['where'] = $this->where; public function match($regex)
} {
$this->regex = $regex;
if(count($this->requestMethods)) { return $this;
$output['method'] = $this->requestMethods; }
}
/**
if(count($this->parameters)) { * Get arguments that can be inherited by child routes.
$output['parameters'] = $this->parameters; *
} * @return array
*/
return $output; public function getMergeableData()
} {
$output = array();
/**
* Set arguments/data by array if ($this->namespace !== null) {
* $output['namespace'] = $this->namespace;
* @param array $settings }
* @return static
*/ if (count($this->middlewares) > 0) {
public function setData(array $settings) { $output['middleware'] = $this->middlewares;
}
if (isset($settings['namespace']) && $this->namespace === null) {
$this->setNamespace($settings['namespace']); if (count($this->where) > 0) {
} $output['where'] = $this->where;
}
// Push middleware if multiple
if (isset($settings['middleware'])) { if (count($this->requestMethods) > 0) {
$this->middlewares = array_merge((array)$settings['middleware'], $this->middlewares); $output['method'] = $this->requestMethods;
} }
if(isset($settings['method'])) { if (count($this->parameters) > 0) {
$this->setRequestMethods((array)$settings['method']); $output['parameters'] = $this->parameters;
} }
if(isset($settings['where'])) { return $output;
$this->where($settings['where']); }
}
/**
if(isset($settings['parameters'])) { * Set arguments/data by array
$this->setParameters($settings['parameters']); *
} * @param array $settings
* @return static
return $this; */
} public function setData(array $settings)
{
abstract function matchRoute(Request $request); if (isset($settings['namespace']) && $this->namespace === null) {
$this->setNamespace($settings['namespace']);
}
// Push middleware if multiple
if (isset($settings['middleware'])) {
$this->middlewares = array_merge((array)$settings['middleware'], $this->middlewares);
}
if (isset($settings['method'])) {
$this->setRequestMethods((array)$settings['method']);
}
if (isset($settings['where'])) {
$this->where($settings['where']);
}
if (isset($settings['parameters'])) {
$this->setParameters($settings['parameters']);
}
return $this;
}
abstract function matchRoute(Request $request);
} }
+74 -69
View File
@@ -1,93 +1,98 @@
<?php <?php
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
use Pecee\Http\Request; use Pecee\Http\Request;
class RouterGroup extends RouterEntry { class RouterGroup extends RouterEntry
{
protected $prefix;
protected $domains = array();
protected $exceptionHandlers = array();
protected $prefix; public function matchDomain(Request $request)
protected $domains = array(); {
protected $exceptionHandlers = array(); if (count($this->domains) > 0) {
foreach ($this->domains as $domain) {
public function matchDomain(Request $request) { $parameters = $this->parseParameters($domain, $request->getHost(), '.*');
if(count($this->domains)) {
for($i = 0; $i < count($this->domains); $i++) {
$domain = $this->domains[$i];
$parameters = $this->parseParameters($domain, $request->getHost(), '.*'); if ($parameters !== null) {
$this->parameters = $parameters;
return true;
}
}
if($parameters !== null) { return false;
$this->parameters = $parameters; }
return true;
}
}
return false; return true;
} }
return true; public function matchRoute(Request $request)
} {
// Skip if prefix doesn't match
if ($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) {
return false;
}
public function matchRoute(Request $request) { return $this->matchDomain($request);
// Skip if prefix doesn't match }
if($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) {
return false;
}
return $this->matchDomain($request); public function setExceptionHandlers(array $handlers)
} {
$this->exceptionHandlers = $handlers;
return $this;
}
public function setExceptionHandlers(array $handlers) { public function getExceptionHandlers()
$this->exceptionHandlers = $handlers; {
return $this; return $this->exceptionHandlers;
} }
public function getExceptionHandlers() { public function getDomains()
return $this->exceptionHandlers; {
} return $this->domains;
}
public function getDomains() { public function setDomains(array $domains)
return $this->domains; {
} $this->domains = $domains;
return $this;
}
public function setDomains(array $domains) { /**
$this->domains = $domains; * @param string $prefix
return $this; * @return static
} */
public function setPrefix($prefix)
{
$this->prefix = '/' . trim($prefix, '/');
return $this;
}
/** /**
* @param string $prefix * @return string
* @return static */
*/ public function getPrefix()
public function setPrefix($prefix) { {
$this->prefix = '/' . trim($prefix, '/'); return $this->prefix;
return $this; }
}
/** public function setData(array $settings)
* @return string {
*/ if (isset($settings['prefix'])) {
public function getPrefix() { $this->setPrefix($settings['prefix']);
return $this->prefix; }
}
public function setData(array $settings) { if (isset($settings['exceptionHandler'])) {
$this->setExceptionHandlers((array)$settings['exceptionHandler']);
}
if(isset($settings['prefix'])) { if (isset($settings['domain'])) {
$this->setPrefix($settings['prefix']); $this->setDomains((array)$settings['domain']);
} }
if(isset($settings['exceptionHandler'])) { return parent::setData($settings);
$this->setExceptionHandlers((array)$settings['exceptionHandler']); }
}
if(isset($settings['domain'])) {
$this->setDomains((array)$settings['domain']);
}
return parent::setData($settings);
}
} }
+91 -83
View File
@@ -4,112 +4,120 @@ namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException; use Pecee\Exception\RouterException;
use Pecee\Http\Request; use Pecee\Http\Request;
class RouterResource extends LoadableRoute implements IControllerRoute { class RouterResource extends LoadableRoute implements IControllerRoute
{
protected $controller;
protected $controller; public function __construct($url, $controller)
{
$this->setUrl($url);
$this->controller = $controller;
}
public function __construct($url, $controller) { public function renderRoute(Request $request)
$this->setUrl($url); {
$this->controller = $controller; if ($this->getCallback() !== null && 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]);
public function renderRoute(Request $request) { if (!method_exists($class, $method)) {
if($this->getCallback() !== null && is_callable($this->getCallback())) { throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
// 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)) { call_user_func_array([$class, $method], $this->getParameters());
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 $class; return null;
} }
return null; protected function call($method, $parameters)
} {
$this->setCallback($this->controller . '@' . $method);
$this->parameters = $parameters;
protected function call($method, $parameters) { return true;
$this->setCallback($this->controller . '@' . $method); }
$this->parameters = $parameters;
return true;
}
public function matchRoute(Request $request) { public function matchRoute(Request $request)
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH); {
$url = rtrim($url, '/') . '/'; $url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$route = rtrim($this->url, '/') . '/{id?}/{action?}'; $route = rtrim($this->url, '/') . '/{id?}/{action?}';
$parameters = $this->parseParameters($route, $url); $parameters = $this->parseParameters($route, $url);
if($parameters !== null) { if ($parameters !== null) {
if(is_array($parameters)) { $parameters = array_merge($this->parameters, (array)$parameters);
$parameters = array_merge($this->parameters, $parameters);
}
$action = isset($parameters['action']) ? $parameters['action'] : null; $action = isset($parameters['action']) ? $parameters['action'] : null;
unset($parameters['action']); unset($parameters['action']);
// Delete $method = request()->getMethod();
if($request->getMethod() === static::REQUEST_TYPE_DELETE && $request->getMethod() === static::REQUEST_TYPE_POST) {
return $this->call('destroy', $parameters);
}
// Update // Delete
if(in_array($request->getMethod(), array(static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT)) && $request->getMethod() === static::REQUEST_TYPE_POST) { if (isset($parameters['id']) && $method === static::REQUEST_TYPE_DELETE) {
return $this->call('update', $parameters); return $this->call('destroy', $parameters);
} }
// Edit // Update
if(isset($action) && strtolower($action) === 'edit' && $request->getMethod() === static::REQUEST_TYPE_GET) { if (isset($parameters['id']) && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT])) {
return $this->call('edit', $parameters); return $this->call('update', $parameters);
} }
// Create // Edit
if(strtolower($action) === 'create' && $request->getMethod() === static::REQUEST_TYPE_GET) { if (isset($parameters['id']) && strtolower($action) === 'edit' && $method === static::REQUEST_TYPE_GET) {
return $this->call('create', $parameters); return $this->call('edit', $parameters);
} }
// Save // Create
if($request->getMethod() === static::REQUEST_TYPE_POST) { if (strtolower($action) === 'create' && $method === static::REQUEST_TYPE_GET) {
return $this->call('store', $parameters); return $this->call('create', $parameters);
} }
// Show // Save
if(isset($parameters['id']) && $request->getMethod() === static::REQUEST_TYPE_GET) { if ($method === static::REQUEST_TYPE_POST) {
return $this->call('show', $parameters); return $this->call('store', $parameters);
} }
// Index // Show
return $this->call('index', $parameters); if (isset($parameters['id']) && $method === static::REQUEST_TYPE_GET) {
} return $this->call('show', $parameters);
}
return null; // Index
} return $this->call('index', $parameters);
}
/** return null;
* @return string }
*/
public function getController() {
return $this->controller;
}
/** /**
* @param string $controller * @return string
* @return static */
*/ public function getController()
public function setController($controller) { {
$this->controller = $controller; return $this->controller;
return $this; }
}
/**
* @param string $controller
* @return static
*/
public function setController($controller)
{
$this->controller = $controller;
return $this;
}
} }
+29 -29
View File
@@ -1,42 +1,42 @@
<?php <?php
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
use Pecee\Http\Request; use Pecee\Http\Request;
class RouterRoute extends LoadableRoute { class RouterRoute extends LoadableRoute
{
public function __construct($url, $callback)
{
$this->setUrl($url);
$this->setCallback($callback);
}
public function __construct($url, $callback) { public function matchRoute(Request $request)
$this->setUrl($url); {
$this->setCallback($callback); $url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
} $url = rtrim($url, '/') . '/';
public function matchRoute(Request $request) { // Match on custom defined regular expression
if ($this->regex !== null) {
$parameters = array();
if (preg_match('/(' . $this->regex . ')/is', $request->getHost() . $url, $parameters)) {
$this->parameters = (array)$parameters[0];
return true;
}
return null;
}
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH); // Make regular expression based on route
$url = rtrim($url, '/') . '/'; $route = rtrim($this->url, '/') . '/';
// Match on custom defined regular expression $parameters = $this->parseParameters($route, $url);
if($this->regex !== null) {
$parameters = array();
if(preg_match('/(' . $this->regex . ')/is', $request->getHost() . $url, $parameters)) {
$this->parameters = (!is_array($parameters[0]) ? array($parameters[0]) : $parameters[0]);
return true;
}
return null;
}
// Make regular expression based on route if ($parameters !== null) {
$route = rtrim($this->url, '/') . '/'; $this->parameters = array_merge($this->parameters, $parameters);
return true;
}
$parameters = $this->parseParameters($route, $url); return null;
}
if($parameters !== null) {
$this->parameters = array_merge($this->parameters, $parameters);
return true;
}
return null;
}
} }
+299 -110
View File
@@ -1,158 +1,347 @@
<?php <?php
/** /**
* --------------------------- * ---------------------------
* Router helper class * Router helper class
* --------------------------- * ---------------------------
* This class is added so calls can be made statically like Router::get() making the code look more pretty. * This class is added so calls can be made statically like Router::get() making the code look more pretty.
*/ */
namespace Pecee\SimpleRouter; namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException;
use Pecee\Http\Middleware\BaseCsrfVerifier; use Pecee\Http\Middleware\BaseCsrfVerifier;
class SimpleRouter { class SimpleRouter
{
protected static $defaultNamespace;
/** /**
* Start/route request * Start/route request
* @throws \Pecee\Exception\RouterException *
*/ * @throws \Pecee\Exception\RouterException
public static function start() { */
RouterBase::getInstance()->routeRequest(); public static function start()
} {
static::router()->routeRequest();
}
/** /**
* Set default namespace for all routes * Set default namespace which will be prepended to all routes.
* @param string $defaultNamespace *
*/ * @param string $defaultNamespace
public static function setDefaultNamespace($defaultNamespace) { */
RouterBase::getInstance()->setDefaultNamespace($defaultNamespace); public static function setDefaultNamespace($defaultNamespace)
} {
static::$defaultNamespace = $defaultNamespace;
}
/** /**
* Set base csrf verifier * Base CSRF verifier
* @param BaseCsrfVerifier $baseCsrfVerifier *
*/ * @param BaseCsrfVerifier $baseCsrfVerifier
public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier) { */
RouterBase::getInstance()->setCsrfVerifier($baseCsrfVerifier); public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier)
} {
static::router()->setCsrfVerifier($baseCsrfVerifier);
}
public static function addBootManager(RouterBootManager $bootManager) { /**
RouterBase::getInstance()->addBootManager($bootManager); * Boot managers allows you to alter the routes before the routing occurs.
} * Perfect if you want to load pretty-urls from a file or database.
*
* @param RouterBootManager $bootManager
*/
public static function addBootManager(RouterBootManager $bootManager)
{
static::router()->addBootManager($bootManager);
}
public static function get($url, $callback, array $settings = null) { /**
return static::match(['get'], $url, $callback, $settings); * Route the given url to your callback on GET request method.
} *
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function get($url, $callback, array $settings = null)
{
return static::match(['get'], $url, $callback, $settings);
}
public static function post($url, $callback, array $settings = null) { /**
return static::match(['post'], $url, $callback, $settings); * Route the given url to your callback on POST request method.
} *
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function post($url, $callback, array $settings = null)
{
return static::match(['post'], $url, $callback, $settings);
}
public static function put($url, $callback, array $settings = null) { /**
return static::match(['put'], $url, $callback, $settings); * Route the given url to your callback on PUT request method.
} *
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function put($url, $callback, array $settings = null)
{
return static::match(['put'], $url, $callback, $settings);
}
public static function patch($url, $callback, array $settings = null) { /**
return static::match(['patch'], $url, $callback, $settings); * Route the given url to your callback on PATCH request method.
} *
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function patch($url, $callback, array $settings = null)
{
return static::match(['patch'], $url, $callback, $settings);
}
public static function options($url, $callback, array $settings = null) { /**
return static::match(['options'], $url, $callback, $settings); * Route the given url to your callback on OPTIONS request method.
} *
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function options($url, $callback, array $settings = null)
{
return static::match(['options'], $url, $callback, $settings);
}
public static function delete($url, $callback, array $settings = null) { /**
return static::match(['delete'], $url, $callback, $settings); * Route the given url to your callback on DELETE request method.
} *
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function delete($url, $callback, array $settings = null)
{
return static::match(['delete'], $url, $callback, $settings);
}
public static function group($settings = array(), $callback) { /**
$group = new RouterGroup(); * Groups allows for encapsulating routes with special settings.
$group->setCallback($callback); *
* @param array $settings
* @param \Closure $callback
* @throws RouterException
* @return RouterGroup
*/
public static function group($settings = array(), \Closure $callback)
{
$group = new RouterGroup();
$group->setCallback($callback);
if($settings !== null && is_array($settings)) { if ($settings !== null && is_array($settings) === true) {
$group->setData($settings); $group->setData($settings);
} }
RouterBase::getInstance()->addRoute($group); if (is_callable($callback) === false) {
throw new RouterException('Invalid callback provided. Only functions or methods supported');
}
return $group; static::router()->addRoute($group);
}
/** return $group;
* Adds get + post route }
*
* @param string $url
* @param callable $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function basic($url, $callback, array $settings = null) {
return static::match(['get', 'post'], $url, $callback, $settings);
}
public static function match(array $requestMethods, $url, $callback, array $settings = null) { /**
$route = new RouterRoute($url, $callback); * Alias for the form method
$route->setRequestMethods($requestMethods); *
* @param string $url
* @param callable $callback
* @param array|null $settings
* @see SimpleRouter::form
* @return RouterRoute
*/
public static function basic($url, $callback, array $settings = null)
{
return static::match(['get', 'post'], $url, $callback, $settings);
}
if($settings !== null) { /**
$route->setData($settings); * This type will route the given url to your callback on the provided request methods.
} * Route the given url to your callback on POST and GET request method.
*
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @see SimpleRouter::form
* @return RouterRoute
*/
public static function form($url, $callback, array $settings = null)
{
return static::match(['get', 'post'], $url, $callback, $settings);
}
RouterBase::getInstance()->addRoute($route); /**
* This type will route the given url to your callback on the provided request methods.
*
* @param array $requestMethods
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterEntry|RouterRoute
*/
public static function match(array $requestMethods, $url, $callback, array $settings = null)
{
$route = new RouterRoute($url, $callback);
$route->setRequestMethods($requestMethods);
return $route; if ($settings !== null) {
} $route->setData($settings);
}
public static function all($url, $callback, array $settings = null) { $route = static::addDefaultNamespace($route);
$route = new RouterRoute($url, $callback);
if($settings !== null) { static::router()->addRoute($route);
$route->setData($settings);
}
RouterBase::getInstance()->addRoute($route); return $route;
}
return $route; /**
} * This type will route the given url to your callback and allow any type of request method
*
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouterRoute
*/
public static function all($url, $callback, array $settings = null)
{
$route = new RouterRoute($url, $callback);
public static function controller($url, $controller, array $settings = null) { if ($settings !== null) {
$route = new RouterController($url, $controller); $route->setData($settings);
}
if($settings !== null) { $route = static::addDefaultNamespace($route);
$route->setData($settings);
}
RouterBase::getInstance()->addRoute($route); static::router()->addRoute($route);
return $route; return $route;
} }
public static function resource($url, $controller, array $settings = null) { /**
$route = new RouterResource($url, $controller); * This route will route request from the given url to the controller.
*
* @param string $url
* @param string $controller
* @param array|null $settings
* @return RouterController
*/
public static function controller($url, $controller, array $settings = null)
{
$route = new RouterController($url, $controller);
if($settings !== null) { if ($settings !== null) {
$route->setData($settings); $route->setData($settings);
} }
static::router()->addRoute($route); $route = static::addDefaultNamespace($route);
return $route; static::router()->addRoute($route);
}
public static function getRoute($controller = null, $parameters = null, $getParams = null) { return $route;
return static::router()->getRoute($controller, $parameters, $getParams); }
}
public static function request() { /**
return static::router()->getRequest(); * This type will route all REST-supported requests to different methods in the provided controller.
} *
* @param string $url
* @param string $controller
* @param array|null $settings
* @return RouterResource
*/
public static function resource($url, $controller, array $settings = null)
{
$route = new RouterResource($url, $controller);
public static function response() { if ($settings !== null) {
return static::router()->getResponse(); $route->setData($settings);
} }
protected static function router() { static::router()->addRoute($route);
return RouterBase::getInstance();
} return $route;
}
/**
* Get url by controller or alias.
*
* @param string $controller
* @param array|null $parameters
* @param array|null $getParams
* @return string
*/
public static function getRoute($controller = null, $parameters = null, $getParams = null)
{
return static::router()->getRoute($controller, $parameters, $getParams);
}
/**
* Get the request
*
* @return \Pecee\Http\Request
*/
public static function request()
{
return static::router()->getRequest();
}
/**
* Get the response object
*
* @return \Pecee\Http\Response
*/
public static function response()
{
return static::router()->getResponse();
}
/**
* Returns the router instance
*
* @return RouterBase
*/
public static function router()
{
return RouterBase::getInstance();
}
/**
* Prepends the default namespace to all new routes added.
*
* @param RouterEntry $route
* @return RouterEntry
*/
protected static function addDefaultNamespace(RouterEntry $route)
{
if (static::$defaultNamespace !== null) {
$namespace = static::$defaultNamespace;
if ($route->getNamespace() !== null) {
$namespace .= '\\' . $route->getNamespace();
}
$route->setNamespace($namespace);
}
return $route;
}
} }
+18 -11
View File
@@ -1,18 +1,25 @@
<?php <?php
class DummyController { class DummyController
{
public function start()
{
echo static::class . '@' . 'start() OK';
}
public function start() { public function param($params = null)
echo static::class . '@' .'start() OK'; {
} $params = func_get_args();
echo 'Params: ' . join(', ', $params);
}
public function param($params = null) { public function notFound()
$params = func_get_args(); {
echo 'Params: ' . join(', ', $params); echo 'not found';
} }
public function notFound() { public function silent() {
echo 'not found';
} }
} }
+6 -6
View File
@@ -1,14 +1,14 @@
<?php <?php
require_once 'Exceptions/MiddlewareLoadedException.php'; require_once 'Exceptions/MiddlewareLoadedException.php';
use Pecee\Http\Middleware\IMiddleware; use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request; use Pecee\Http\Request;
class DummyMiddleware implements IMiddleware { class DummyMiddleware implements IMiddleware
{
public function handle(Request $request, \Pecee\SimpleRouter\RouterEntry &$route = null) { public function handle(Request $request, \Pecee\SimpleRouter\RouterEntry &$route = null)
throw new MiddlewareLoadedException('Middleware loaded!'); {
} throw new MiddlewareLoadedException('Middleware loaded!');
}
} }
@@ -1,2 +1,4 @@
<?php <?php
class MiddlewareLoadedException extends \Exception {} class MiddlewareLoadedException extends \Exception
{
}
+6 -4
View File
@@ -1,8 +1,10 @@
<?php <?php
class ExceptionHandler implements \Pecee\Handler\IExceptionHandler {
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\RouterEntry &$route = null, \Exception $error){ class ExceptionHandler implements \Pecee\Handler\IExceptionHandler
throw $error; {
} public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\RouterEntry &$route = null, \Exception $error)
{
throw $error;
}
} }
+63 -52
View File
@@ -3,79 +3,90 @@
require_once 'Dummy/DummyMiddleware.php'; require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php'; require_once 'Dummy/DummyController.php';
class GroupTest extends PHPUnit_Framework_TestCase { use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
protected $result; class GroupTest extends PHPUnit_Framework_TestCase
{
protected $result;
public function testGroupLoad() { public function testGroupLoad()
{
$this->result = false;
$this->result = false; SimpleRouter::group(['prefix' => '/group'], function () {
$this->result = true;
});
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/group'], function() { try {
$this->result = true; SimpleRouter::start();
}); } catch (Exception $e) {
// ignore RouteNotFound exception
}
try { $this->assertTrue($this->result);
\Pecee\SimpleRouter\SimpleRouter::start(); }
} catch(Exception $e) {
// ignore RouteNotFound exception
}
$this->assertTrue($this->result); public function testNestedGroup()
} {
public function testNestedGroup() { SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/api/v1/test');
SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::group(['prefix' => '/api'], function () {
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/api/v1/test');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/api'], function() { SimpleRouter::group(['prefix' => '/v1'], function () {
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/v1'], function() { SimpleRouter::get('/test', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::get('/test', 'DummyController@start'); });
});
});
\Pecee\SimpleRouter\SimpleRouter::start(); });
}
public function testManyRoutes() { SimpleRouter::start();
}
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); public function testManyRoutes()
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/match'); {
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/api'], function() { SimpleRouter::router()->reset();
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/v1'], function() { SimpleRouter::request()->setUri('/my/match');
\Pecee\SimpleRouter\SimpleRouter::get('/test', 'DummyController@start'); SimpleRouter::request()->setMethod('get');
});
});
\Pecee\SimpleRouter\SimpleRouter::get('/my/match', 'DummyController@start'); SimpleRouter::group(['prefix' => '/api'], function () {
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/service'], function() { SimpleRouter::group(['prefix' => '/v1'], function () {
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/v1'], function() { SimpleRouter::get('/test', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::get('/no-match', 'DummyController@start'); });
});
});
\Pecee\SimpleRouter\SimpleRouter::start(); });
}
public function testUrls() { SimpleRouter::get('/my/match', 'DummyController@start');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::group(['prefix' => '/service'], function () {
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/fancy/url/1');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::get('/my/fancy/url/1', 'DummyController@start', ['as' => 'fancy1']); SimpleRouter::group(['prefix' => '/v1'], function () {
\Pecee\SimpleRouter\SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setAlias('fancy2'); SimpleRouter::get('/no-match', 'DummyController@start');
});
\Pecee\SimpleRouter\SimpleRouter::start(); });
$this->assertTrue((\Pecee\SimpleRouter\SimpleRouter::getRoute('fancy1') === '/my/fancy/url/1/')); SimpleRouter::start();
$this->assertTrue((\Pecee\SimpleRouter\SimpleRouter::getRoute('fancy2') === '/my/fancy/url/2/')); }
} public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/fancy/url/1');
SimpleRouter::request()->setMethod('get');
SimpleRouter::get('/my/fancy/url/1', 'DummyController@start', ['as' => 'fancy1']);
SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setAlias('fancy2');
SimpleRouter::start();
$this->assertTrue((SimpleRouter::getRoute('fancy1') === '/my/fancy/url/1/'));
$this->assertTrue((SimpleRouter::getRoute('fancy2') === '/my/fancy/url/2/'));
}
} }
+19 -18
View File
@@ -4,28 +4,29 @@ require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php'; require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php'; require_once 'Dummy/Handler/ExceptionHandler.php';
class MiddlewareTest extends PHPUnit_Framework_TestCase { use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
public function testMiddlewareFound() { class MiddlewareTest extends PHPUnit_Framework_TestCase
{
public function testMiddlewareFound()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/test/url');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get'); SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url'); });
\Pecee\SimpleRouter\SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function() { $found = false;
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
});
$found = false; try {
SimpleRouter::start();
} catch (\Exception $e) {
$found = ($e instanceof MiddlewareLoadedException);
}
try { $this->assertTrue($found);
\Pecee\SimpleRouter\SimpleRouter::start(); }
}catch(\Exception $e) {
$found = ($e instanceof MiddlewareLoadedException);
}
$this->assertTrue($found);
}
} }
+103 -101
View File
@@ -4,135 +4,137 @@ require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php'; require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php'; require_once 'Dummy/Handler/ExceptionHandler.php';
class RouterRouteTest extends PHPUnit_Framework_TestCase { use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
protected $result = false; class RouterRouteTest extends PHPUnit_Framework_TestCase
{
protected $result = false;
public function testNotFound() { public function testNotFound()
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); {
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get'); SimpleRouter::router()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test-param1-param2'); SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
\Pecee\SimpleRouter\SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function() { SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
\Pecee\SimpleRouter\SimpleRouter::get('/non-existing-path', 'DummyController@start'); SimpleRouter::get('/non-existing-path', 'DummyController@start');
}); });
$found = false; $found = false;
try { try {
\Pecee\SimpleRouter\SimpleRouter::start(); SimpleRouter::start();
}catch(\Exception $e) { } catch (\Exception $e) {
$found = ($e instanceof \Pecee\Exception\RouterException && $e->getCode() == 404); $found = ($e instanceof \Pecee\Exception\RouterException && $e->getCode() == 404);
} }
$this->assertTrue($found); $this->assertTrue($found);
}
} public function testGet()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('get');
public function testGet() { SimpleRouter::get('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::start();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url'); }
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start'); public function testPost()
\Pecee\SimpleRouter\SimpleRouter::start(); {
} SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
public function testPost() { SimpleRouter::post('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::start();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url'); }
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('post');
\Pecee\SimpleRouter\SimpleRouter::post('/my/test/url', 'DummyController@start'); public function testPut()
\Pecee\SimpleRouter\SimpleRouter::start(); {
} SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('put');
public function testPut() { SimpleRouter::put('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::start();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url'); }
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('put');
\Pecee\SimpleRouter\SimpleRouter::put('/my/test/url', 'DummyController@start'); public function testDelete()
\Pecee\SimpleRouter\SimpleRouter::start(); {
} SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('delete');
public function testDelete() { SimpleRouter::delete('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::start();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url'); }
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('delete');
\Pecee\SimpleRouter\SimpleRouter::delete('/my/test/url', 'DummyController@start'); public function testMethodNotAllowed()
\Pecee\SimpleRouter\SimpleRouter::start(); {
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
} SimpleRouter::get('/my/test/url', 'DummyController@start');
public function testMethodNotAllowed() { try {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::start();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url'); } catch (\Exception $e) {
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('post'); $this->assertEquals(403, $e->getCode());
}
}
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start'); public function testSimpleParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1');
try { SimpleRouter::get('/test-{param1}', 'DummyController@param');
\Pecee\SimpleRouter\SimpleRouter::start(); SimpleRouter::start();
} catch(\Exception $e) { }
$this->assertEquals(403, $e->getCode());
}
} public function testMultiParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
public function testSimpleParam() { SimpleRouter::get('/test-{param1}-{param2}', 'DummyController@param');
SimpleRouter::start();
}
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); public function testPathParamRegex()
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get'); {
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test-param1'); SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test/path/123123');
\Pecee\SimpleRouter\SimpleRouter::get('/test-{param1}', 'DummyController@param'); SimpleRouter::get('/test/path/{myParam}', 'DummyController@param', ['where' => ['myParam' => '([0-9]+)']]);
\Pecee\SimpleRouter\SimpleRouter::start(); SimpleRouter::start();
}
} public function testDomainRoute()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test');
SimpleRouter::request()->setHost('hello.world.com');
public function testMultiParam() { $this->result = false;
\Pecee\SimpleRouter\RouterBase::getInstance()->reset(); SimpleRouter::group(['domain' => '{subdomain}.world.com'], function () {
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get'); SimpleRouter::get('test', function ($subdomain = null) {
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test-param1-param2'); $this->result = ($subdomain === 'hello');
});
});
\Pecee\SimpleRouter\SimpleRouter::get('/test-{param1}-{param2}', 'DummyController@param'); SimpleRouter::start();
\Pecee\SimpleRouter\SimpleRouter::start();
} $this->assertTrue($this->result);
public function testPathParamRegex() { }
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test/path/123123');
\Pecee\SimpleRouter\SimpleRouter::get('/test/path/{myParam}', 'DummyController@param', ['where' => ['myParam' => '([0-9]+)']]);
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testDomainRoute() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test');
\Pecee\SimpleRouter\SimpleRouter::request()->setHost('hello.world.com');
$this->result = false;
\Pecee\SimpleRouter\SimpleRouter::group(['domain' => '{subdomain}.world.com'], function() {
\Pecee\SimpleRouter\SimpleRouter::get('test', function($subdomain = null) {
$this->result = ($subdomain === 'hello');
});
});
\Pecee\SimpleRouter\SimpleRouter::start();
$this->assertTrue($this->result);
}
} }
+83
View File
@@ -0,0 +1,83 @@
<?php
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php';
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
class RouterUrlTest extends PHPUnit_Framework_TestCase
{
protected $result = false;
protected function getUrl($controller = null, $parameters = null, $getParams = null) {
return SimpleRouter::getRoute($controller, $parameters, $getParams);
}
public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/');
// Match normal route on alias
SimpleRouter::get('/', 'DummyController@silent', ['as' => 'home']);
SimpleRouter::group(['prefix' => '/admin'], function() {
// Match route with prefix on alias
SimpleRouter::get('/{id?}', 'DummyController@start', ['as' => 'admin.home']);
// Match controller with prefix and alias
SimpleRouter::controller('/users', 'DummyController', ['as' => 'admin.users']);
// Match controller with prefix and NO alias
SimpleRouter::controller('/pages', 'DummyController');
});
// Match controller with no prefix and no alias
SimpleRouter::controller('/cats', 'CatsController');
// Pretend to load page
SimpleRouter::start();
// Should match /
$this->assertEquals($this->getUrl('home'), '/');
// Should match /admin/
$this->assertEquals($this->getUrl('DummyController@start'), '/admin/');
// Should match /admin/
$this->assertEquals($this->getUrl('admin.home'), '/admin/');
// Should match /admin/2/
$this->assertEquals($this->getUrl('admin.home', ['id' => 2]), '/admin/2/');
// Should match /admin/users/
$this->assertEquals($this->getUrl('admin.users'), '/admin/users/');
// Should match /admin/users/home/
$this->assertEquals($this->getUrl('admin.users@home'), '/admin/users/home/');
// Should match /cats/
$this->assertEquals($this->getUrl('CatsController'), '/cats/');
// Should match /cats/view/
$this->assertEquals($this->getUrl('CatsController', 'view'), '/cats/view/');
// Should match /cats/view/
$this->assertEquals($this->getUrl('CatsController', ['view']), '/cats/view/');
// Should match /cats/view/666
$this->assertEquals($this->getUrl('CatsController@view', ['666']), '/cats/view/666/');
// Should match /funny/man/
$this->assertEquals($this->getUrl('/funny/man'), '/funny/man/');
// Should match /?jackdaniels=true
$this->assertEquals($this->getUrl('home', null, ['jackdaniels' => 'true']), '/?jackdaniels=true');
}
}