Compare commits

...

46 Commits

Author SHA1 Message Date
Simon Sessingø 3e41ee28b6 Merge pull request #200 from skipperbent/v2-development
Optimised route-match behavior
2016-11-28 06:45:05 +01:00
Simon Sessingø 8f3ce68a5e Optimised route-match behavior 2016-11-28 06:43:26 +01:00
Simon Sessingø 751b4444ae Merge pull request #198 from skipperbent/v2-development
Fixed parameters not merged with default values
2016-11-28 05:53:26 +01:00
Simon Sessingø d25351f4f9 Fixed parameters not merged with default values 2016-11-28 05:53:02 +01:00
Simon Sessingø 8cd42a2c4b Merge pull request #196 from skipperbent/v2-development
2.6.0
2016-11-28 05:26:04 +01:00
Simon Sessingø e8f19fbeae Simplified PARAMETERS_REGEX_MATCH in Route class. 2016-11-28 05:24:12 +01:00
Simon Sessingø 5c89ae2aaf Moved regex/match functionality to LoadableRoute. 2016-11-28 04:45:46 +01:00
Simon Sessingø b694a7c0c9 More cleanup 2016-11-28 04:39:34 +01:00
Simon Sessingø 7847b71bbc Cleanup 2016-11-28 04:38:38 +01:00
Simon Sessingø d9b97ccf42 Bugfixes 2016-11-28 04:20:34 +01:00
Simon Sessingø 74351e0330 Bugfixes 2016-11-27 01:07:11 +01:00
Simon Sessingø f5b03e106c Bugfixes 2016-11-27 00:55:47 +01:00
Simon Sessingø 2c5221051e Development 2016-11-26 10:40:42 +01:00
Simon Sessingø e8e1471bab Merge pull request #194 from skipperbent/v2-development
Input optimisations
2016-11-26 05:22:02 +01:00
Simon Sessingø aad11ac581 Input optimisations 2016-11-26 05:21:09 +01:00
Simon Sessingø 4de1498723 Merge pull request #192 from skipperbent/v2-development
V2 development
2016-11-26 05:03:36 +01:00
Simon Sessingø c1835152b6 Removed PHP 7 specific functionality. 2016-11-26 04:53:05 +01:00
Simon Sessingø 6213f2fb75 Development
- Optimised Input-classes.
- `get` and `getObject` methods on `Input` now supports filtering on multiple method-types when using the `$method` parameter.
- Input classes now know how to parse that stupid nested $_FILES array.
- It's now possible to change method-names on ResourceControllers.
- Removed `getValue` and `setValue` from `InputFile` classes.
- Ensured that request-method are only parsed from $_POST or $_SERVER.
- Fixed minor parameter-issues with subdomain routing.
- Added PHPDocs.
- Added even more unit-tests.
- Many small optimisations tweaks.
2016-11-26 04:30:00 +01:00
Simon Sessingø ea243f2c89 Merge pull request #190 from skipperbent/v2-development
Development
2016-11-25 18:28:26 +01:00
Simon Sessingø 68fc6b76c0 Development
- It's now possible to adjust the load-order for parameters on routes.
- Replaced PHP 7.1 deprecated `mcrypt_create_iv` function with `random_bytes` if it is available (requires > PHP7)
- Added `setIndex`, `setName` and `setValue` methods to `IInputItem` to allow for extendability.
- Cleanup and bug fixes.
2016-11-25 18:26:50 +01:00
Simon Sessingø 56653568e4 Merge pull request #188 from skipperbent/v2-development
Development
2016-11-25 12:55:08 +01:00
Simon Sessingø 1c515119b4 Development
- Ensure that request-method is always lowercase.
- Fixed spaces instead of tabs to comply with PSR-2.
2016-11-25 12:51:45 +01:00
Simon Sessingø 5d330643e7 Merge pull request #186 from skipperbent/v2-development
Development
2016-11-25 03:28:49 +02:00
Simon Sessingø 2dd2d95af5 Development
- Fixed BootManager not loading.
- Optimised for-loops.
2016-11-25 02:27:46 +01:00
Simon Sessingø 57aa8eac1e Merge pull request #184 from skipperbent/v2-development
Fixed Exception when using Request
2016-11-25 03:05:17 +02:00
Simon Sessingø 7edee8e6d3 Fixed Exception when using Request 2016-11-25 02:04:42 +01:00
Simon Sessingø 4efc72d013 Merge pull request #182 from skipperbent/v2-development
Development
2016-11-25 02:58:43 +02:00
Simon Sessingø e360fb5438 Removed demo-project. 2016-11-25 01:57:39 +01:00
Simon Sessingø c6bce8a420 Development
- Began work on new documentation.
- BaseCsrfVerifier now only matches `POST`, `PUT` and `DELETE`.
- Parameters are now parsed on custom regex-matches.
- Added `$type` option to `get` method in `Input` class.
2016-11-25 01:53:02 +01:00
Simon Sessingø fb6da37963 Simplified parseInput method with new handleGetPost helper method. 2016-11-24 22:58:32 +01:00
Simon Sessingø abe427ff59 Development
- Optimised Input and Input-related features.
- Removed InputCollection class.
- Changed more foreach to for.
- Updated documentation.
2016-11-24 22:44:58 +01:00
Simon Sessingø 49fc991f9a Merge pull request #180 from skipperbent/v2-development
Updated documentation
2016-11-24 14:51:07 +02:00
Simon Sessingø b2f23c6c7d Updated documentation 2016-11-24 13:50:45 +01:00
Simon Sessingø 20353c6e4d Merge pull request #178 from skipperbent/v2-development
Updated documentation to use Demo instead of MyWebsite
2016-11-24 14:44:56 +02:00
Simon Sessingø 53ece9a7fd Updated documentation to use Demo instead of MyWebsite 2016-11-24 13:44:20 +01:00
Simon Sessingø 4c62f86a26 Merge pull request #176 from skipperbent/v2-development
Fixed HttpException not thrown as NotFoundHttpException
2016-11-24 13:18:52 +02:00
Simon Sessingø 132cf1a10d Fixed HttpException not thrown as NotFoundHttpException 2016-11-24 12:17:47 +01:00
Simon Sessingø 6445746324 Merge pull request #174 from skipperbent/v2-development
Optimisations + bugfixes
2016-11-24 11:05:57 +02:00
Simon Sessingø ff1f027bda Make sure parameter-modifier is found before parsing parameters. 2016-11-24 10:04:47 +01:00
Simon Sessingø 9418d54c8e No need to return getValue as it will be returned on render. 2016-11-24 09:56:21 +01:00
Simon Sessingø e4ab14a2cb Ensure that setError is always int. 2016-11-24 09:42:37 +01:00
Simon Sessingø 258e0e0f13 Optimisations + bugfixes 2016-11-24 09:36:10 +01:00
Simon Sessingø 1a2921acb4 Merge pull request #173 from skipperbent/v2-development
Development
2016-11-21 09:30:58 +02:00
Simon Sessingø f1a9a50ee5 Development
- Only add $_GET param is every other parameter is null when calling getUrl.
2016-11-21 08:29:26 +01:00
Simon Sessingø 258d9d05c7 Merge pull request #171 from skipperbent/v2-development
Enhancements
2016-11-21 09:04:22 +02:00
Simon Sessingø 2cc97c120f Enhancements
- Added example on how to get current url in documentation.
- Fixed so urls always ends with /.
2016-11-21 07:56:37 +01:00
48 changed files with 4356 additions and 3946 deletions
+720 -303
View File
File diff suppressed because it is too large Load Diff
-100
View File
@@ -1,100 +0,0 @@
# Simple PHP router demo project
This project is here to give you a basic understanding of how to setup and using simple-php-router.
Please note that this demo-project only covers how to integrate the `simple-php-router` in a project without a framework. If you are using some sort of PHP framework in your project the implementation might vary.
**What we won't cover:**
- How to setup a solution that fits your need. This is a basic demo to help you get started.
- Understanding of MVC; including Controllers, Middlewares or ExceptionHandlers.
- How to integrate into third party frameworks.
**What we cover:**
- How to get up and running fast - from scratch.
- How to get ExceptionHandlers, Middlewares and Controllers working.
- How to setup your webservers.
## Installation
- Navigate to the `demo-project` folder in terminal and run `composer update` to install the latest version.
- Point your webserver to `demo-project/public`.
### Setting up Nginx
If you are using Nginx please make sure that url-rewriting is enabled.
You can easily enable url-rewriting by adding the following configuration for the Nginx configuration-file for the demo-project.
```
location / {
try_files $uri $uri/ /index.php?$query_string;
}
```
### Setting up Apache
Nothing special is required for Apache to work. We've include the `.htaccess` file in the `public` folder. If rewriting is not working for you, please check that the `mod_rewrite` module (htaccess support) is enabled in the Apache configuration.
## Folder structure
| Folder | Description |
| ------------- |-------------|
| app |Contains projects-specific PHP classes|
| public |Public folder which are accessible through the web.|
## Notes
The demo project has it's own `Router` class implementation which extends the `SimpleRouter` class with further functionality.
This class can be useful adding additional functionality that are required before and after routing occurs or any extra functionality belonging to the router itself.
In this project we also use our custom router-class to autoload the `routes.php` file from our custom location (`app/routes.php`).
Please check the `routes.php` file in `demo-project/app` for all the urls/rules available in the project.
### CSRF-verifier
For the purpose of this demo, we've added a custom CSRF-verifier middleware called `CsrfVerifier` and disabled CSRF checks for all calls to `/api/*`. This will ensure that CSRF form-checks are not applied when calling our demo api url.
### Exception handlers
The included `CustomExceptionHandler` class returns a very basic json response for errors received on calls to `/api/*` or otherwise just a simple formatted error response.
### Middlewares
`ApiVerification` class is added to all calls to `/api/*`. This simple class just adds some data to the `Request` object, which is returned in one of the methods in the `ApiController` class. We've added this class to demonstrate that you can use middlewares to ensure that the user has the correct authentication - before router loads the controller itself.
### Urls
Please see `routes.php` for all routes and rules.
| URL |
| ------------- |
| / |
| /api/demo |
| /companies |
| /companies/[id] |
| /contact |
## The MIT License (MIT)
Copyright (c) 2016 Simon Sessingø / simple-php-router
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -1,16 +0,0 @@
<?php
namespace Demo\Controllers;
class ApiController
{
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,27 +0,0 @@
<?php
namespace Demo\Controllers;
class DefaultController
{
public function index()
{
// implement
echo sprintf('DefaultController -> index (?fun=%s)', input()->get('fun'));
}
public function contact()
{
echo 'DefaultController -> contact';
}
public function companies($id = null)
{
echo 'DefaultController -> companies -> id: ' . $id;
}
public function notFound()
{
echo 'Page not found';
}
}
@@ -1,44 +0,0 @@
<?php
namespace Demo\Handlers;
use Pecee\Handlers\IExceptionHandler;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
use Pecee\SimpleRouter\Route\ILoadableRoute;
class CustomExceptionHandler implements IExceptionHandler
{
public function handleError(Request $request, ILoadableRoute &$route = null, \Exception $error)
{
/* You can use the exception handler to format errors depending on the request and type. */
if (stripos($request->getUri(), '/api') !== false) {
response()->json([
'error' => $error->getMessage(),
'code' => $error->getCode(),
]);
}
/* The router will throw the NotFoundHttpException on 404 */
if($error instanceof NotFoundHttpException) {
/*
* Render your own custom 404-view, rewrite the request to another route,
* or simply return the $request object to ignore the error and continue on rendering the route.
*
* The code below will make the router render our page.notfound route.
*/
$request->setUri(url('page.notfound'));
return $request;
}
throw $error;
}
}
@@ -1,18 +0,0 @@
<?php
namespace Demo\Middlewares;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Route\ILoadableRoute;
class ApiVerification implements IMiddleware
{
public function handle(Request $request, ILoadableRoute &$route)
{
// Do authentication
$request->authenticated = true;
return $request;
}
}
@@ -1,13 +0,0 @@
<?php
namespace Demo\Middlewares;
use Pecee\Http\Middleware\BaseCsrfVerifier;
class CsrfVerifier extends BaseCsrfVerifier
{
/**
* CSRF validation will be ignored on the following urls.
*/
protected $except = ['/api/*'];
}
-26
View File
@@ -1,26 +0,0 @@
<?php
/**
* Custom router which handles default middlewares, default exceptions and things
* that should be happen before and after the router is initialised.
*/
namespace Demo;
use Pecee\SimpleRouter\SimpleRouter;
class Router extends SimpleRouter
{
public static function start($defaultNamespace = null)
{
// Load our helpers
require_once 'helpers.php';
// Load our custom routes
require_once 'routes.php';
parent::setDefaultNamespace('\Demo');
// Do initial stuff
parent::start();
}
}
-44
View File
@@ -1,44 +0,0 @@
<?php
use Pecee\SimpleRouter\SimpleRouter;
function url($controller, $parameters = null, $getParams = null)
{
SimpleRouter::getUrl($controller, $parameters, $getParams);
}
/**
* Get current csrf-token
* @return null|string
*/
function csrf_token()
{
$token = new \Pecee\CsrfToken();
return $token->getToken();
}
/**
* Get request object
* @return \Pecee\Http\Request
*/
function request()
{
return SimpleRouter::request();
}
/**
* Get response object
* @return \Pecee\Http\Response
*/
function response()
{
return SimpleRouter::response();
}
/**
* Get input class
* @return \Pecee\Http\Input\Input
*/
function input()
{
return SimpleRouter::request()->getInput();
}
-25
View File
@@ -1,25 +0,0 @@
<?php
/**
* This file contains all the routes for the project
*/
use Demo\Router;
Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
Router::group(['exceptionHandler' => 'Demo\Handlers\CustomExceptionHandler'], function () {
Router::get('/', 'DefaultController@index')->setName('home');
Router::get('/contact', 'DefaultController@contact')->setName('contact');
Router::get('/404', 'DefaultController@notFound')->setName('404');
Router::basic('/companies/{id?}', 'DefaultController@companies')->setName('companies');
// Api
Router::group(['prefix' => '/api', 'middleware' => 'Demo\Middlewares\ApiVerification'], function () {
Router::resource('/demo', 'ApiController');
});
});
-26
View File
@@ -1,26 +0,0 @@
{
"name": "pecee/simple-router-demo",
"description": "Simple router demo project",
"keywords": [
"simple-router",
"php",
"php-simple-router"
],
"license": "MIT",
"type": "project",
"require": {
"php": ">=5.4.0",
"pecee/simple-router": "2.*"
},
"require-dev": {
},
"config": {
"preferred-install": "dist"
},
"autoload": {
"psr-4": {
"Demo\\": "app/"
}
}
}
-5
View File
@@ -1,5 +0,0 @@
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(.*)$ index.php/$1
-7
View File
@@ -1,7 +0,0 @@
<?php
// load composer dependencies
require '../vendor/autoload.php';
// Start the routing
\Demo\Router::start();
+35 -34
View File
@@ -1,46 +1,47 @@
<?php
namespace Pecee\Controllers;
interface IRestController {
interface IRestController
{
/**
* @return void
*/
function index();
/**
* @return void
*/
public function index();
/**
* @param mixed $id
* @return void
*/
function show($id);
/**
* @param mixed $id
* @return void
*/
public function show($id);
/**
* @return void
*/
function store();
/**
* @return void
*/
public function store();
/**
* @return void
*/
function create();
/**
* @return void
*/
public function create();
/**
* View
* @param mixed $id
* @return void
*/
function edit($id);
/**
* View
* @param mixed $id
* @return void
*/
public function edit($id);
/**
* @param mixed $id
* @return void
*/
function update($id);
/**
* @param mixed $id
* @return void
*/
public function update($id);
/**
* @param mixed $id
* @return void
*/
function destroy($id);
/**
* @param mixed $id
* @return void
*/
public function destroy($id);
}
+58 -55
View File
@@ -3,66 +3,69 @@ namespace Pecee;
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
*
* @return string
*/
public static function generateToken()
{
if (function_exists('random_bytes')) {
return bin2hex(random_bytes(32));
}
/**
* Validate valid CSRF token
*
* @param string $token
* @return bool
*/
public function validate($token)
{
if ($token !== null && $this->getToken() !== null) {
return hash_equals($token, $this->getToken());
}
return false;
}
return bin2hex(openssl_random_pseudo_bytes(32));
}
/**
* Set csrf token cookie
*
* @param $token
*/
public function setToken($token)
{
setcookie(static::CSRF_KEY, $token, time() + 60 * 120, '/');
}
/**
* Validate valid CSRF token
*
* @param string $token
* @return bool
*/
public function validate($token)
{
if ($token !== null && $this->getToken() !== null) {
return hash_equals($token, $this->getToken());
}
/**
* Get csrf token
* @return string|null
*/
public function getToken()
{
if ($this->hasToken()) {
return $_COOKIE[static::CSRF_KEY];
}
return null;
}
return false;
}
/**
* Returns whether the csrf token has been defined
* @return bool
*/
public function hasToken()
{
return isset($_COOKIE[static::CSRF_KEY]);
}
/**
* Set csrf token cookie
*
* @param $token
*/
public function setToken($token)
{
setcookie(static::CSRF_KEY, $token, time() + 60 * 120, '/');
}
/**
* Get csrf token
* @return string|null
*/
public function getToken()
{
if ($this->hasToken()) {
return $_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]);
}
}
+7 -7
View File
@@ -6,12 +6,12 @@ use Pecee\SimpleRouter\Route\ILoadableRoute;
interface IExceptionHandler
{
/**
* @param Request $request
* @param ILoadableRoute $route
* @param \Exception $error
* @return Request|null
*/
public function handleError(Request $request, ILoadableRoute &$route = null, \Exception $error);
/**
* @param Request $request
* @param ILoadableRoute $route
* @param \Exception $error
* @return Request|null
*/
public function handleError(Request $request, ILoadableRoute &$route = null, \Exception $error);
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace Pecee\Http\Input;
interface IInputItem
{
public function getIndex();
public function setIndex($index);
public function getName();
public function setName($name);
public function __toString();
}
+242 -158
View File
@@ -5,207 +5,291 @@ use Pecee\Http\Request;
class Input
{
/**
* @var \Pecee\Http\Input\InputCollection
*/
public $get;
/**
* @var array
*/
public $get = [];
/**
* @var \Pecee\Http\Input\InputCollection
*/
public $post;
/**
* @var array
*/
public $post = [];
/**
* @var \Pecee\Http\Input\InputCollection
*/
public $file;
/**
* @var array
*/
public $file = [];
/**
* @var Request
*/
protected $request;
/**
* @var Request
*/
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
$this->setGet();
$this->setPost();
$this->setFile();
}
public function __construct(Request $request)
{
$this->request = $request;
/**
* Get all get/post items
* @param array|null $filter Only take items in filter
* @return array
*/
public function all(array $filter = null)
{
$output = $_POST;
$this->parseInputs();
}
if ($this->request->getMethod() === 'post') {
public function parseInputs()
{
/* Parse get requests */
if (count($_GET) > 0) {
$this->get = $this->handleGetPost($_GET);
}
$contents = file_get_contents('php://input');
/* Parse post requests */
$postVars = $_POST;
if (stripos(trim($contents), '{') === 0) {
$output = json_decode($contents, true);
if ($output === false) {
$output = array();
}
}
}
if (in_array($this->request->getMethod(), ['put', 'patch', 'delete'], false) === true) {
parse_str(file_get_contents('php://input'), $postVars);
}
$output = array_merge($_GET, $output);
if (count($postVars) > 0) {
$this->post = $this->handleGetPost($postVars);
}
if ($filter !== null) {
$output = array_filter($output, function ($key) use ($filter) {
if (in_array($key, $filter)) {
return true;
}
/* Parse get requests */
if (count($_FILES) > 0) {
$this->file = $this->parseFiles();
}
}
return false;
}, ARRAY_FILTER_USE_KEY);
}
public function parseFiles()
{
$list = [];
return $output;
}
foreach ($_FILES as $key => $value) {
public function getObject($index, $default = null)
{
$key = (strpos($index, '[') > -1) ? substr($index, strpos($index, '[') + 1, strpos($index, ']') - strlen($index)) : null;
$index = (strpos($index, '[') > -1) ? substr($index, 0, strpos($index, '[')) : $index;
// Handle array input
if (is_array($value['name']) === false) {
$values['index'] = $key;
$list[$key] = InputFile::createFromArray(array_merge($value, $values));
continue;
}
$element = $this->get->findFirst($index);
$keys = [];
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
$files = $this->rearrangeFiles($value['name'], $keys, $value);
if ($this->request->getMethod() !== 'get') {
if (isset($list[$key])) {
$list[$key][] = $files;
} else {
$list[$key] = $files;
}
$element = $this->post->findFirst($index);
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
}
$element = $this->file->findFirst($index);
if ($element !== null) {
return ($key !== null) ? $element[$key] : $element;
}
}
return $list;
}
return $default;
}
protected function rearrangeFiles(array $values, &$index, $original)
{
/**
* 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);
$output = [];
if ($item !== null) {
$getItem = function ($key, $property = 'name') use ($original, $index) {
if ($item instanceof InputCollection || $item instanceof InputFile) {
return $item;
}
$path = $original[$property];
return (trim($item->getValue()) === '') ? $default : $item->getValue();
}
foreach (array_values($index) as $i) {
$path = $path[$i];
}
return $default;
}
return $path[$key];
};
public function exists($index)
{
return ($this->getObject($index) !== null);
}
foreach ($values as $key => $value) {
public function setGet()
{
$this->get = new InputCollection();
if (is_array($getItem($key)) === false) {
if (count($_GET) > 0) {
foreach ($_GET as $key => $get) {
if (is_array($get) === false) {
$this->get->{$key} = new InputItem($key, $get);
continue;
}
$file = InputFile::createFromArray([
'index' => $key,
'error' => $getItem($key, 'error'),
'tmp_name' => $getItem($key, 'tmp_name'),
'type' => $getItem($key, 'type'),
'size' => $getItem($key, 'size'),
'filename' => $getItem($key, 'name'),
]);
$output = new InputCollection();
if (isset($output[$key])) {
$output[$key][] = $file;
} else {
$output[$key] = $file;
}
foreach ($get as $k => $g) {
$output->{$k} = new InputItem($k, $g);
}
continue;
}
$this->get->{$key} = $output;
}
}
}
$index[] = $key;
public function setPost()
{
$this->post = new InputCollection();
$files = $this->rearrangeFiles($value, $index, $original);
$postVars = $_POST;
if (isset($output[$key])) {
$output[$key][] = $files;
} else {
$output[$key] = $files;
}
if (in_array($this->request->getMethod(), ['put', 'patch', 'delete']) === true) {
parse_str(file_get_contents('php://input'), $postVars);
}
}
if (count($postVars) > 0) {
return $output;
}
foreach ($postVars as $key => $post) {
if (is_array($post) === false) {
$this->post->{strtolower($key)} = new InputItem($key, $post);
continue;
}
protected function handleGetPost(array $array)
{
$list = [];
$output = new InputCollection();
$max = count($array) - 1;
$keys = array_keys($array);
foreach ($post as $k => $p) {
$output->{$k} = new InputItem($k, $p);
}
for ($i = $max; $i >= 0; $i--) {
$this->post->{strtolower($key)} = $output;
}
}
}
$key = $keys[$i];
$value = $array[$key];
public function setFile()
{
$this->file = new InputCollection();
// Handle array input
if (is_array($value) === false) {
$list[$key] = new InputItem($key, $value);
continue;
}
if (count($_FILES) > 0) {
foreach ($_FILES as $key => $values) {
$output = $this->handleGetPost($value);
// Handle array input
if (is_array($values['name']) === false && trim($values['error']) !== '4') {
$values['index'] = $key;
$this->file->{strtolower($key)} = InputFile::createFromArray($values);
continue;
}
$list[$key] = $output;
}
$output = new InputCollection();
return $list;
}
foreach ($values['name'] as $k => $val) {
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]
]);
}
}
/**
* Find post-value by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputItem|string
*/
public function findPost($index, $defaultValue = null)
{
return isset($this->post[$index]) ? $this->post[$index] : $defaultValue;
}
$this->file->{strtolower($key)} = $output;
}
}
}
/**
* Find file by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputFile|string
*/
public function findFile($index, $defaultValue = null)
{
return isset($this->file[$index]) ? $this->file[$index] : $defaultValue;
}
/**
* Find parameter/query-string by index or return default value.
*
* @param string $index
* @param string|null $defaultValue
* @return InputItem|string
*/
public function findGet($index, $defaultValue = null)
{
return isset($this->get[$index]) ? $this->get[$index] : $defaultValue;
}
/**
* Get input object
*
* @param string $index
* @param string|null $defaultValue
* @param array|string|null $methods
* @return IInputItem|string
*/
public function getObject($index, $defaultValue = null, $methods = null)
{
if ($methods !== null && is_string($methods) === true) {
$methods = [$methods];
}
$element = null;
if ($methods === null || in_array('get', $methods)) {
$element = $this->findGet($index);
}
if (($element === null && $methods === null) || ($methods !== null && in_array('post', $methods))) {
$element = $this->findPost($index);
}
if (($element === null && $methods === null) || ($methods !== null && in_array('file', $methods))) {
$element = $this->findFile($index);
}
return ($element !== null) ? $element : $defaultValue;
}
/**
* Get input element value matching index
*
* @param string $index
* @param string|null $defaultValue
* @param array|string|null $methods
* @return InputItem|string
*/
public function get($index, $defaultValue = null, $methods = null)
{
$input = $this->getObject($index, $defaultValue, $methods);
if ($input instanceof InputItem) {
return (trim($input->getValue()) === '') ? $defaultValue : $input->getValue();
}
return $input;
}
/**
* Check if a input-item exist
*
* @param string $index
* @return bool
*/
public function exists($index)
{
return ($this->getObject($index) !== null);
}
/**
* Get all get/post items
* @param array|null $filter Only take items in filter
* @return array
*/
public function all(array $filter = null)
{
$output = $_POST;
if ($this->request->getMethod() === 'post') {
$contents = file_get_contents('php://input');
if (strpos(trim($contents), '{') === 0) {
$output = json_decode($contents, true);
if ($output === false) {
$output = [];
}
}
}
$output = array_merge($_GET, $output);
if ($filter !== null) {
$output = array_filter($output, function ($key) use ($filter) {
return (in_array($key, $filter) === true);
}, ARRAY_FILTER_USE_KEY);
}
return $output;
}
}
-94
View File
@@ -1,94 +0,0 @@
<?php
namespace Pecee\Http\Input;
class InputCollection implements \IteratorAggregate
{
protected $data = array();
/**
* Search for input element matching index.
*
* @param string $index
* @param string|null $default
* @return InputItem|mixed
*/
public function findFirst($index, $default = null)
{
if (count($this->data) > 0) {
if (isset($this->data[$index])) {
return $this->data[$index];
}
foreach ($this->data as $key => $input) {
if (strtolower($index) === strtolower($key)) {
return $input;
}
}
}
return $default;
}
/**
* 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);
if($input !== null && trim($input->getValue()) !== '') {
return $input->getValue();
}
return $default;
}
public function getValue($index, $default = null) {
}
/**
* @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;
}
public function __set($index, $value)
{
$this->data[$index] = $value;
}
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>
* @since 5.0.0
*/
public function getIterator()
{
return new \ArrayIterator($this->data);
}
}
+248 -114
View File
@@ -1,136 +1,270 @@
<?php
namespace Pecee\Http\Input;
class InputFile extends InputItem
class InputFile implements IInputItem
{
public $size;
public $type;
public $error;
public $tmpName;
public $index;
public $name;
public $filename;
public $size;
public $type;
public $error;
public $tmpName;
/**
* @return string
*/
public function getSize()
{
return $this->size;
}
public function __construct($index)
{
$this->index = $index;
/**
* @return string
*/
public function getType()
{
return $this->type;
}
// Make the name human friendly, by replace _ with space
$this->name = ucfirst(str_replace('_', ' ', $this->index));
}
/**
* @return string
*/
public function getError()
{
return $this->error;
}
/**
* Create from array
*
* @param array $values
* @throws \InvalidArgumentException
* @return static
*/
public static function createFromArray(array $values)
{
if (!isset($values['index'])) {
throw new \InvalidArgumentException('Index key is required');
}
public function getMime()
{
return $this->getType();
}
/* Easy way of ensuring that all indexes-are set and not filling the screen with isset() */
/**
* @return string
*/
public function getTmpName()
{
return $this->tmpName;
}
$values = array_merge([
'tmp_name' => null,
'type' => null,
'size' => null,
'name' => null,
'error' => null,
], $values);
public function getExtension()
{
return pathinfo($this->getName(), PATHINFO_EXTENSION);
}
return (new static($values['index']))
->setError($values['error'])
->setSize($values['size'])
->setType($values['type'])
->setTmpName($values['tmp_name'])
->setFilename($values['name']);
public function move($destination)
{
return move_uploaded_file($this->tmpName, $destination);
}
}
public function getContents()
{
return file_get_contents($this->tmpName);
}
/**
* @return string
*/
public function getIndex()
{
return $this->index;
}
/**
* Set file temp. name
* @param string $name
* @return static $this
*/
public function setTmpName($name)
{
$this->tmpName = $name;
return $this;
}
/**
* Set input index
* @param string $index
* @return static $this
*/
public function setIndex($index)
{
$this->index = $index;
/**
* Set file size
* @param int $size
* @return static $this
*/
public function setSize($size)
{
$this->size = $size;
return $this;
}
return $this;
}
/**
* Set type
* @param string $type
* @return static $this
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* @return string
*/
public function getSize()
{
return $this->size;
}
/**
* Set error
* @param int $error
* @return static $this
*/
public function setError($error)
{
$this->error = $error;
return $this;
}
/**
* Set file size
* @param int $size
* @return static $this
*/
public function setSize($size)
{
$this->size = $size;
/**
* 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');
}
return $this;
}
$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));
/**
* Get mime-type of file
* @return string
*/
public function getMime()
{
return $this->getType();
}
return $input;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return string
*/
public function getValue()
{
return $this->tmpName;
}
/**
* Set type
* @param string $type
* @return static $this
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Returns extension without "."
*
* @return string
*/
public function getExtension()
{
return pathinfo($this->getName(), PATHINFO_EXTENSION);
}
/**
* Get human friendly name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set human friendly name.
* Useful for adding validation etc.
*
* @param string $name
* @return static $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Set filename
*
* @param string $name
* @return static $this
*/
public function setFilename($name)
{
$this->filename = $name;
return $this;
}
/**
* Get filename
*
* @return string mixed
*/
public function getFilename()
{
return $this->filename;
}
/**
* Move the uploaded temporary file to it's new home
*
* @param string $destination
* @return bool
*/
public function move($destination)
{
return move_uploaded_file($this->tmpName, $destination);
}
/**
* Get file contents
*
* @return string
*/
public function getContents()
{
return file_get_contents($this->tmpName);
}
/**
* Return true if an upload error occured.
*
* @return bool
*/
public function hasError()
{
return ($this->getError() !== 0);
}
/**
* Get upload-error code.
*
* @return string
*/
public function getError()
{
return $this->error;
}
/**
* Set error
*
* @param int $error
* @return static $this
*/
public function setError($error)
{
$this->error = (int)$error;
return $this;
}
/**
* @return string
*/
public function getTmpName()
{
return $this->tmpName;
}
/**
* Set file temp. name
* @param string $name
* @return static $this
*/
public function setTmpName($name)
{
$this->tmpName = $name;
return $this;
}
public function __toString()
{
return $this->getTmpName();
}
public function toArray()
{
return [
'tmp_name' => $this->tmpName,
'type' => $this->type,
'size' => $this->size,
'name' => $this->filename,
'error' => $this->error,
];
}
}
+65 -56
View File
@@ -1,70 +1,79 @@
<?php
namespace Pecee\Http\Input;
class InputItem
class InputItem implements IInputItem
{
public $index;
public $name;
public $value;
public $index;
public $name;
public $value;
public function __construct($index, $value = null)
{
$this->index = $index;
$this->value = $value;
public function __construct($index, $value = null)
{
$this->index = $index;
$this->value = $value;
// Make the name human friendly, by replace _ with space
$this->name = ucfirst(str_replace('_', ' ', $this->index));
}
// Make the name human friendly, by replace _ with space
$this->name = ucfirst(str_replace('_', ' ', $this->index));
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getIndex()
{
return $this->index;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
public function setIndex($index)
{
$this->index = $index;
/**
* @return string
*/
public function getIndex()
{
return $this->index;
}
return $this;
}
/**
* Set input name
* @param string $name
* @return static $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set input value
* @param string $value
* @return static $this
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* Set input name
* @param string $name
* @return static $this
*/
public function setName($name)
{
$this->name = $name;
public function __toString()
{
return (string)$this->value;
}
return $this;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* Set input value
* @param string $value
* @return static $this
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
public function __toString()
{
return (string)$this->value;
}
}
+71 -66
View File
@@ -2,94 +2,99 @@
namespace Pecee\Http\Middleware;
use Pecee\CsrfToken;
use Pecee\Exceptions\TokenMismatchException;
use Pecee\Http\Middleware\Exceptions\TokenMismatchException;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Route\ILoadableRoute;
class BaseCsrfVerifier implements IMiddleware
{
const POST_KEY = 'csrf-token';
const HEADER_KEY = 'X-CSRF-TOKEN';
const POST_KEY = 'csrf-token';
const HEADER_KEY = 'X-CSRF-TOKEN';
protected $except;
protected $csrfToken;
protected $token;
protected $except;
protected $csrfToken;
protected $token;
public function __construct()
{
$this->csrfToken = new CsrfToken();
public function __construct()
{
$this->csrfToken = new CsrfToken();
// Generate or get the CSRF-Token from Cookie.
$this->token = (!$this->hasToken()) ? $this->generateToken() : $this->csrfToken->getToken();
}
// Generate or get the CSRF-Token from Cookie.
$this->token = ($this->hasToken() === false) ? $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;
}
/**
* 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) {
$url = rtrim($url, '/');
if ($url[strlen($url) - 1] === '*') {
$url = rtrim($url, '*');
$skip = (stripos($request->getUri(), $url) === 0);
} else {
$skip = ($url === rtrim($request->getUri(), '/'));
}
$max = count($this->except) - 1;
if ($skip) {
return true;
}
}
for ($i = $max; $i >= 0; $i--) {
$url = $this->except[$i];
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(), '/'));
}
public function handle(Request $request, ILoadableRoute &$route = null)
{
if ($skip === true) {
return true;
}
}
if ($request->getMethod() !== 'get' && !$this->skip($request)) {
return false;
}
$token = $request->getInput()->post->get(static::POST_KEY);
public function handle(Request $request, ILoadableRoute &$route = null)
{
// If the token is not posted, check headers for valid x-csrf-token
if ($token === null) {
$token = $request->getHeader(static::HEADER_KEY);
}
if ($this->skip($request) === false && in_array($request->getMethod(), ['post', 'put', 'delete'], false) === true) {
if (!$this->csrfToken->validate($token)) {
throw new TokenMismatchException('Invalid csrf-token.');
}
$token = $request->getInput()->get(static::POST_KEY, null, 'post');
}
// 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) === false) {
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;
}
}
return $this->csrfToken->hasToken();
}
public function generateToken()
{
$token = CsrfToken::generateToken();
$this->csrfToken->setToken($token);
public function getToken()
{
return $this->token;
}
return $token;
}
public function hasToken()
{
if ($this->token !== null) {
return true;
}
return $this->csrfToken->hasToken();
}
public function getToken()
{
return $this->token;
}
}
@@ -1,5 +1,5 @@
<?php
namespace Pecee\Exceptions;
namespace Pecee\Http\Middleware\Exceptions;
class TokenMismatchException extends \Exception
{
+6 -6
View File
@@ -6,11 +6,11 @@ use Pecee\SimpleRouter\Route\ILoadableRoute;
interface IMiddleware
{
/**
* @param Request $request
* @param ILoadableRoute $route
* @return Request|null
*/
public function handle(Request $request, ILoadableRoute &$route);
/**
* @param Request $request
* @param ILoadableRoute $route
* @return Request|null
*/
public function handle(Request $request, ILoadableRoute &$route);
}
+197 -172
View File
@@ -5,202 +5,227 @@ use Pecee\Http\Input\Input;
class Request
{
protected $data = array();
protected $headers;
protected $host;
protected $uri;
protected $method;
protected $input;
protected $data = [];
protected $headers;
protected $host;
protected $uri;
protected $method;
protected $input;
public function __construct()
{
$this->parseHeaders();
$this->input = new Input($this);
$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()
{
$this->parseHeaders();
$this->host = $this->getHeader('http-host');
$this->uri = $this->getHeader('request-uri');
$this->input = new Input($this);
$this->method = strtolower($this->input->get('_method', $this->getHeader('request-method'), 'post'));
}
protected function parseHeaders()
{
$this->headers = array();
protected function parseHeaders()
{
$this->headers = [];
foreach ($_SERVER as $name => $value) {
$this->headers[strtolower($name)] = $value;
$this->headers[strtolower(str_replace('_', '-', $name))] = $value;
}
}
$max = count($_SERVER) - 1;
$keys = array_keys($_SERVER);
public function isSecure()
{
if ($this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || $this->getHeader('server-port') === 443) {
return true;
}
for ($i = $max; $i >= 0; $i--) {
$key = $keys[$i];
$value = $_SERVER[$key];
return false;
}
$this->headers[strtolower($key)] = $value;
$this->headers[strtolower(str_replace('_', '-', $key))] = $value;
}
/**
* @return string
*/
public function getUri()
{
return $this->uri;
}
}
/**
* @return string
*/
public function getHost()
{
return $this->host;
}
public function isSecure()
{
return $this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || $this->getHeader('server-port') === 443;
}
/**
* @return string
*/
public function getMethod()
{
return $this->method;
}
/**
* @return string
*/
public function getUri()
{
return $this->uri;
}
/**
* Get http basic auth user
* @return string|null
*/
public function getUser()
{
return $this->getHeader('php-auth-user');
}
/**
* @return string
*/
public function getHost()
{
return $this->host;
}
/**
* Get http basic auth password
* @return string|null
*/
public function getPassword()
{
return $this->getHeader('php-auth-pw');
}
/**
* @return string
*/
public function getMethod()
{
return $this->method;
}
/**
* Get all headers
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
/**
* Get http basic auth user
* @return string|null
*/
public function getUser()
{
return $this->getHeader('php-auth-user');
}
/**
* Get id address
* @return string
*/
public function getIp()
{
if ($this->getHeader('http-cf-connecting-ip') !== null) {
return $this->getHeader('http-cf-connecting-ip');
}
/**
* Get http basic auth password
* @return string|null
*/
public function getPassword()
{
return $this->getHeader('php-auth-pw');
}
if ($this->getHeader('http-x-forwarded-for') !== null && strlen($this->getHeader('http-x-forwarded-for'))) {
return $this->getHeader('http-x-forwarded_for');
}
/**
* Get all headers
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
return $this->getHeader('remote-addr');
}
/**
* Get id address
* @return string
*/
public function getIp()
{
if ($this->getHeader('http-cf-connecting-ip') !== null) {
return $this->getHeader('http-cf-connecting-ip');
}
/**
* Get referer
* @return string
*/
public function getReferer()
{
return $this->getHeader('http-referer');
}
if ($this->getHeader('http-x-forwarded-for') !== null) {
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
* @return string
*/
public function getReferer()
{
return $this->getHeader('http-referer');
}
/**
* Get input class
* @return Input
*/
public function getInput()
{
return $this->input;
}
/**
* Get user agent
* @return string
*/
public function getUserAgent()
{
return $this->getHeader('http-user-agent');
}
/**
* Is format accepted
*
* @param string $format
*
* @return bool
*/
public function isFormatAccepted($format)
{
return ($this->getHeader('http-accept') !== null && stripos($this->getHeader('http-accept'), $format) > -1);
}
/**
* Get header value by name
*
* @param string $name
* @param string|null $defaultValue
*
* @return string|null
*/
public function getHeader($name, $defaultValue = null)
{
if (isset($this->headers[strtolower($name)])) {
return $this->headers[strtolower($name)];
}
/**
* Get accept formats
* @return array
*/
public function getAcceptFormats()
{
return explode(',', $this->getHeader('http-accept'));
}
$max = count($_SERVER) - 1;
$keys = array_keys($_SERVER);
/**
* @param string $uri
*/
public function setUri($uri)
{
$this->uri = $uri;
}
for ($i = $max; $i >= 0; $i--) {
/**
* @param string $host
*/
public function setHost($host)
{
$this->host = $host;
}
$key = $keys[$i];
$name = $_SERVER[$key];
/**
* @param string $method
*/
public function setMethod($method)
{
$this->method = $method;
}
if ($key === $name) {
return $name;
}
}
public function __set($name, $value = null)
{
$this->data[$name] = $value;
}
return $defaultValue;
}
public function __get($name)
{
return isset($this->data[$name]) ? $this->data[$name] : null;
}
/**
* Get input class
* @return Input
*/
public function getInput()
{
return $this->input;
}
/**
* Is format accepted
*
* @param string $format
*
* @return bool
*/
public function isFormatAccepted($format)
{
return ($this->getHeader('http-accept') !== null && stripos($this->getHeader('http-accept'), $format) > -1);
}
/**
* Get accept formats
* @return array
*/
public function getAcceptFormats()
{
return explode(',', $this->getHeader('http-accept'));
}
/**
* @param string $uri
*/
public function setUri($uri)
{
$this->uri = $uri;
}
/**
* @param string $host
*/
public function setHost($host)
{
$this->host = $host;
}
/**
* @param string $method
*/
public function setMethod($method)
{
$this->method = $method;
}
public function __isset($name)
{
return array_key_exists($name, $this->data);
}
public function __set($name, $value = null)
{
$this->data[$name] = $value;
}
public function __get($name)
{
return isset($this->data[$name]) ? $this->data[$name] : null;
}
}
+99 -96
View File
@@ -3,116 +3,119 @@ namespace Pecee\Http;
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
*
* @param int $code
* @return static
*/
public function httpCode($code)
{
http_response_code($code);
/**
* Redirect the response
*
* @param string $url
* @param int $httpCode
*/
public function redirect($url, $httpCode = null)
{
if ($httpCode !== null) {
$this->httpCode($httpCode);
}
return $this;
}
$this->header('location: ' . $url);
die();
}
/**
* Redirect the response
*
* @param string $url
* @param int $httpCode
*/
public function redirect($url, $httpCode = null)
{
if ($httpCode !== null) {
$this->httpCode($httpCode);
}
public function refresh()
{
$this->redirect($this->request->getUri());
}
$this->header('location: ' . $url);
die();
}
/**
* 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 refresh()
{
$this->redirect($this->request->getUri());
}
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',
]);
$this->headers([
'Cache-Control: public',
'Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModified) . ' GMT',
'Etag: ' . $eTag
]);
return $this;
}
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $lastModified ||
isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $eTag
) {
public function cache($eTag, $lastModified = 2592000)
{
$this->headers([
'HTTP/1.1 304 Not Modified'
]);
$this->headers([
'Cache-Control: public',
'Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT',
'Etag: ' . $eTag,
]);
exit();
}
$httpModified = $this->request->getHeader('http-if-modified-since');
$httpIfNoneMatch = $this->request->getHeader('http-if-none-match');
return $this;
}
if (($httpIfNoneMatch !== null && $httpIfNoneMatch === $eTag) || ($httpModified !== null && strtotime($httpModified) === $lastModified)) {
/**
* Json encode array
* @param array $value
*/
public function json(array $value)
{
$this->header('Content-type: application/json');
echo json_encode($value);
die();
}
$this->header('HTTP/1.1 304 Not Modified');
/**
* Add header to response
* @param string $value
* @return static
*/
public function header($value)
{
header($value);
return $this;
}
exit();
}
/**
* Add multiple headers to response
* @param array $headers
* @return static
*/
public function headers(array $headers)
{
foreach ($headers as $header) {
header($header);
}
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();
}
/**
* Add header to response
* @param string $value
* @return static
*/
public function header($value)
{
header($value);
return $this;
}
/**
* Add multiple headers to response
* @param array $headers
* @return static
*/
public function headers(array $headers)
{
foreach ($headers as $header) {
$this->header($header);
}
return $this;
}
}
@@ -5,11 +5,11 @@ use Pecee\Http\Request;
interface IRouterBootManager
{
/**
* Called when router loads it's routes
*
* @param Request $request
* @return Request
*/
public function boot(Request $request);
/**
* Called when router loads it's routes
*
* @param Request $request
* @return Request
*/
public function boot(Request $request);
}
@@ -3,34 +3,34 @@ namespace Pecee\SimpleRouter\Route;
interface IControllerRoute extends IRoute
{
/**
* Get controller class-name
*
* @return string
*/
public function getController();
/**
* Get controller class-name
*
* @return string
*/
public function getController();
/**
* Set controller class-name
*
* @param string $controller
* @return static
*/
public function setController($controller);
/**
* Set controller class-name
*
* @param string $controller
* @return static
*/
public function setController($controller);
/**
* Return active method
*
* @return string
*/
public function getMethod();
/**
* Return active method
*
* @return string
*/
public function getMethod();
/**
* Set active method
*
* @param string $method
* @return static
*/
public function setMethod($method);
/**
* Set active method
*
* @param string $method
* @return static
*/
public function setMethod($method);
}
+46 -46
View File
@@ -5,56 +5,56 @@ use Pecee\Http\Request;
interface IGroupRoute extends IRoute
{
/**
* Method called to check if a domain matches
*
* @param Request $request
* @return bool
*/
public function matchDomain(Request $request);
/**
* Method called to check if a domain matches
*
* @param Request $request
* @return bool
*/
public function matchDomain(Request $request);
/**
* Set exception-handlers for group
*
* @param array $handlers
* @return static $this
*/
public function setExceptionHandlers(array $handlers);
/**
* Set exception-handlers for group
*
* @param array $handlers
* @return static $this
*/
public function setExceptionHandlers(array $handlers);
/**
* Get exception-handlers for group
*
* @return array
*/
public function getExceptionHandlers();
/**
* Get exception-handlers for group
*
* @return array
*/
public function getExceptionHandlers();
/**
* Get domains for domain.
*
* @return array
*/
public function getDomains();
/**
* Get domains for domain.
*
* @return array
*/
public function getDomains();
/**
* Set allowed domains for group.
*
* @param array $domains
* @return $this
*/
public function setDomains(array $domains);
/**
* Set allowed domains for group.
*
* @param array $domains
* @return $this
*/
public function setDomains(array $domains);
/**
* Set prefix that child-routes will inherit.
*
* @param string $prefix
* @return string
*/
public function setPrefix($prefix);
/**
* Set prefix that child-routes will inherit.
*
* @param string $prefix
* @return string
*/
public function setPrefix($prefix);
/**
* Get prefix.
*
* @return string
*/
public function getPrefix();
/**
* Get prefix.
*
* @return string
*/
public function getPrefix();
}
+54 -39
View File
@@ -5,50 +5,65 @@ use Pecee\Http\Request;
interface ILoadableRoute extends IRoute
{
/**
* Find url that matches method, parameters or name.
* Used when calling the url() helper.
*
* @param string|null $method
* @param array|null $parameters
* @param string|null $name
* @return string
*/
public function findUrl($method = null, $parameters = null, $name = null);
/**
* Find url that matches method, parameters or name.
* Used when calling the url() helper.
*
* @param string|null $method
* @param array|null $parameters
* @param string|null $name
* @return string
*/
public function findUrl($method = null, $parameters = null, $name = null);
/**
* Loads and renders middlewares-classes
*
* @param Request $request
* @param ILoadableRoute $route
*/
public function loadMiddleware(Request $request, ILoadableRoute &$route);
/**
* Loads and renders middlewares-classes
*
* @param Request $request
* @param ILoadableRoute $route
*/
public function loadMiddleware(Request $request, ILoadableRoute $route);
public function getUrl();
public function getUrl();
public function setUrl($url);
public function setUrl($url);
/**
* Returns the provided name for the router.
*
* @return string
*/
public function getName();
/**
* Returns the provided name for the router.
*
* @return string
*/
public function getName();
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name);
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name);
/**
* Sets the router name, which makes it easier to obtain the url or router at a later point.
*
* @param string $name
* @return static $this
*/
public function setName($name);
/**
* Sets the router name, which makes it easier to obtain the url or router at a later point.
*
* @param string $name
* @return static $this
*/
public function setName($name);
/**
* Get regular expression match used for matching route (if defined).
*
* @return string
*/
public function getMatch();
/**
* Add regular expression match for the entire route.
*
* @param string $regex
* @return static
*/
public function setMatch($regex);
}
+150 -164
View File
@@ -5,195 +5,181 @@ use Pecee\Http\Request;
interface IRoute
{
/**
* Method called to check if a domain matches
*
* @param Request $request
* @return bool
*/
public function matchRoute(Request $request);
/**
* Method called to check if a domain matches
*
* @param Request $request
* @return bool
*/
public function matchRoute(Request $request);
/**
* Called when route is matched.
* Returns class to be rendered.
*
* @param Request $request
* @return object
*/
public function renderRoute(Request $request);
/**
* Called when route is matched.
* Returns class to be rendered.
*
* @param Request $request
* @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException
* @return void
*/
public function renderRoute(Request $request);
/**
* Returns callback name/identifier for the current route based on the callback.
* Useful if you need to get a unique identifier for the loaded route, for instance
* when using translations etc.
*
* @return string
*/
public function getIdentifier();
/**
* Returns callback name/identifier for the current route based on the callback.
* Useful if you need to get a unique identifier for the loaded route, for instance
* when using translations etc.
*
* @return string
*/
public function getIdentifier();
/**
* Set allowed request methods
*
* @param array $methods
* @return static $this
*/
public function setRequestMethods(array $methods);
/**
* Set allowed request methods
*
* @param array $methods
* @return static $this
*/
public function setRequestMethods(array $methods);
/**
* Get allowed request methods
*
* @return array
*/
public function getRequestMethods();
/**
* Get allowed request methods
*
* @return array
*/
public function getRequestMethods();
/**
* @return IRoute|null
*/
public function getParent();
/**
* @return IRoute|null
*/
public function getParent();
/**
* Get the group for the route.
*
* @return IGroupRoute|null
*/
public function getGroup();
/**
* Get the group for the route.
*
* @return IGroupRoute|null
*/
public function getGroup();
/**
* Set group
*
* @param IGroupRoute $group
* @return static $this
*/
public function setGroup(IGroupRoute $group);
/**
* Set group
*
* @param IGroupRoute $group
* @return static $this
*/
public function setGroup(IGroupRoute $group);
/**
* Set parent route
*
* @param IRoute $parent
* @return static $this
*/
public function setParent(IRoute $parent);
/**
* Set parent route
*
* @param IRoute $parent
* @return static $this
*/
public function setParent(IRoute $parent);
/**
* Set callback
*
* @param string $callback
* @return static
*/
public function setCallback($callback);
/**
* Set callback
*
* @param string $callback
* @return static
*/
public function setCallback($callback);
/**
* @return string
*/
public function getCallback();
/**
* @return string
*/
public function getCallback();
public function getMethod();
public function getMethod();
public function getClass();
public function getClass();
public function setMethod($method);
public function setMethod($method);
/**
* @param string $namespace
* @return static $this
*/
public function setNamespace($namespace);
/**
* @param string $namespace
* @return static $this
*/
public function setNamespace($namespace);
/**
* @return string
*/
public function getNamespace();
/**
* @return string
*/
public function getNamespace();
/**
* @param string $namespace
* @return static $this
*/
public function setDefaultNamespace($namespace);
/**
* @param string $namespace
* @return static $this
*/
public function setDefaultNamespace($namespace);
public function getDefaultNamespace();
public function getDefaultNamespace();
/**
* Get regular expression match used for matching route (if defined).
*
* @return string
*/
public function getMatch();
/**
* Get parameter names.
*
* @return array
*/
public function getWhere();
/**
* Add regular expression match for the entire route.
*
* @param string $regex
* @return static
*/
public function setMatch($regex);
/**
* Set parameter names.
*
* @param array $options
* @return static
*/
public function setWhere(array $options);
/**
* Get parameter names.
*
* @return array
*/
public function getWhere();
/**
* Get parameters
*
* @return array
*/
public function getParameters();
/**
* Set parameter names.
*
* @param array $options
* @return static
*/
public function setWhere(array $options);
/**
* Get parameters
*
* @param array $parameters
* @return static $this
*/
public function setParameters(array $parameters);
/**
* Get parameters
*
* @return array
*/
public function getParameters();
/**
* Merge with information from another route.
*
* @param array $settings
* @param bool $merge
* @return static $this
*/
public function setSettings(array $settings, $merge = false);
/**
* Get parameters
*
* @param array $parameters
* @return static $this
*/
public function setParameters(array $parameters);
/**
* Export route settings to array so they can be merged with another route.
*
* @return array
*/
public function toArray();
/**
* Merge with information from another route.
*
* @param array $settings
* @param bool $merge
* @return static $this
*/
public function setSettings(array $settings, $merge = false);
/**
* Get middlewares array
*
* @return array
*/
public function getMiddlewares();
/**
* Export route settings to array so they can be merged with another route.
*
* @return array
*/
public function toArray();
/**
* Set middleware class-name
*
* @param string $middleware
* @return static
*/
public function setMiddleware($middleware);
/**
* Get middlewares array
*
* @return array
*/
public function getMiddlewares();
/**
* Set middleware class-name
*
* @param string $middleware
* @return static
*/
public function setMiddleware($middleware);
/**
* Set middlewares array
*
* @param array $middlewares
* @return $this
*/
public function setMiddlewares(array $middlewares);
/**
* Set middlewares array
*
* @param array $middlewares
* @return $this
*/
public function setMiddlewares(array $middlewares);
}
+211 -143
View File
@@ -7,177 +7,245 @@ use Pecee\SimpleRouter\Exceptions\HttpException;
abstract class LoadableRoute extends Route implements ILoadableRoute
{
const PARAMETERS_REGEX_MATCH = '%s([\w\-\_]*?)\%s{0,1}%s';
/**
* @var string
*/
protected $url;
protected $url;
protected $name;
/**
* @var string
*/
protected $name;
/**
* Loads and renders middlewares-classes
*
* @param Request $request
* @param ILoadableRoute $route
* @throws HttpException
*/
public function loadMiddleware(Request $request, ILoadableRoute &$route)
{
if (count($this->getMiddlewares()) > 0) {
foreach ($this->getMiddlewares() as $middleware) {
protected $regex;
$middleware = $this->loadClass($middleware);
if (!($middleware instanceof IMiddleware)) {
throw new HttpException($middleware . ' must be instance of Middleware');
}
/**
* Loads and renders middlewares-classes
*
* @param Request $request
* @param ILoadableRoute $route
* @throws HttpException
*/
public function loadMiddleware(Request $request, ILoadableRoute $route)
{
if (count($this->getMiddlewares()) > 0) {
$middleware->handle($request, $route);
}
}
}
$max = count($this->getMiddlewares());
/**
* Set url
*
* @param string $url
* @return static
*/
public function setUrl($url)
{
$this->url = ($url === '/') ? '/' : '/' . trim($url, '/') . '/';
$regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
for ($i = 0; $i < $max; $i++) {
if (preg_match_all('/' . $regex . '/is', $this->url, $matches)) {
foreach ($matches[1] as $key) {
$this->parameters[$key] = null;
}
}
$middleware = $this->getMiddlewares()[$i];
return $this;
}
$middleware = $this->loadClass($middleware);
public function getUrl()
{
return $this->url;
}
if (!($middleware instanceof IMiddleware)) {
throw new HttpException($middleware . ' must be instance of Middleware');
}
/**
* Find url that matches method, parameters or name.
* Used when calling the url() helper.
*
* @param string|null $method
* @param array|null $parameters
* @param string|null $name
* @return string
*/
public function findUrl($method = null, $parameters = null, $name = null)
{
$url = '';
$middleware->handle($request, $route);
}
}
}
$parameters = (array)$parameters;
public function matchRegex(Request $request, $url)
{
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
$url .= '//' . $this->getGroup()->getDomains()[0];
}
/* Match on custom defined regular expression */
$url .= $this->getUrl();
if ($this->regex === null) {
return null;
}
$params = array_merge($this->getParameters(), $parameters);
$parameters = [];
/* Url that contains parameters that aren't recognized */
$unknownParams = [];
if (preg_match($this->regex, $request->getHost() . $url, $parameters) > 0) {
/* Create the param string - {} */
$param1 = $this->paramModifiers[0] . '%s' . $this->paramModifiers[1];
/* Remove global match */
$this->parameters = array_slice($parameters, 1);
/* Create the param string with the optional symbol - {?} */
$param2 = $this->paramModifiers[0] . '%s' . $this->paramOptionalSymbol . $this->paramModifiers[1];
return true;
}
/* Let's parse the values of any {} parameter in the url */
foreach ($params as $param => $value) {
$value = (isset($parameters[$param])) ? $parameters[$param] : $value;
return false;
}
if (stripos($url, $param1) !== false || stripos($url, $param) !== false) {
$url = str_ireplace([sprintf($param1, $param), sprintf($param2, $param)], $value, $url);
} else {
$unknownParams[$param] = $value;
}
}
/**
* Set url
*
* @param string $url
* @return static
*/
public function setUrl($url)
{
$this->url = ($url === '/') ? '/' : '/' . trim($url, '/') . '/';
$url .= join('/', $unknownParams);
if (strpos($this->url, $this->paramModifiers[0]) !== false) {
return rtrim($url, '/') . '/';
}
$regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
/**
* Returns the provided name for the router.
*
* @return string
*/
public function getName()
{
return $this->name;
}
if (preg_match_all('/' . $regex . '/is', $this->url, $matches)) {
$this->parameters = array_fill_keys($matches[1], null);
}
}
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name)
{
return (strtolower($this->name) === strtolower($name));
}
return $this;
}
/**
* Sets the router name, which makes it easier to obtain the url or router at a later point.
* Alias for LoadableRoute::setName().
*
* @see LoadableRoute::setName()
* @param string|array $name
* @return static
*/
public function name($name)
{
return $this->setName($name);
}
public function getUrl()
{
return $this->url;
}
/**
* Sets the router name, which makes it easier to obtain the url or router at a later point.
*
* @param string $name
* @return static $this
*/
public function setName($name)
{
$this->name = $name;
/**
* Find url that matches method, parameters or name.
* Used when calling the url() helper.
*
* @param string|null $method
* @param array|null $parameters
* @param string|null $name
* @return string
*/
public function findUrl($method = null, $parameters = null, $name = null)
{
$url = '';
return $this;
}
$parameters = (array)$parameters;
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['as'])) {
if ($this->name !== null && $merge !== false) {
$this->setName($values['as'] . '.' . $this->name);
} else {
$this->setName($values['as']);
}
}
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
$url .= '//' . $this->getGroup()->getDomains()[0];
}
if (isset($values['prefix'])) {
$this->setUrl($values['prefix'] . $this->getUrl());
}
$url .= $this->getUrl();
parent::setSettings($values, $merge);
$params = array_merge($this->getParameters(), $parameters);
return $this;
}
/* Url that contains parameters that aren't recognized */
$unknownParams = [];
/* Create the param string - {} */
$param1 = $this->paramModifiers[0] . '%s' . $this->paramModifiers[1];
/* Create the param string with the optional symbol - {?} */
$param2 = $this->paramModifiers[0] . '%s' . $this->paramOptionalSymbol . $this->paramModifiers[1];
/* Let's parse the values of any {} parameter in the url */
$max = count($params) - 1;
$keys = array_keys($params);
for ($i = $max; $i >= 0; $i--) {
$param = $keys[$i];
$value = $params[$param];
$value = isset($parameters[$param]) ? $parameters[$param] : $value;
if (stripos($url, $param1) !== false || stripos($url, $param) !== false) {
$url = str_ireplace([sprintf($param1, $param), sprintf($param2, $param)], $value, $url);
} else {
$unknownParams[$param] = $value;
}
}
/** @noinspection AliasFunctionsUsageInspection */
$url .= join('/', $unknownParams);
return rtrim($url, '/') . '/';
}
/**
* Returns the provided name for the router.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name)
{
return (strtolower($this->name) === strtolower($name));
}
/**
* Add regular expression match for the entire route.
*
* @param string $regex
* @return static
*/
public function setMatch($regex)
{
$this->regex = $regex;
return $this;
}
/**
* Get regular expression match used for matching route (if defined).
*
* @return string
*/
public function getMatch()
{
return $this->regex;
}
/**
* Sets the router name, which makes it easier to obtain the url or router at a later point.
* Alias for LoadableRoute::setName().
*
* @see LoadableRoute::setName()
* @param string|array $name
* @return static
*/
public function name($name)
{
return $this->setName($name);
}
/**
* Sets the router name, which makes it easier to obtain the url or router at a later point.
*
* @param string $name
* @return static $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['as'])) {
if ($this->name !== null && $merge !== false) {
$this->setName($values['as'] . '.' . $this->name);
} else {
$this->setName($values['as']);
}
}
if (isset($values['prefix'])) {
$this->setUrl($values['prefix'] . $this->getUrl());
}
parent::setSettings($values, $merge);
return $this;
}
}
+470 -507
View File
@@ -2,516 +2,479 @@
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Exceptions\HttpException;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
abstract class Route implements IRoute
{
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_POST = 'post';
const REQUEST_TYPE_PUT = 'put';
const REQUEST_TYPE_PATCH = 'patch';
const REQUEST_TYPE_OPTIONS = 'options';
const REQUEST_TYPE_DELETE = 'delete';
public static $requestTypes = [
self::REQUEST_TYPE_GET,
self::REQUEST_TYPE_POST,
self::REQUEST_TYPE_PUT,
self::REQUEST_TYPE_PATCH,
self::REQUEST_TYPE_OPTIONS,
self::REQUEST_TYPE_DELETE,
];
protected $paramModifiers = '{}';
protected $paramOptionalSymbol = '?';
protected $group;
protected $parent;
protected $callback;
protected $defaultNamespace;
/* Default options */
protected $namespace;
protected $regex;
protected $requestMethods = [];
protected $where = [];
protected $parameters = [];
protected $middlewares = [];
public function renderRoute(Request $request)
{
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 = $controller[1];
if (!method_exists($class, $method)) {
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}
$parameters = array_filter($this->getParameters(), function ($var) {
return ($var !== null);
});
call_user_func_array([$class, $method], $parameters);
return $class;
}
return null;
}
protected function parseParameters($route, $url, $parameterRegex = '[\w]+')
{
$parameterNames = [];
$regex = '';
$lastCharacter = '';
$isParameter = false;
$parameter = '';
for ($i = 0; $i < strlen($route); $i++) {
$character = $route[$i];
if ($character === '{') {
/* Remove "/" and "\" from regex */
if (substr($regex, strlen($regex) - 1) === '/') {
$regex = substr($regex, 0, strlen($regex) - 2);
}
$isParameter = true;
} elseif ($isParameter && $character === '}') {
$required = true;
/* Check for optional parameter and use custom parameter regex if it exists */
if (is_array($this->where) === true && isset($this->where[$parameter])) {
$parameterRegex = $this->where[$parameter];
}
if ($lastCharacter === '?') {
$parameter = substr($parameter, 0, strlen($parameter) - 1);
$regex .= '(?:\/?(?P<' . $parameter . '>' . $parameterRegex . ')[^\/]?)?';
$required = false;
} else {
$regex .= '\/?(?P<' . $parameter . '>' . $parameterRegex . ')[^\/]?';
}
$parameterNames[] = [
'name' => $parameter,
'required' => $required,
];
$parameter = '';
$isParameter = false;
} elseif ($isParameter) {
$parameter .= $character;
} elseif ($character === '/') {
$regex .= '\\' . $character;
} else {
$regex .= str_replace('.', '\\.', $character);
}
$lastCharacter = $character;
}
$parameterValues = [];
if (preg_match('/^' . $regex . '\/?$/is', $url, $parameterValues)) {
$parameters = [];
foreach ($parameterNames as $name) {
$parameterValue = isset($parameterValues[$name['name']]) ? $parameterValues[$name['name']] : null;
if ($name['required'] && $parameterValue === null) {
throw new HttpException('Missing required parameter ' . $name['name'], 404);
}
if ($name['required'] === false && $parameterValue === null) {
continue;
}
$parameters[$name['name']] = $parameterValue;
}
return $parameters;
}
return null;
}
protected function loadClass($name)
{
if (!class_exists($name)) {
throw new HttpException(sprintf('Class %s does not exist', $name), 500);
}
return new $name();
}
/**
* Returns callback name/identifier for the current route based on the callback.
* Useful if you need to get a unique identifier for the loaded route, for instance
* when using translations etc.
*
* @return string
*/
public function getIdentifier()
{
if (strpos($this->callback, '@') !== false) {
return $this->callback;
}
return 'function_' . md5($this->callback);
}
/**
* Set allowed request methods
*
* @param array $methods
* @return static $this
*/
public function setRequestMethods(array $methods)
{
$this->requestMethods = $methods;
return $this;
}
/**
* Get allowed request methods
*
* @return array
*/
public function getRequestMethods()
{
return $this->requestMethods;
}
/**
* @return IRoute|null
*/
public function getParent()
{
return $this->parent;
}
/**
* Get the group for the route.
*
* @return IGroupRoute|null
*/
public function getGroup()
{
return $this->group;
}
/**
* Set group
*
* @param IGroupRoute $group
* @return static $this
*/
public function setGroup(IGroupRoute $group)
{
$this->group = $group;
return $this;
}
/**
* Set parent route
*
* @param IRoute $parent
* @return static $this
*/
public function setParent(IRoute $parent)
{
$this->parent = $parent;
return $this;
}
/**
* Set callback
*
* @param string $callback
* @return static
*/
public function setCallback($callback)
{
$this->callback = $callback;
return $this;
}
/**
* @return string
*/
public function getCallback()
{
return $this->callback;
}
public function getMethod()
{
if (strpos($this->callback, '@') !== false) {
$tmp = explode('@', $this->callback);
return $tmp[1];
}
return null;
}
public function getClass()
{
if (strpos($this->callback, '@') !== false) {
$tmp = explode('@', $this->callback);
return $tmp[0];
}
return null;
}
public function setMethod($method)
{
$this->callback = sprintf('%s@%s', $this->getClass(), $method);
return $this;
}
public function setClass($class)
{
$this->callback = sprintf('%s@%s', $class, $this->getMethod());
return $this;
}
/**
* @param string $namespace
* @return static $this
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace;
return $this;
}
/**
* @param string $namespace
* @return static $this
*/
public function setDefaultNamespace($namespace)
{
$this->defaultNamespace = $namespace;
return $this;
}
public function getDefaultNamespace()
{
return $this->defaultNamespace;
}
/**
* @return string
*/
public function getNamespace()
{
return ($this->namespace === null) ? $this->defaultNamespace : $this->namespace;
}
/**
* Add regular expression match for the entire route.
*
* @param string $regex
* @return static
*/
public function setMatch($regex)
{
$this->regex = $regex;
return $this;
}
/**
* Get regular expression match used for matching route (if defined).
*
* @return string
*/
public function getMatch()
{
return $this->regex;
}
/**
* Export route settings to array so they can be merged with another route.
*
* @return array
*/
public function toArray()
{
$values = [];
if ($this->namespace !== null) {
$values['namespace'] = $this->namespace;
}
if (count($this->requestMethods) > 0) {
$values['method'] = $this->requestMethods;
}
if (count($this->where) > 0) {
$values['where'] = $this->where;
}
if (count($this->parameters) > 0) {
$values['parameters'] = $this->parameters;
}
if (count($this->middlewares) > 0) {
$values['middleware'] = $this->middlewares;
}
return $values;
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static $this
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['namespace']) && $this->namespace === null) {
$this->setNamespace($values['namespace']);
}
if (isset($values['method'])) {
$this->setRequestMethods(array_merge($this->requestMethods, (array)$values['method']));
}
if (isset($values['where'])) {
$this->setWhere(array_merge($this->where, (array)$values['where']));
}
if (isset($values['parameters'])) {
$this->setParameters(array_merge($this->parameters, (array)$values['parameters']));
}
// Push middleware if multiple
if (isset($values['middleware'])) {
$this->setMiddlewares(array_merge((array)$values['middleware'], $this->middlewares));
}
return $this;
}
/**
* Get parameter names.
*
* @return array
*/
public function getWhere()
{
return $this->where;
}
/**
* Set parameter names.
*
* @param array $options
* @return static
*/
public function setWhere(array $options)
{
$this->where = $options;
return $this;
}
/**
* Add regular expression parameter match.
* Alias for LoadableRoute::where()
*
* @see LoadableRoute::where()
* @param array $options
* @return static
*/
public function where(array $options)
{
return $this->where($options);
}
/**
* Get parameters
*
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* Get parameters
*
* @param array $parameters
* @return static $this
*/
public function setParameters(array $parameters)
{
$this->parameters = $parameters;
return $this;
}
/**
* Set middleware class-name
*
* @param string $middleware
* @return static
*/
public function setMiddleware($middleware)
{
$this->middlewares[] = $middleware;
return $this;
}
/**
* Set middlewares array
*
* @param array $middlewares
* @return $this
*/
public function setMiddlewares(array $middlewares)
{
$this->middlewares = $middlewares;
return $this;
}
/**
* @return string|array
*/
public function getMiddlewares()
{
return $this->middlewares;
}
const PARAMETERS_REGEX_MATCH = '%s([\w]+)(\%s?)%s';
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_POST = 'post';
const REQUEST_TYPE_PUT = 'put';
const REQUEST_TYPE_PATCH = 'patch';
const REQUEST_TYPE_OPTIONS = 'options';
const REQUEST_TYPE_DELETE = 'delete';
public static $requestTypes = [
self::REQUEST_TYPE_GET,
self::REQUEST_TYPE_POST,
self::REQUEST_TYPE_PUT,
self::REQUEST_TYPE_PATCH,
self::REQUEST_TYPE_OPTIONS,
self::REQUEST_TYPE_DELETE,
];
/**
* If enabled parameters containing null-value
* will not be passed along to the callback.
*
* @var bool
*/
protected $filterEmptyParams = false;
protected $paramModifiers = '{}';
protected $paramOptionalSymbol = '?';
protected $group;
protected $parent;
protected $callback;
protected $defaultNamespace;
/* Default options */
protected $namespace;
protected $requestMethods = [];
protected $where = [];
protected $parameters = [];
protected $originalParameters = [];
protected $middlewares = [];
protected function loadClass($name)
{
if (class_exists($name) === false) {
throw new NotFoundHttpException(sprintf('Class %s does not exist', $name), 404);
}
return new $name();
}
public function renderRoute(Request $request)
{
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 = $controller[1];
if (method_exists($class, $method) === false) {
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}
$parameters = $this->getParameters();
/* Filter parameters with null-value */
if ($this->filterEmptyParams === true) {
$parameters = array_filter($parameters, function ($var) {
return ($var !== null);
});
}
call_user_func_array([$class, $method], $parameters);
}
}
protected function parseParameters($route, $url, $parameterRegex = '[\w]+')
{
$regex = sprintf(static::PARAMETERS_REGEX_MATCH, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
if (preg_match_all('/' . $regex . '/is', $route, $parameters)) {
$urlParts = preg_split('/((\-?\/?)\{[^}]+\})/is', rtrim($route, '/'));
foreach ($urlParts as $key => $t) {
$regex = '';
if ($key < (count($parameters[1]))) {
$name = $parameters[1][$key];
$regex = isset($this->where[$name]) ? $this->where[$name] : $parameterRegex;
$regex = sprintf('\-?\/?(?P<%s>%s)', $name, $regex) . $parameters[2][$key];
}
$urlParts[$key] = preg_quote($t, '/') . $regex;
}
$urlRegex = join('', $urlParts);
} else {
$urlRegex = preg_quote($route, '/');
}
if (preg_match('/^' . $urlRegex . '(\/?)$/is', $url, $matches) > 0) {
$values = [];
/* Only take matched parameters with name */
foreach ($parameters[1] as $name) {
$values[$name] = isset($matches[$name]) ? $matches[$name] : null;
}
return $values;
}
return null;
}
/**
* Returns callback name/identifier for the current route based on the callback.
* Useful if you need to get a unique identifier for the loaded route, for instance
* when using translations etc.
*
* @return string
*/
public function getIdentifier()
{
if (strpos($this->callback, '@') !== false) {
return $this->callback;
}
return 'function_' . md5($this->callback);
}
/**
* Set allowed request methods
*
* @param array $methods
* @return static $this
*/
public function setRequestMethods(array $methods)
{
$this->requestMethods = $methods;
return $this;
}
/**
* Get allowed request methods
*
* @return array
*/
public function getRequestMethods()
{
return $this->requestMethods;
}
/**
* @return IRoute|null
*/
public function getParent()
{
return $this->parent;
}
/**
* Get the group for the route.
*
* @return IGroupRoute|null
*/
public function getGroup()
{
return $this->group;
}
/**
* Set group
*
* @param IGroupRoute $group
* @return static $this
*/
public function setGroup(IGroupRoute $group)
{
$this->group = $group;
return $this;
}
/**
* Set parent route
*
* @param IRoute $parent
* @return static $this
*/
public function setParent(IRoute $parent)
{
$this->parent = $parent;
return $this;
}
/**
* Set callback
*
* @param string $callback
* @return static
*/
public function setCallback($callback)
{
$this->callback = $callback;
return $this;
}
/**
* @return string
*/
public function getCallback()
{
return $this->callback;
}
public function getMethod()
{
if (strpos($this->callback, '@') !== false) {
$tmp = explode('@', $this->callback);
return $tmp[1];
}
return null;
}
public function getClass()
{
if (strpos($this->callback, '@') !== false) {
$tmp = explode('@', $this->callback);
return $tmp[0];
}
return null;
}
public function setMethod($method)
{
$this->callback = sprintf('%s@%s', $this->getClass(), $method);
return $this;
}
public function setClass($class)
{
$this->callback = sprintf('%s@%s', $class, $this->getMethod());
return $this;
}
/**
* @param string $namespace
* @return static $this
*/
public function setNamespace($namespace)
{
$this->namespace = $namespace;
return $this;
}
/**
* @param string $namespace
* @return static $this
*/
public function setDefaultNamespace($namespace)
{
$this->defaultNamespace = $namespace;
return $this;
}
public function getDefaultNamespace()
{
return $this->defaultNamespace;
}
/**
* @return string
*/
public function getNamespace()
{
return ($this->namespace === null) ? $this->defaultNamespace : $this->namespace;
}
/**
* Export route settings to array so they can be merged with another route.
*
* @return array
*/
public function toArray()
{
$values = [];
if ($this->namespace !== null) {
$values['namespace'] = $this->namespace;
}
if (count($this->requestMethods) > 0) {
$values['method'] = $this->requestMethods;
}
if (count($this->where) > 0) {
$values['where'] = $this->where;
}
if (count($this->middlewares) > 0) {
$values['middleware'] = $this->middlewares;
}
return $values;
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static $this
*/
public function setSettings(array $values, $merge = false)
{
if ($this->namespace === null && isset($values['namespace'])) {
$this->setNamespace($values['namespace']);
}
if (isset($values['method'])) {
$this->setRequestMethods(array_merge($this->requestMethods, (array)$values['method']));
}
if (isset($values['where'])) {
$this->setWhere(array_merge($this->where, (array)$values['where']));
}
if (isset($values['parameters'])) {
$this->setParameters(array_merge($this->parameters, (array)$values['parameters']));
}
// Push middleware if multiple
if (isset($values['middleware'])) {
$this->setMiddlewares(array_merge((array)$values['middleware'], $this->middlewares));
}
return $this;
}
/**
* Get parameter names.
*
* @return array
*/
public function getWhere()
{
return $this->where;
}
/**
* Set parameter names.
*
* @param array $options
* @return static
*/
public function setWhere(array $options)
{
$this->where = $options;
return $this;
}
/**
* Add regular expression parameter match.
* Alias for LoadableRoute::where()
*
* @see LoadableRoute::where()
* @param array $options
* @return static
*/
public function where(array $options)
{
return $this->where($options);
}
/**
* Get parameters
*
* @return array
*/
public function getParameters()
{
/* Sort the parameters after the user-defined param order, if any */
$parameters = [];
if (count($this->originalParameters) > 0) {
$parameters = $this->originalParameters;
}
return array_merge($parameters, $this->parameters);
}
/**
* Get parameters
*
* @param array $parameters
* @return static $this
*/
public function setParameters(array $parameters)
{
/*
* If this is the first time setting parameters we store them so we
* later can organize the array, in case somebody tried to sort the array.
*/
if (count($parameters) > 0 && count($this->originalParameters) === 0) {
$this->originalParameters = $parameters;
}
$this->parameters = array_merge($this->parameters, $parameters);
return $this;
}
/**
* Set middleware class-name
*
* @param string $middleware
* @return static
*/
public function setMiddleware($middleware)
{
$this->middlewares[] = $middleware;
return $this;
}
/**
* Set middlewares array
*
* @param array $middlewares
* @return $this
*/
public function setMiddlewares(array $middlewares)
{
$this->middlewares = $middlewares;
return $this;
}
/**
* @return string|array
*/
public function getMiddlewares()
{
return $this->middlewares;
}
}
+140 -156
View File
@@ -2,198 +2,182 @@
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
class RouteController extends LoadableRoute implements IControllerRoute
{
protected $defaultMethod = 'index';
protected $controller;
protected $method;
protected $names = [];
protected $defaultMethod = 'index';
protected $controller;
protected $method;
protected $names = [];
public function __construct($url, $controller)
{
$this->setUrl($url);
$this->setName(trim(str_replace('/', '.', $url), '/'));
$this->controller = $controller;
}
public function __construct($url, $controller)
{
$this->setUrl($url);
$this->setName(trim(str_replace('/', '.', $url), '/'));
$this->controller = $controller;
}
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name)
{
if ($this->name === null) {
return false;
}
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name)
{
if ($this->name === null) {
return false;
}
/* Remove method/type */
if (stripos($name, '.') !== false) {
$method = substr($name, strrpos($name, '.') + 1);
$newName = substr($name, 0, strrpos($name, '.'));
/* Remove method/type */
if (strpos($name, '.') !== false) {
$method = substr($name, strrpos($name, '.') + 1);
$newName = substr($name, 0, strrpos($name, '.'));
if (strtolower($this->name) === strtolower($newName) && in_array($method, $this->names)) {
return true;
}
}
if (in_array($method, $this->names, false) === true && strtolower($this->name) === strtolower($newName)) {
return true;
}
}
return parent::hasName($name);
}
return parent::hasName($name);
}
public function findUrl($method = null, $parameters = null, $name = null)
{
/**
* @param string|null $method
* @param string|array|null $parameters
* @param string|null $name
* @return string
*/
public function findUrl($method = null, $parameters = null, $name = null)
{
if (strpos($name, '.') !== false) {
$found = array_search(substr($name, strrpos($name, '.') + 1), $this->names, false);
if ($found !== false) {
$method = $found;
}
}
if (stripos($name, '.') !== false) {
$found = array_search(substr($name, strrpos($name, '.') + 1), $this->names);
if ($found !== false) {
$method = $found;
}
}
$url = '';
$parameters = (array)$parameters;
$url = '';
if ($method !== null) {
$parameters = (array)$parameters;
/* Remove requestType from method-name, if it exists */
foreach (static::$requestTypes as $requestType) {
/* Remove requestType from method-name, if it exists */
if ($method !== null) {
foreach (static::$requestTypes as $requestType) {
if (stripos($method, $requestType) === 0) {
$method = substr($method, strlen($requestType));
break;
}
}
$method .= '/';
}
if (stripos($method, $requestType) === 0) {
$method = substr($method, strlen($requestType));
break;
}
}
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
$url .= '//' . $this->getGroup()->getDomains()[0];
}
$method .= '/';
}
$url .= '/' . trim($this->getUrl(), '/') . '/' . strtolower($method) . join('/', $parameters);
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
$url .= '//' . $this->getGroup()->getDomains()[0];
}
return '/' . trim($url, '/') . '/';
}
$url .= '/' . trim($this->getUrl(), '/') . '/' . strtolower($method) . join('/', $parameters);
public function renderRoute(Request $request)
{
if ($this->getCallback() !== null && is_callable($this->getCallback())) {
return '/' . trim($url, '/') . '/';
}
// 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];
public function matchRoute(Request $request)
{
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$class = $this->loadClass($className);
$method = $request->getMethod() . ucfirst($controller[1]);
/* Match global regular-expression for route */
if ($this->matchRegex($request, $url) === true) {
return true;
}
if (!method_exists($class, $method)) {
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}
if (stripos($url, $this->url) === 0 && strtolower($url) === strtolower($this->url)) {
call_user_func_array([$class, $method], $this->getParameters());
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
return $class;
}
$path = explode('/', $strippedUrl);
return null;
}
if (count($path) > 0) {
public function matchRoute(Request $request)
{
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$method = (!isset($path[0]) || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
$this->method = $method;
if (strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
$this->parameters = array_slice($path, 1);
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
// Set callback
$this->setCallback($this->controller . '@' . $this->method);
$path = explode('/', $strippedUrl);
return true;
}
}
if (count($path) > 0) {
return false;
}
$method = (!isset($path[0]) || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
$this->method = $method;
/**
* Get controller class-name.
*
* @return string
*/
public function getController()
{
return $this->controller;
}
array_shift($path);
$this->parameters = $path;
/**
* Get controller class-name.
*
* @param string $controller
* @return static
*/
public function setController($controller)
{
$this->controller = $controller;
// Set callback
$this->setCallback($this->controller . '@' . $this->method);
return $this;
}
return true;
}
}
/**
* Return active method
*
* @return string
*/
public function getMethod()
{
return $this->method;
}
return null;
}
/**
* Set active method
*
* @param string $method
* @return static
*/
public function setMethod($method)
{
$this->method = $method;
/**
* Get controller class-name.
*
* @return string
*/
public function getController()
{
return $this->controller;
}
return $this;
}
/**
* Get controller class-name.
*
* @param string $controller
* @return static
*/
public function setController($controller)
{
$this->controller = $controller;
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['names'])) {
$this->names = $values['names'];
}
return $this;
}
parent::setSettings($values, $merge);
/**
* Return active method
*
* @return string
*/
public function getMethod()
{
return $this->method;
}
/**
* Set active method
*
* @param string $method
* @return static
*/
public function setMethod($method)
{
$this->method = $method;
return $this;
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['names'])) {
$this->names = $values['names'];
}
parent::setSettings($values, $merge);
return $this;
}
return $this;
}
}
+145 -140
View File
@@ -5,173 +5,178 @@ use Pecee\Http\Request;
class RouteGroup extends Route implements IGroupRoute
{
protected $prefix;
protected $name;
protected $domains = [];
protected $exceptionHandlers = [];
protected $prefix;
protected $name;
protected $domains = [];
protected $exceptionHandlers = [];
/**
* Method called to check if a domain matches
*
* @param Request $request
* @return bool
*/
public function matchDomain(Request $request)
{
if (count($this->domains) > 0) {
foreach ($this->domains as $domain) {
/**
* Method called to check if a domain matches
*
* @param Request $request
* @return bool
*/
public function matchDomain(Request $request)
{
if (count($this->domains) === 0) {
return true;
}
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
foreach ($this->domains as $domain) {
if ($parameters !== null) {
$this->parameters = $parameters;
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
return true;
}
}
if ($parameters !== null && count($parameters) > 0) {
return false;
}
$this->parameters = $parameters;
return true;
}
return true;
}
}
/**
* Method called to check if route matches
*
* @param Request $request
* @return bool
*/
public function matchRoute(Request $request)
{
// Skip if prefix doesn't match
if ($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) {
return false;
}
return false;
}
return $this->matchDomain($request);
}
/**
* Method called to check if route matches
*
* @param Request $request
* @return bool
*/
public function matchRoute(Request $request)
{
/* Skip if prefix doesn't match */
if ($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) {
return false;
}
/**
* Set exception-handlers for group
*
* @param array $handlers
* @return static $this
*/
public function setExceptionHandlers(array $handlers)
{
$this->exceptionHandlers = $handlers;
return $this->matchDomain($request);
}
return $this;
}
/**
* Set exception-handlers for group
*
* @param array $handlers
* @return static $this
*/
public function setExceptionHandlers(array $handlers)
{
$this->exceptionHandlers = $handlers;
/**
* Get exception-handlers for group
*
* @return array
*/
public function getExceptionHandlers()
{
return $this->exceptionHandlers;
}
return $this;
}
/**
* Get allowed domains for domain.
*
* @return array
*/
public function getDomains()
{
return $this->domains;
}
/**
* Get exception-handlers for group
*
* @return array
*/
public function getExceptionHandlers()
{
return $this->exceptionHandlers;
}
/**
* Set allowed domains for group.
*
* @param array $domains
* @return $this
*/
public function setDomains(array $domains)
{
$this->domains = $domains;
/**
* Get allowed domains for domain.
*
* @return array
*/
public function getDomains()
{
return $this->domains;
}
return $this;
}
/**
* Set allowed domains for group.
*
* @param array $domains
* @return $this
*/
public function setDomains(array $domains)
{
$this->domains = $domains;
/**
* @param string $prefix
* @return static
*/
public function setPrefix($prefix)
{
$this->prefix = '/' . trim($prefix, '/');
return $this;
}
return $this;
}
/**
* @param string $prefix
* @return static
*/
public function setPrefix($prefix)
{
$this->prefix = '/' . trim($prefix, '/');
/**
* Set prefix that child-routes will inherit.
*
* @return string
*/
public function getPrefix()
{
return $this->prefix;
}
return $this;
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
/**
* Set prefix that child-routes will inherit.
*
* @return string
*/
public function getPrefix()
{
return $this->prefix;
}
if (isset($values['prefix'])) {
$this->setPrefix($values['prefix'] . $this->prefix);
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['exceptionHandler'])) {
$this->setExceptionHandlers((array)$values['exceptionHandler']);
}
if (isset($values['prefix'])) {
$this->setPrefix($values['prefix'] . $this->prefix);
}
if (isset($values['domain'])) {
$this->setDomains((array)$values['domain']);
}
if (isset($values['exceptionHandler'])) {
$this->setExceptionHandlers((array)$values['exceptionHandler']);
}
if (isset($values['as'])) {
if ($this->name !== null && $merge !== false) {
$this->name = $values['as'] . '.' . $this->name;
} else {
$this->name = $values['as'];
}
}
if (isset($values['domain'])) {
$this->setDomains((array)$values['domain']);
}
parent::setSettings($values, $merge);
if (isset($values['as'])) {
if ($this->name !== null && $merge !== false) {
$this->name = $values['as'] . '.' . $this->name;
} else {
$this->name = $values['as'];
}
}
return $this;
}
parent::setSettings($values, $merge);
/**
* Export route settings to array so they can be merged with another route.
*
* @return array
*/
public function toArray()
{
$values = [];
return $this;
}
if ($this->prefix !== null) {
$values['prefix'] = $this->getPrefix();
}
/**
* Export route settings to array so they can be merged with another route.
*
* @return array
*/
public function toArray()
{
$values = [];
if ($this->name !== null) {
$values['as'] = $this->name;
}
if ($this->prefix !== null) {
$values['prefix'] = $this->getPrefix();
}
return array_merge($values, parent::toArray());
}
if ($this->name !== null) {
$values['as'] = $this->name;
}
if (count($this->parameters) > 0) {
$values['parameters'] = $this->parameters;
}
return array_merge($values, parent::toArray());
}
}
+172 -156
View File
@@ -2,202 +2,218 @@
namespace Pecee\SimpleRouter\Route;
use Pecee\Http\Request;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
class RouteResource extends LoadableRoute implements IControllerRoute
{
protected $urls = [
'index' => '',
'create' => 'create',
'store' => '',
'show' => '',
'edit' => 'edit',
'update' => '',
'destroy' => '',
];
protected $names = [];
protected $controller;
protected $urls = [
'index' => '',
'create' => 'create',
'store' => '',
'show' => '',
'edit' => 'edit',
'update' => '',
'destroy' => '',
];
public function __construct($url, $controller)
{
$this->setUrl($url);
$this->controller = $controller;
$this->setName(trim(str_replace('/', '.', $url), '/'));
}
protected $methodNames = [
'index' => 'index',
'create' => 'create',
'store' => 'store',
'show' => 'show',
'edit' => 'edit',
'update' => 'update',
'destroy' => 'destroy',
];
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name)
{
if ($this->name === null) {
return false;
}
protected $names = [];
protected $controller;
if (strtolower($this->name) === strtolower($name)) {
return true;
}
public function __construct($url, $controller)
{
$this->setUrl($url);
$this->controller = $controller;
$this->setName(trim(str_replace('/', '.', $url), '/'));
}
/* Remove method/type */
if (stripos($name, '.') !== false) {
$name = substr($name, 0, strrpos($name, '.'));
}
/**
* Check if route has given name.
*
* @param string $name
* @return bool
*/
public function hasName($name)
{
if ($this->name === null) {
return false;
}
return (strtolower($this->name) === strtolower($name));
}
if (strtolower($this->name) === strtolower($name)) {
return true;
}
public function findUrl($method = null, $parameters = null, $name = null)
{
$method = array_search($name, $this->names);
if ($method !== false) {
return rtrim($this->url . $this->urls[$method], '/') . '/';
}
/* Remove method/type */
if (strpos($name, '.') !== false) {
$name = substr($name, 0, strrpos($name, '.'));
}
return $this->url;
}
return (strtolower($this->name) === strtolower($name));
}
public function renderRoute(Request $request)
{
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 findUrl($method = null, $parameters = null, $name = null)
{
$method = array_search($name, $this->names, false);
if ($method !== false) {
return rtrim($this->url . $this->urls[$method], '/') . '/';
}
if (!method_exists($class, $method)) {
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}
return $this->url;
}
call_user_func_array([$class, $method], $this->getParameters());
protected function call($method)
{
$this->setCallback($this->controller . '@' . $method);
return $class;
}
return true;
}
return null;
}
public function matchRoute(Request $request)
{
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
protected function call($method, $parameters)
{
$this->setCallback($this->controller . '@' . $method);
$this->parameters = $parameters;
/* Match global regular-expression for route */
$domainMatch = $this->matchRegex($request, $url);
if ($domainMatch !== null) {
return $domainMatch;
}
return true;
}
$route = rtrim($this->url, '/') . '/{id?}/{action?}';
public function matchRoute(Request $request)
{
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$parameters = $this->parseParameters($route, $url);
if ($parameters === null) {
return false;
}
$route = rtrim($this->url, '/') . '/{id?}/{action?}';
$this->parameters = (array)$parameters;
$parameters = $this->parseParameters($route, $url);
$action = isset($this->parameters['action']) ? $this->parameters['action'] : null;
unset($this->parameters['action']);
if ($parameters !== null) {
$method = $request->getMethod();
$parameters = array_merge($this->parameters, (array)$parameters);
// Delete
if ($method === static::REQUEST_TYPE_DELETE && isset($this->parameters['id'])) {
return $this->call($this->methodNames['destroy']);
}
$action = isset($parameters['action']) ? $parameters['action'] : null;
unset($parameters['action']);
// Update
if (isset($this->parameters['id']) && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT], false)) {
return $this->call($this->methodNames['update']);
}
$method = request()->getMethod();
// Edit
if ($method === static::REQUEST_TYPE_GET && isset($this->parameters['id']) && strtolower($action) === 'edit') {
return $this->call($this->methodNames['edit']);
}
// Delete
if (isset($parameters['id']) && $method === static::REQUEST_TYPE_DELETE) {
return $this->call('destroy', $parameters);
}
// Create
if ($method === static::REQUEST_TYPE_GET && strtolower($action) === 'create') {
return $this->call($this->methodNames['create']);
}
// Update
if (isset($parameters['id']) && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT])) {
return $this->call('update', $parameters);
}
// Save
if ($method === static::REQUEST_TYPE_POST) {
return $this->call($this->methodNames['store']);
}
// Edit
if (isset($parameters['id']) && strtolower($action) === 'edit' && $method === static::REQUEST_TYPE_GET) {
return $this->call('edit', $parameters);
}
// Show
if ($method === static::REQUEST_TYPE_GET && isset($this->parameters['id'])) {
return $this->call($this->methodNames['show']);
}
// Create
if (strtolower($action) === 'create' && $method === static::REQUEST_TYPE_GET) {
return $this->call('create', $parameters);
}
// Index
return $this->call($this->methodNames['index']);
}
// Save
if ($method === static::REQUEST_TYPE_POST) {
return $this->call('store', $parameters);
}
/**
* @return string
*/
public function getController()
{
return $this->controller;
}
// Show
if (isset($parameters['id']) && $method === static::REQUEST_TYPE_GET) {
return $this->call('show', $parameters);
}
/**
* @param string $controller
* @return static
*/
public function setController($controller)
{
$this->controller = $controller;
// Index
return $this->call('index', $parameters);
}
return $this;
}
return null;
}
public function setName($name)
{
$this->name = $name;
/**
* @return string
*/
public function getController()
{
return $this->controller;
}
$this->names = [
'index' => $this->name . '.index',
'create' => $this->name . '.create',
'store' => $this->name . '.store',
'show' => $this->name . '.show',
'edit' => $this->name . '.edit',
'update' => $this->name . '.update',
'destroy' => $this->name . '.destroy',
];
/**
* @param string $controller
* @return static
*/
public function setController($controller)
{
$this->controller = $controller;
return $this;
}
return $this;
}
/**
* Define custom method name for resource controller
*
* @param array $names
* @return static $this
*/
public function setMethodNames(array $names)
{
$this->methodNames = $names;
public function setName($name)
{
$this->name = $name;
return $this;
}
$this->names = [
'index' => $this->name . '.index',
'create' => $this->name . '.create',
'store' => $this->name . '.store',
'show' => $this->name . '.show',
'edit' => $this->name . '.edit',
'update' => $this->name . '.update',
'destroy' => $this->name . '.destroy',
];
/**
* Get method names
*
* @return array $this
*/
public function getMethodNames()
{
return $this->methodNames;
}
return $this;
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['names'])) {
$this->names = $values['names'];
}
/**
* Merge with information from another route.
*
* @param array $values
* @param bool $merge
* @return static
*/
public function setSettings(array $values, $merge = false)
{
if (isset($values['names'])) {
$this->names = $values['names'];
}
if (isset($values['methods'])) {
$this->methodNames = $values['methods'];
}
parent::setSettings($values, $merge);
parent::setSettings($values, $merge);
return $this;
}
return $this;
}
}
+22 -30
View File
@@ -5,41 +5,33 @@ use Pecee\Http\Request;
class RouteUrl extends LoadableRoute
{
public function __construct($url, $callback)
{
$this->setUrl($url);
$this->setCallback($callback);
}
public function __construct($url, $callback)
{
$this->setUrl($url);
$this->setCallback($callback);
}
public function matchRoute(Request $request)
{
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
public function matchRoute(Request $request)
{
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
// Match on custom defined regular expression
if ($this->regex !== null) {
$parameters = [];
if (preg_match('/(' . $this->regex . ')/is', $request->getHost() . $url, $parameters)) {
$this->parameters = (array)$parameters[0];
/* Match global regular-expression for route */
$domainMatch = $this->matchRegex($request, $url);
if ($domainMatch !== null) {
return $domainMatch;
}
return true;
}
/* Make regular expression based on route */
$parameters = $this->parseParameters($this->url, $url);
if ($parameters === null) {
return false;
}
return null;
}
$this->setParameters($parameters);
// Make regular expression based on route
$route = rtrim($this->url, '/') . '/';
return true;
$parameters = $this->parseParameters($route, $url);
if ($parameters !== null) {
$this->parameters = array_merge($this->parameters, $parameters);
return true;
}
return null;
}
}
}
File diff suppressed because it is too large Load Diff
+308 -307
View File
@@ -21,354 +21,355 @@ use Pecee\SimpleRouter\Route\RouteUrl;
class SimpleRouter
{
/**
* Default namespace added to all routes
* @var string
*/
protected static $defaultNamespace;
/**
* Default namespace added to all routes
* @var string
*/
protected static $defaultNamespace;
/**
* The response object
* @var Response
*/
protected static $response;
/**
* The response object
* @var Response
*/
protected static $response;
/**
* Start/route request
*
* @throws HttpException
* @throws NotFoundHttpException
*/
public static function start()
{
static::router()->routeRequest();
}
/**
* Start/route request
*
* @throws HttpException
* @throws NotFoundHttpException
*/
public static function start()
{
static::router()->routeRequest();
}
/**
* Set default namespace which will be prepended to all routes.
*
* @param string $defaultNamespace
*/
public static function setDefaultNamespace($defaultNamespace)
{
static::$defaultNamespace = $defaultNamespace;
}
/**
* Set default namespace which will be prepended to all routes.
*
* @param string $defaultNamespace
*/
public static function setDefaultNamespace($defaultNamespace)
{
static::$defaultNamespace = $defaultNamespace;
}
/**
* Base CSRF verifier
*
* @param BaseCsrfVerifier $baseCsrfVerifier
*/
public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier)
{
static::router()->setCsrfVerifier($baseCsrfVerifier);
}
/**
* Base CSRF verifier
*
* @param BaseCsrfVerifier $baseCsrfVerifier
*/
public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier)
{
static::router()->setCsrfVerifier($baseCsrfVerifier);
}
/**
* 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 IRouterBootManager $bootManager
*/
public static function addBootManager(IRouterBootManager $bootManager)
{
static::router()->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 IRouterBootManager $bootManager
*/
public static function addBootManager(IRouterBootManager $bootManager)
{
static::router()->addBootManager($bootManager);
}
/**
* Route the given url to your callback on GET request method.
*
* @param string $url
* @param string|\Closure $callback
* @param array|null $settings
* @return RouteUrl
*/
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 RouteUrl
*/
public static function get($url, $callback, array $settings = null)
{
return static::match(['get'], $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 RouteUrl
*/
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 RouteUrl
*/
public static function post($url, $callback, array $settings = null)
{
return static::match(['post'], $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 RouteUrl
*/
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 RouteUrl
*/
public static function put($url, $callback, array $settings = null)
{
return static::match(['put'], $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 RouteUrl
*/
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 RouteUrl
*/
public static function patch($url, $callback, array $settings = null)
{
return static::match(['patch'], $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 RouteUrl
*/
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 RouteUrl
*/
public static function options($url, $callback, array $settings = null)
{
return static::match(['options'], $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 RouteUrl
*/
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 RouteUrl
*/
public static function delete($url, $callback, array $settings = null)
{
return static::match(['delete'], $url, $callback, $settings);
}
/**
* Groups allows for encapsulating routes with special settings.
*
* @param array $settings
* @param \Closure $callback
* @throws \InvalidArgumentException
* @return RouteGroup
*/
public static function group(array $settings = [], \Closure $callback)
{
$group = new RouteGroup();
$group->setCallback($callback);
$group->setSettings($settings);
/**
* Groups allows for encapsulating routes with special settings.
*
* @param array $settings
* @param \Closure $callback
* @throws \InvalidArgumentException
* @return RouteGroup
*/
public static function group(array $settings = [], \Closure $callback)
{
$group = new RouteGroup();
$group->setCallback($callback);
$group->setSettings($settings);
if (is_callable($callback) === false) {
throw new \InvalidArgumentException('Invalid callback provided. Only functions or methods supported');
}
if (is_callable($callback) === false) {
throw new \InvalidArgumentException('Invalid callback provided. Only functions or methods supported');
}
static::router()->addRoute($group);
static::router()->addRoute($group);
return $group;
}
return $group;
}
/**
* Alias for the form method
*
* @param string $url
* @param callable $callback
* @param array|null $settings
* @see SimpleRouter::form
* @return RouteUrl
*/
public static function basic($url, $callback, array $settings = null)
{
return static::match(['get', 'post'], $url, $callback, $settings);
}
/**
* Alias for the form method
*
* @param string $url
* @param callable $callback
* @param array|null $settings
* @see SimpleRouter::form
* @return RouteUrl
*/
public static function basic($url, $callback, array $settings = null)
{
return static::match(['get', 'post'], $url, $callback, $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 RouteUrl
*/
public static function form($url, $callback, array $settings = null)
{
return static::match(['get', 'post'], $url, $callback, $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 RouteUrl
*/
public static function form($url, $callback, array $settings = null)
{
return static::match(['get', 'post'], $url, $callback, $settings);
}
/**
* 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 RouteUrl
*/
public static function match(array $requestMethods, $url, $callback, array $settings = null)
{
$route = new RouteUrl($url, $callback);
$route->setRequestMethods($requestMethods);
$route = static::addDefaultNamespace($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 RouteUrl
*/
public static function match(array $requestMethods, $url, $callback, array $settings = null)
{
$route = new RouteUrl($url, $callback);
$route->setRequestMethods($requestMethods);
$route = static::addDefaultNamespace($route);
if ($settings !== null) {
$route->setSettings($settings);
}
if ($settings !== null) {
$route->setSettings($settings);
}
static::router()->addRoute($route);
static::router()->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 RouteUrl
*/
public static function all($url, $callback, array $settings = null)
{
$route = new RouteUrl($url, $callback);
$route = static::addDefaultNamespace($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 RouteUrl
*/
public static function all($url, $callback, array $settings = null)
{
$route = new RouteUrl($url, $callback);
$route = static::addDefaultNamespace($route);
if ($settings !== null) {
$route->setSettings($settings);
}
if ($settings !== null) {
$route->setSettings($settings);
}
static::router()->addRoute($route);
static::router()->addRoute($route);
return $route;
}
return $route;
}
/**
* This route will route request from the given url to the controller.
*
* @param string $url
* @param string $controller
* @param array|null $settings
* @return RouteController
*/
public static function controller($url, $controller, array $settings = null)
{
$route = new RouteController($url, $controller);
$route = static::addDefaultNamespace($route);
/**
* This route will route request from the given url to the controller.
*
* @param string $url
* @param string $controller
* @param array|null $settings
* @return RouteController
*/
public static function controller($url, $controller, array $settings = null)
{
$route = new RouteController($url, $controller);
$route = static::addDefaultNamespace($route);
if ($settings !== null) {
$route->setSettings($settings);
}
if ($settings !== null) {
$route->setSettings($settings);
}
static::router()->addRoute($route);
static::router()->addRoute($route);
return $route;
}
return $route;
}
/**
* 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 RouteResource
*/
public static function resource($url, $controller, array $settings = null)
{
$route = new RouteResource($url, $controller);
/**
* 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 RouteResource
*/
public static function resource($url, $controller, array $settings = null)
{
$route = new RouteResource($url, $controller);
if ($settings !== null) {
$route->setSettings($settings);
}
if ($settings !== null) {
$route->setSettings($settings);
}
static::router()->addRoute($route);
static::router()->addRoute($route);
return $route;
}
return $route;
}
/**
* Get url for a route by using either name/alias, class or method name.
*
* The name parameter supports the following values:
* - Route name
* - Controller/resource name (with or without method)
* - Controller class name
*
* When searching for controller/resource by name, you can use this syntax "route.name@method".
* You can also use the same syntax when searching for a specific controller-class "MyController@home".
* If no arguments is specified, it will return the url for the current loaded route.
*
* @param string|null $name
* @param string|array|null $parameters
* @param array|null $getParams
* @return string
*/
public static function getUrl($name = null, $parameters = null, $getParams = [])
{
return static::router()->getUrl($name, $parameters, $getParams);
}
/**
* Get url for a route by using either name/alias, class or method name.
*
* The name parameter supports the following values:
* - Route name
* - Controller/resource name (with or without method)
* - Controller class name
*
* When searching for controller/resource by name, you can use this syntax "route.name@method".
* You can also use the same syntax when searching for a specific controller-class "MyController@home".
* If no arguments is specified, it will return the url for the current loaded route.
*
* @param string|null $name
* @param string|array|null $parameters
* @param array|null $getParams
* @throws \Exception
* @return string
*/
public static function getUrl($name = null, $parameters = null, $getParams = null)
{
return static::router()->getUrl($name, $parameters, $getParams);
}
/**
* Get the request
*
* @return \Pecee\Http\Request
*/
public static function request()
{
return static::router()->getRequest();
}
/**
* Get the request
*
* @return \Pecee\Http\Request
*/
public static function request()
{
return static::router()->getRequest();
}
/**
* Get the response object
*
* @return Response
*/
public static function response()
{
if (static::$response === null) {
static::$response = new Response(static::request());
}
/**
* Get the response object
*
* @return Response
*/
public static function response()
{
if (static::$response === null) {
static::$response = new Response(static::request());
}
return static::$response;
}
return static::$response;
}
/**
* Returns the router instance
*
* @return Router
*/
public static function router()
{
return Router::getInstance();
}
/**
* Returns the router instance
*
* @return Router
*/
public static function router()
{
return Router::getInstance();
}
/**
* Prepends the default namespace to all new routes added.
*
* @param IRoute $route
* @return IRoute
*/
protected static function addDefaultNamespace(IRoute $route)
{
if (static::$defaultNamespace !== null) {
$namespace = static::$defaultNamespace;
/**
* Prepends the default namespace to all new routes added.
*
* @param IRoute $route
* @return IRoute
*/
protected static function addDefaultNamespace(IRoute $route)
{
if (static::$defaultNamespace !== null) {
$namespace = static::$defaultNamespace;
if ($route->getNamespace() !== null) {
$namespace .= '\\' . $route->getNamespace();
}
if ($route->getNamespace() !== null) {
$namespace .= '\\' . $route->getNamespace();
}
$route->setDefaultNamespace($namespace);
}
$route->setDefaultNamespace($namespace);
}
return $route;
}
return $route;
}
}
@@ -0,0 +1,4 @@
<?php
class ExceptionHandlerException extends \Exception
{
}
+1 -1
View File
@@ -4,7 +4,7 @@ class ExceptionHandler implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\Route\ILoadableRoute &$route = null, \Exception $error)
{
throw $error;
echo $error->getMessage();
}
}
@@ -0,0 +1,13 @@
<?php
class TestExceptionHandlerFirst implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\Route\ILoadableRoute &$route = null, \Exception $error)
{
echo 'ExceptionHandler 1 loaded' . chr(10);
$request->setUri('/');
return $request;
}
}
@@ -0,0 +1,13 @@
<?php
class TestExceptionHandlerSecond implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\Route\ILoadableRoute &$route = null, \Exception $error)
{
echo 'ExceptionHandler 2 loaded' . chr(10);
$request->setUri('/');
return $request;
}
}
@@ -0,0 +1,12 @@
<?php
class TestExceptionHandlerThird implements \Pecee\Handlers\IExceptionHandler
{
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\Route\ILoadableRoute &$route = null, \Exception $error)
{
echo 'ExceptionHandler 3 loaded' . chr(10);
throw new ExceptionHandlerException('All good!', 666);
}
}
+57 -57
View File
@@ -7,89 +7,89 @@ use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
class GroupTest extends PHPUnit_Framework_TestCase
{
protected $result;
protected $result;
public function testGroupLoad()
{
$this->result = false;
public function testGroupLoad()
{
$this->result = false;
SimpleRouter::group(['prefix' => '/group'], function () {
$this->result = true;
});
SimpleRouter::group(['prefix' => '/group'], function () {
$this->result = true;
});
try {
SimpleRouter::start();
} catch (Exception $e) {
// ignore RouteNotFound exception
}
try {
SimpleRouter::start();
} catch (Exception $e) {
// ignore RouteNotFound exception
}
$this->assertTrue($this->result);
}
$this->assertTrue($this->result);
}
public function testNestedGroup()
{
public function testNestedGroup()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/api/v1/test');
SimpleRouter::request()->setMethod('get');
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/api/v1/test');
SimpleRouter::request()->setMethod('get');
SimpleRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/test', 'DummyController@start');
});
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/test', 'DummyController@start');
});
});
});
SimpleRouter::start();
}
SimpleRouter::start();
}
public function testManyRoutes()
{
public function testManyRoutes()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/match');
SimpleRouter::request()->setMethod('get');
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/match');
SimpleRouter::request()->setMethod('get');
SimpleRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/api'], function () {
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/test', 'DummyController@start');
});
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/test', 'DummyController@start');
});
});
});
SimpleRouter::get('/my/match', 'DummyController@start');
SimpleRouter::get('/my/match', 'DummyController@start');
SimpleRouter::group(['prefix' => '/service'], function () {
SimpleRouter::group(['prefix' => '/service'], function () {
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/no-match', 'DummyController@start');
});
SimpleRouter::group(['prefix' => '/v1'], function () {
SimpleRouter::get('/no-match', 'DummyController@start');
});
});
});
SimpleRouter::start();
}
SimpleRouter::start();
}
public function testUrls()
{
public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/fancy/url/1');
SimpleRouter::request()->setMethod('get');
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/fancy/url/1');
SimpleRouter::request()->setMethod('get');
// Test array name
SimpleRouter::get('/my/fancy/url/1', 'DummyController@start', ['as' => 'fancy1']);
// Test array name
SimpleRouter::get('/my/fancy/url/1', 'DummyController@start', ['as' => 'fancy1']);
// Test method name
SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setName('fancy2');
// Test method name
SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setName('fancy2');
SimpleRouter::start();
SimpleRouter::start();
$this->assertEquals('/my/fancy/url/1/', SimpleRouter::getUrl('fancy1'));
$this->assertEquals('/my/fancy/url/2/', SimpleRouter::getUrl('fancy2'));
$this->assertEquals('/my/fancy/url/1/', SimpleRouter::getUrl('fancy1'));
$this->assertEquals('/my/fancy/url/2/', SimpleRouter::getUrl('fancy2'));
}
}
}
+25 -16
View File
@@ -8,25 +8,34 @@ use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
class MiddlewareTest extends PHPUnit_Framework_TestCase
{
public function testMiddlewareFound()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/test/url');
public function testMiddlewareFound()
{
$this->setExpectedException('MiddlewareLoadedException');
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
});
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/test/url');
$found = false;
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
});
try {
SimpleRouter::start();
} catch (\Exception $e) {
$found = ($e instanceof MiddlewareLoadedException);
}
SimpleRouter::start();
}
$this->assertTrue($found);
}
public function testNestedMiddlewareLoad()
{
$this->setExpectedException('MiddlewareLoadedException');
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler', 'middleware' => 'DummyMiddleware'], function () {
SimpleRouter::get('/my/test/url', 'DummyController@start');
});
SimpleRouter::start();
}
}
+133 -102
View File
@@ -2,140 +2,171 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php';
require_once 'Dummy/Exceptions/ExceptionHandlerException.php';
require_once 'Dummy/Handler/TestExceptionHandlerFirst.php';
require_once 'Dummy/Handler/TestExceptionHandlerSecond.php';
require_once 'Dummy/Handler/TestExceptionHandlerThird.php';
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException as NotFoundHttpException;
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
class RouterRouteTest extends PHPUnit_Framework_TestCase
{
protected $result = false;
protected $result = false;
public function testNotFound()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
public function testMultiParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
SimpleRouter::get('/non-existing-path', 'DummyController@start');
});
SimpleRouter::get('/test-{param1}-{param2}', function($param1, $param2) {
$found = false;
if($param1 === 'param1' && $param2 === 'param2') {
$this->result = true;
}
try {
SimpleRouter::start();
} catch (\Exception $e) {
$found = ($e instanceof NotFoundHttpException && $e->getCode() == 404);
}
});
$this->assertTrue($found);
}
SimpleRouter::start();
public function testGet()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('get');
$this->assertTrue($this->result);
SimpleRouter::get('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
}
public function testPost()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
/**
* Redirects to another route through 3 exception handlers.
*
* You will see "ExceptionHandler 1 loaded" 2 times. This happen because
* the exceptionhandler is asking the router to reload.
*
* That means that the exceptionhandler is loaded again, but this time
* the router ignores the same rewrite-route to avoid loop - loads
* the second which have same behavior and is also ignored before
* throwing the final Exception in ExceptionHandler 3.
*
* So this tests:
* 1. If ExceptionHandlers loads
* 2. If ExceptionHandlers load in the correct order
* 3. If ExceptionHandlers can rewrite the page on error
* 4. If the router can avoid redirect-loop due to developer has started loop.
* 5. And finally if we reaches the last exception-handler and that the correct
* exception-type is being thrown.
*/
public function testNotFound()
{
$this->setExpectedException('ExceptionHandlerException');
SimpleRouter::post('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
public function testPut()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('put');
SimpleRouter::group(['exceptionHandler' => ['TestExceptionHandlerFirst', 'TestExceptionHandlerSecond']], function () {
SimpleRouter::put('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
SimpleRouter::group(['exceptionHandler' => 'TestExceptionHandlerThird'], function () {
public function testDelete()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('delete');
SimpleRouter::get('/non-existing-path', 'DummyController@start');
SimpleRouter::delete('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
});
});
public function testMethodNotAllowed()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
SimpleRouter::start();
}
SimpleRouter::get('/my/test/url', 'DummyController@start');
public function testGet()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('get');
try {
SimpleRouter::start();
} catch (\Exception $e) {
$this->assertEquals(403, $e->getCode());
}
}
SimpleRouter::get('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
public function testSimpleParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1');
public function testPost()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
SimpleRouter::get('/test-{param1}', 'DummyController@param');
SimpleRouter::start();
}
SimpleRouter::post('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
public function testMultiParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1-param2');
public function testPut()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('put');
SimpleRouter::get('/test-{param1}-{param2}', 'DummyController@param');
SimpleRouter::start();
}
SimpleRouter::put('/my/test/url', 'DummyController@start');
SimpleRouter::start();
}
public function testPathParamRegex()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test/path/123123');
public function testDelete()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('delete');
SimpleRouter::get('/test/path/{myParam}', 'DummyController@param', ['where' => ['myParam' => '([0-9]+)']]);
SimpleRouter::start();
}
SimpleRouter::delete('/my/test/url', 'DummyController@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 testMethodNotAllowed()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setUri('/my/test/url');
SimpleRouter::request()->setMethod('post');
$this->result = false;
SimpleRouter::get('/my/test/url', 'DummyController@start');
SimpleRouter::group(['domain' => '{subdomain}.world.com'], function () {
SimpleRouter::get('/test', function ($subdomain = null) {
$this->result = ($subdomain === 'hello');
});
});
try {
SimpleRouter::start();
} catch (\Exception $e) {
$this->assertEquals(403, $e->getCode());
}
}
SimpleRouter::start();
public function testSimpleParam()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test-param1');
$this->assertTrue($this->result);
SimpleRouter::get('/test-{param1}', 'DummyController@param');
SimpleRouter::start();
}
}
public function testPathParamRegex()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test/path/123123');
SimpleRouter::get('/test/path/{myParam}', 'DummyController@param', ['where' => ['myParam' => '([0-9]+)']]);
SimpleRouter::start();
}
public function testDomainRoute()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/test');
SimpleRouter::request()->setHost('hello.world.com');
$this->result = false;
SimpleRouter::group(['domain' => '{subdomain}.world.com'], function () {
SimpleRouter::get('/test', function ($subdomain = null) {
$this->result = ($subdomain === 'hello');
});
});
SimpleRouter::start();
$this->assertTrue($this->result);
}
}
+59 -58
View File
@@ -8,94 +8,95 @@ use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
class RouterUrlTest extends PHPUnit_Framework_TestCase
{
protected $result = false;
protected $result = false;
protected function getUrl($name = null, $parameters = null, array $getParams = []) {
return SimpleRouter::getUrl($name, $parameters, $getParams);
}
protected function getUrl($name = null, $parameters = null, array $getParams = [])
{
return SimpleRouter::getUrl($name, $parameters, $getParams);
}
public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/');
public function testUrls()
{
SimpleRouter::router()->reset();
SimpleRouter::request()->setMethod('get');
SimpleRouter::request()->setUri('/');
// Match normal route on alias
SimpleRouter::get('/', 'DummyController@silent', ['as' => 'home']);
// Match normal route on alias
SimpleRouter::get('/', 'DummyController@silent', ['as' => 'home']);
SimpleRouter::get('/about', 'DummyController@about');
SimpleRouter::get('/about', 'DummyController@about');
SimpleRouter::group(['prefix' => '/admin', 'as' => 'admin'], function() {
SimpleRouter::group(['prefix' => '/admin', 'as' => 'admin'], function () {
// Match route with prefix on alias
SimpleRouter::get('/{id?}', 'DummyController@start', ['as' => 'home']);
// Match route with prefix on alias
SimpleRouter::get('/{id?}', 'DummyController@start', ['as' => 'home']);
// Match controller with prefix and alias
SimpleRouter::controller('/users', 'DummyController', ['as' => 'users']);
// Match controller with prefix and alias
SimpleRouter::controller('/users', 'DummyController', ['as' => 'users']);
// Match controller with prefix and NO alias
SimpleRouter::controller('/pages', 'DummyController');
// Match controller with prefix and NO alias
SimpleRouter::controller('/pages', 'DummyController');
});
});
SimpleRouter::group(['prefix' => 'api', 'as' => 'api'], function() {
SimpleRouter::group(['prefix' => 'api', 'as' => 'api'], function () {
// Match resource controller
SimpleRouter::resource('phones', 'DummyController');
// Match resource controller
SimpleRouter::resource('phones', 'DummyController');
});
});
SimpleRouter::controller('gadgets', 'DummyController', ['names' => ['getIphoneInfo' => 'iphone']]);
SimpleRouter::controller('gadgets', 'DummyController', ['names' => ['getIphoneInfo' => 'iphone']]);
// Match controller with no prefix and no alias
SimpleRouter::controller('/cats', 'CatsController');
// Match controller with no prefix and no alias
SimpleRouter::controller('/cats', 'CatsController');
// Pretend to load page
SimpleRouter::start();
// Pretend to load page
SimpleRouter::start();
$this->assertEquals('/gadgets/iphoneinfo/', $this->getUrl('gadgets.iphone'));
$this->assertEquals('/gadgets/iphoneinfo/', $this->getUrl('gadgets.iphone'));
$this->assertEquals('/api/phones/create/', $this->getUrl('api.phones.create'));
$this->assertEquals('/api/phones/create/', $this->getUrl('api.phones.create'));
// Should match /
$this->assertEquals('/', $this->getUrl('home'));
// Should match /
$this->assertEquals('/', $this->getUrl('home'));
// Should match /about/
$this->assertEquals('/about/', $this->getUrl('DummyController@about'));
// Should match /about/
$this->assertEquals('/about/', $this->getUrl('DummyController@about'));
// Should match /admin/
$this->assertEquals('/admin/', $this->getUrl('DummyController@start'));
// Should match /admin/
$this->assertEquals('/admin/', $this->getUrl('DummyController@start'));
// Should match /admin/
$this->assertEquals('/admin/', $this->getUrl('admin.home'));
// Should match /admin/
$this->assertEquals('/admin/', $this->getUrl('admin.home'));
// Should match /admin/2/
$this->assertEquals('/admin/2/', $this->getUrl('admin.home', ['id' => 2]));
// Should match /admin/2/
$this->assertEquals('/admin/2/', $this->getUrl('admin.home', ['id' => 2]));
// Should match /admin/users/
$this->assertEquals('/admin/users/', $this->getUrl('admin.users'));
// Should match /admin/users/
$this->assertEquals('/admin/users/', $this->getUrl('admin.users'));
// Should match /admin/users/home/
$this->assertEquals('/admin/users/home/', $this->getUrl('admin.users@home'));
// Should match /admin/users/home/
$this->assertEquals('/admin/users/home/', $this->getUrl('admin.users@home'));
// Should match /cats/
$this->assertEquals('/cats/', $this->getUrl('CatsController'));
// Should match /cats/
$this->assertEquals('/cats/', $this->getUrl('CatsController'));
// Should match /cats/view/
$this->assertEquals('/cats/view/', $this->getUrl('CatsController', 'view'));
// Should match /cats/view/
$this->assertEquals('/cats/view/', $this->getUrl('CatsController', 'view'));
// Should match /cats/view/
//$this->assertEquals('/cats/view/', $this->getUrl('CatsController', ['view']));
// Should match /cats/view/
//$this->assertEquals('/cats/view/', $this->getUrl('CatsController', ['view']));
// Should match /cats/view/666
$this->assertEquals('/cats/view/666/', $this->getUrl('CatsController@getView', ['666']));
// Should match /cats/view/666
$this->assertEquals('/cats/view/666/', $this->getUrl('CatsController@getView', ['666']));
// Should match /funny/man/
$this->assertEquals('/funny/man/', $this->getUrl('/funny/man'));
// Should match /funny/man/
$this->assertEquals('/funny/man/', $this->getUrl('/funny/man'));
// Should match /?jackdaniels=true&cola=yeah
$this->assertEquals('/?jackdaniels=true&cola=yeah', $this->getUrl('home', null, ['jackdaniels' => 'true', 'cola' => 'yeah']));
// Should match /?jackdaniels=true&cola=yeah
$this->assertEquals('/?jackdaniels=true&cola=yeah', $this->getUrl('home', null, ['jackdaniels' => 'true', 'cola' => 'yeah']));
}
}
}