mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-17 16:57:53 +00:00
Compare commits
281 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e7319de06 | |||
| 5ad7dcf9fd | |||
| 531b35532b | |||
| dfd32c0904 | |||
| c258f937e8 | |||
| efe5767220 | |||
| 5415d73f4d | |||
| 60c0bd6355 | |||
| 8370d3d94e | |||
| df3acb6605 | |||
| 88d58cd7b7 | |||
| 4a48a3fcf9 | |||
| d04c74ccad | |||
| 9922dcc552 | |||
| 87d619ca24 | |||
| 7e63197252 | |||
| 02809a4daf | |||
| ba719cf880 | |||
| da6b5af19f | |||
| 808d59d3d3 | |||
| 914ec9d1b7 | |||
| d1f33d9b01 | |||
| 5f72755a98 | |||
| d4a04920b8 | |||
| 4e12cb8bc3 | |||
| 8f33cc1a39 | |||
| ed1ac74e7a | |||
| 41d15d3acd | |||
| a4447313f6 | |||
| ded9c8ebe0 | |||
| 99f869b57d | |||
| 394f7beb8b | |||
| c94523740b | |||
| 305c0ab7c8 | |||
| baab004482 | |||
| eb160ff7bb | |||
| 00c0cad211 | |||
| 2db0601e20 | |||
| c6e85676da | |||
| c59ab12e1a | |||
| 5a74c9d27d | |||
| b298665d33 | |||
| 9ba531d559 | |||
| 73ee4521bc | |||
| b5f8d9410f | |||
| b5eef6f3ee | |||
| 75566dc2ba | |||
| ad0eceb814 | |||
| 8478899eb6 | |||
| 4bec2bc5fb | |||
| 93562bd758 | |||
| 4f47463497 | |||
| 9c413a3c53 | |||
| 669d318a12 | |||
| 9513e38009 | |||
| a13bcd4768 | |||
| 83c73a4240 | |||
| bc14790a67 | |||
| d5e7a13d89 | |||
| e5c86c1822 | |||
| 6de0700e17 | |||
| 32c305bd2c | |||
| 28ffa30d3e | |||
| 540ebb31ac | |||
| 48317ded7a | |||
| 28c3370b67 | |||
| 7ee42c98a7 | |||
| 8740db9582 | |||
| 2d57b45c7b | |||
| 98cc8504d4 | |||
| 035a5b1629 | |||
| 832aff0358 | |||
| 43e05ad821 | |||
| 2fd32868c2 | |||
| e51b72f0e0 | |||
| 3b5e2aee9d | |||
| 27ba532b2d | |||
| a8620cbc70 | |||
| 4e054dccf5 | |||
| e7dfbb159c | |||
| 8c5a5327d1 | |||
| 3c9a675f25 | |||
| dfccd99f2f | |||
| 980a4e9b6a | |||
| fab0d0641c | |||
| 4169716f87 | |||
| 53e5b5362f | |||
| 6780b24e59 | |||
| b540c01650 | |||
| eb8832beec | |||
| eeafcb7862 | |||
| 1a9351c690 | |||
| f98e5ac59d | |||
| a2dbf4149b | |||
| ba736b47a3 | |||
| 6ab1200fd5 | |||
| 67a00c6800 | |||
| 1420203149 | |||
| f7af53a9af | |||
| 6b8351f1b8 | |||
| eb3ddf2bf7 | |||
| 2afe784f47 | |||
| 94e98ad5f0 | |||
| 8f24256434 | |||
| ec355c90b5 | |||
| a8633b5c51 | |||
| 7fdeef74d6 | |||
| 17adfb8aa4 | |||
| 7a429cec1d | |||
| 3da7c4b446 | |||
| f3ac9dc47c | |||
| 22563671c5 | |||
| 491e920cfc | |||
| 6cef099110 | |||
| 5f95290e4b | |||
| 7234415e24 | |||
| 257875c6f9 | |||
| 9b743e6e57 | |||
| 457dbc5710 | |||
| fc4fd0edf1 | |||
| 2f2c3ca3ca | |||
| b34738a51a | |||
| 975c27659c | |||
| 27371dfa11 | |||
| 6e102711a8 | |||
| 4d58fbf7b5 | |||
| 35bb58818e | |||
| 438d3c258b | |||
| a58ec1544d | |||
| 1bafbab56b | |||
| 6395801a06 | |||
| 060479f1fe | |||
| b29f2ce37d | |||
| 5483ffe458 | |||
| 6d8e95fcaa | |||
| db78135d19 | |||
| c4fcf750d4 | |||
| a92b6008fa | |||
| 115c8e510a | |||
| 35ee79d02c | |||
| 6306b604e8 | |||
| 4dd0739df9 | |||
| 0bd234d996 | |||
| 27d24758b1 | |||
| 4d08f08c68 | |||
| aeacda1812 | |||
| 765204f552 | |||
| 4267cb8751 | |||
| 714edf7902 | |||
| c3b12ba053 | |||
| b096742d6b | |||
| 3298970798 | |||
| bb6f56ef8c | |||
| 6c675124fa | |||
| 14a030294e | |||
| 8bc8124366 | |||
| 1332ef7139 | |||
| 12bbc98a82 | |||
| 69b0f4320e | |||
| 4c60055c7e | |||
| 89aeeeb593 | |||
| 849749969d | |||
| c37a7159d2 | |||
| df2545dd37 | |||
| bd0a6af41f | |||
| 3510c4c5a4 | |||
| 7ff88bc658 | |||
| ce27196083 | |||
| 9304b9f866 | |||
| ed886cb7b3 | |||
| cbaa0bcaac | |||
| 98b1759967 | |||
| b9be7695a7 | |||
| 97e2edd207 | |||
| 87fbbcbba2 | |||
| 5a501db767 | |||
| 669bfa0a86 | |||
| 4f07f38cf5 | |||
| c67ab20ddd | |||
| ad1ce21c66 | |||
| 5a19d6339c | |||
| 23ee53060e | |||
| 77ba9f165e | |||
| 4dd6417f71 | |||
| 3012435caa | |||
| 0bec524606 | |||
| d4e9ef7744 | |||
| cede827a45 | |||
| 9da90d1435 | |||
| 4d70efcc4d | |||
| e1c549bfdb | |||
| b9f426989b | |||
| f1f5faa81e | |||
| 6c56947792 | |||
| 925b9761f4 | |||
| 59956d5fca | |||
| 3ba2cec8af | |||
| d36880e9a0 | |||
| c74d83796f | |||
| 2128a24f1c | |||
| 6ee3153f8f | |||
| b1768d86f7 | |||
| 03f90a160b | |||
| 1d8e7c2caf | |||
| 4447a88894 | |||
| 8efec07a8b | |||
| 4d45e34541 | |||
| a9e7a33ff8 | |||
| 6805a79d50 | |||
| 5393aa3200 | |||
| f2ffd83376 | |||
| 5a398f03a6 | |||
| 866832faa6 | |||
| c4bff83ac4 | |||
| 5ca8294015 | |||
| 6e98f8e20b | |||
| 3533ff8906 | |||
| f2fd5261c1 | |||
| 02de9572fa | |||
| e2a618fadd | |||
| e5700477e0 | |||
| 750817e451 | |||
| 3b4954821a | |||
| 5c36e9c652 | |||
| b930c06683 | |||
| 0f8bba7c32 | |||
| 19dc295199 | |||
| c93e0f2ce6 | |||
| 388c027d04 | |||
| 2c8e65f25b | |||
| eb93584d85 | |||
| bd5d17b6fb | |||
| 7c0ac390fd | |||
| 3fc81b6492 | |||
| b400b86322 | |||
| 1d338e9aa9 | |||
| 889ceaa37f | |||
| 363338c92f | |||
| 3dd9dba029 | |||
| be277f276f | |||
| f215eaa9cf | |||
| 933f2370fe | |||
| b3f8910cab | |||
| 8557741083 | |||
| c60d7d81c1 | |||
| 637b998f02 | |||
| aca7d3d503 | |||
| 846c9e6584 | |||
| 0df469184c | |||
| 649ed28a91 | |||
| 5cb7086e96 | |||
| a2edc1504c | |||
| d31cda8e70 | |||
| 921f050a31 | |||
| dcbf59b305 | |||
| bc16388613 | |||
| d3ed3a61b5 | |||
| 969b64650e | |||
| c2cf2334e7 | |||
| af730e6e15 | |||
| f5a32cf520 | |||
| 1843ea0594 | |||
| fd28f4549f | |||
| 5e5a424ee8 | |||
| 099f04fc10 | |||
| ac2993f804 | |||
| 99da70874e | |||
| 2a66350883 | |||
| c95a5291d3 | |||
| 20fc067765 | |||
| cbb4294f58 | |||
| d6bdcbe70c | |||
| 25f569384f | |||
| b37c73d5dd | |||
| f5597c24ce | |||
| b8061f2aa7 | |||
| 6c7ac2b250 | |||
| d2de22e5e0 | |||
| 252fb16326 | |||
| 63dfbb24af | |||
| 3ccfac9422 |
+3
-1
@@ -1,2 +1,4 @@
|
||||
.idea
|
||||
composer.lock
|
||||
composer.lock
|
||||
vendor/
|
||||
demo-project/vendor
|
||||
@@ -1,25 +1,24 @@
|
||||
# Simple PHP router
|
||||
Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.
|
||||
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expandability in mind.
|
||||
|
||||
## Installation
|
||||
Add the latest version pf Simple PHP Router to your ```composer.json```
|
||||
Add the latest version of Simple PHP Router running this command.
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"pecee/simple-php-router": "1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"pecee/simple-php-router": "1.*"
|
||||
}
|
||||
}
|
||||
```
|
||||
composer require pecee/simple-router
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 5.4 or greater
|
||||
|
||||
## Notes
|
||||
|
||||
The goal of this project is to create a router that is 100% compatible with the Laravel documentation, but as simple as possible and as easy to integrate and change as possible.
|
||||
|
||||
### Features
|
||||
|
||||
- Basic routing (get, post, put, delete) with support for custom multiple verbs.
|
||||
- Basic routing (`GET`, `POST`, `PUT`, `PATCH`, `UPDATE`, `DELETE`) with support for custom multiple verbs.
|
||||
- Regular Expression Constraints for parameters.
|
||||
- Named routes.
|
||||
- Generating url to routes.
|
||||
@@ -28,12 +27,18 @@ Add the latest version pf Simple PHP Router to your ```composer.json```
|
||||
- Namespaces.
|
||||
- Route prefixes.
|
||||
- CSRF protection.
|
||||
- Optional parameters
|
||||
- Sub-domain routing
|
||||
- Custom boot managers to rewrite urls to "nicer" ones.
|
||||
- Input manager; easily manage `GET`, `POST` and `FILE` values.
|
||||
|
||||
### Features currently "in-the-works"
|
||||
## Installation and demo
|
||||
|
||||
- Global Constraints
|
||||
- Sub-Domain Routing
|
||||
- Optional/required parameters
|
||||
We've included a simple demo project for the router which can be found in the `demo-project` folder.
|
||||
|
||||
Please refer to the demo-project documentation for further reading on how to setup and install simple-php-router:
|
||||
|
||||
[Link to demo documentation](demo-project/README.md)
|
||||
|
||||
## Initialising the router
|
||||
|
||||
@@ -42,15 +47,20 @@ In your ```index.php``` require your ```routes.php``` and call the ```routeReque
|
||||
This is an example of a basic ```index.php``` file:
|
||||
|
||||
```php
|
||||
use \Pecee\SimpleRouter;
|
||||
use \Pecee\SimpleRouter\SimpleRouter;
|
||||
|
||||
require_once 'routes.php'; // change this to whatever makes sense in your project
|
||||
// Load external routes file
|
||||
require_once 'routes.php';
|
||||
|
||||
// The apps default namespace (so we don't have to specify it each time we use MyController@home)
|
||||
$defaultControllerNamespace = 'MyWebsite\\Controller';
|
||||
/*
|
||||
* The default namespace for route-callbacks, so we don't have to specify it each time.
|
||||
* Can be overwritten by using the namespace config option on your routes.
|
||||
*/
|
||||
|
||||
SimpleRouter::setDefaultNamespace('MyWebsite');
|
||||
|
||||
// Do the routing
|
||||
SimpleRouter::init($defaultControllerNamespace);
|
||||
// Start the routing
|
||||
SimpleRouter::start();
|
||||
```
|
||||
|
||||
## Adding routes
|
||||
@@ -59,134 +69,234 @@ This router is heavily inspired by the Laravel 5.* router, so anything you find
|
||||
|
||||
### Basic example
|
||||
|
||||
- ExceptionsHandlers must implement the `IExceptionHandler` interface.
|
||||
- Middlewares must implement the `IMiddleware` interface.
|
||||
- Resource controllers can inherit the `IRestController` interface, but is not required.
|
||||
|
||||
```php
|
||||
use Pecee\SimpleRouter\SimpleRouter;
|
||||
|
||||
/*
|
||||
* This route will match the url /v1/services/answers/1/
|
||||
|
||||
* The middleware is just a class that renders before the
|
||||
* Controller or callback is loaded. This is useful for stopping
|
||||
* the request, for instance if a user is not authenticated.
|
||||
* controller or callback is loaded.
|
||||
*
|
||||
* This is useful for stopping the request, for
|
||||
* instance if a user is not authenticated etc.
|
||||
*/
|
||||
|
||||
SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\SomeMiddlewareClass'], function() {
|
||||
|
||||
SimpleRouter::group(['prefix' => 'services'], function() {
|
||||
// Add your csrfVerifier here
|
||||
|
||||
SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show')
|
||||
->where(['id' => '[0-9]+');
|
||||
SimpleRouter::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
|
||||
|
||||
/**
|
||||
* This example will route url when matching the regular expression to the method.
|
||||
* For example route: /ajax/music/world -> ControllerAjax@process (parameter: music/world)
|
||||
*/
|
||||
SimpleRouter::all('/ajax', 'ControllerAjax@process')->match('ajax\\/([A-Za-z0-9\\/]+)');
|
||||
SimpleRouter::group(['middleware' => 'Middlewares\Site', 'exceptionHandler' => 'Handlers\CustomExceptionHandler'], function() {
|
||||
|
||||
// Resetful resource
|
||||
SimpleRouter::resource('/rest', 'ControllerRessource');
|
||||
|
||||
// Load the entire controller (where url matches method names - getIndex(), postIndex() etc)
|
||||
SimpleRouter::controller('/controller', 'ControllerDefault');
|
||||
SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' => ['id' => '[0-9]+']]);
|
||||
|
||||
// Example of providing callback instead of Controller
|
||||
SimpleRouter::get('/something', function() {
|
||||
die('Callback example');
|
||||
});
|
||||
/**
|
||||
* Using optional parameters
|
||||
*/
|
||||
SimpleRouter::get('/answers/{id?}', 'ControllerAnswers@show');
|
||||
|
||||
|
||||
/**
|
||||
* This example will route url when matching the regular expression to the method.
|
||||
* For example route: domain.com/ajax/music/world -> ControllerAjax@process (parameter: music/world)
|
||||
*/
|
||||
|
||||
SimpleRouter::all('/ajax', 'ControllerAjax@process')->setMatch('.*?\\/ajax\\/([A-Za-z0-9\\/]+)');
|
||||
|
||||
|
||||
/**
|
||||
* Restful resource (see IRestController interface for available methods)
|
||||
*/
|
||||
|
||||
SimpleRouter::resource('/rest', 'ControllerRessource');
|
||||
|
||||
|
||||
/**
|
||||
* Load the entire controller (where url matches method names - getIndex(), postIndex(), putIndex()).
|
||||
* The url paths will determine which method to render.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* GET /animals => getIndex()
|
||||
* GET /animals/view => getView()
|
||||
* POST /animals/save => postSave()
|
||||
*
|
||||
* etc.
|
||||
*/
|
||||
|
||||
SimpleRouter::controller('/animals', 'ControllerAnimals');
|
||||
|
||||
|
||||
/**
|
||||
* Example of providing callback instead of Controller
|
||||
*/
|
||||
|
||||
SimpleRouter::post('/something', function() {
|
||||
|
||||
die('Callback example');
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfound']);
|
||||
|
||||
```
|
||||
|
||||
#### ExceptionHandler example
|
||||
|
||||
This is a basic example of an ExceptionHandler implementation:
|
||||
|
||||
```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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Sub-domain routing
|
||||
|
||||
Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the ```domain``` key on the group attribute array:
|
||||
|
||||
```php
|
||||
Route::group(['domain' => '{account}.myapp.com'], function () {
|
||||
|
||||
Route::get('user/{id}', function ($account, $id) {
|
||||
// Do stuff...
|
||||
});
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### Doing it the object oriented (hardcore) way
|
||||
The prefix group array attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:
|
||||
|
||||
The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```RouterBase``` class.
|
||||
### Adding routes manually (with no helper)
|
||||
|
||||
The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```Router``` class.
|
||||
If you are up for a challenge, want the full control or simply just want to create your own ```Router``` helper class, this example is for you.
|
||||
|
||||
```php
|
||||
use \Pecee\SimpleRouter\RouterBase;
|
||||
use \Pecee\SimpleRouter\RouterRoute;
|
||||
use \Pecee\SimpleRouter\Router;
|
||||
use \Pecee\SimpleRouter\Route\RouteUrl;
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
/* Grap the router instance */
|
||||
$router = Router::getInstance();
|
||||
|
||||
$route = new RouteUrl('/answer/1', function() {
|
||||
|
||||
$route = new RouterRoute('/answer/1', function() {
|
||||
die('this callback will match /answer/1');
|
||||
|
||||
});
|
||||
|
||||
$route->setMiddleware('\HSWebserviceV1\Middleware\AuthMiddleware');
|
||||
$route->setMiddleware('\Demo\Middlewares\AuthMiddleware');
|
||||
$route->setNamespace('MyWebsite');
|
||||
$route->setPrefix('v1');
|
||||
|
||||
// Add the route to the router
|
||||
/* Add the route to the router */
|
||||
$router->addRoute($route);
|
||||
```
|
||||
|
||||
### Extending
|
||||
|
||||
This is a simple example of an integration into a framework.
|
||||
|
||||
The framework has it's own ```Router``` class which inherits from the ```SimpleRouter``` class. This allows the framework to add custom functionality.
|
||||
The framework has it's own ```Router``` class which inherits from the ```SimpleRouter``` class. This allows the framework to add custom functionality like loading a custom `routes.php` file or add debugging information etc.
|
||||
|
||||
```php
|
||||
namespace MyProject;
|
||||
namespace Demo;
|
||||
|
||||
use Pecee\Handler\ExceptionHandler;
|
||||
use Pecee\SimpleRouter\SimpleRouter;
|
||||
|
||||
class Router extends SimpleRouter {
|
||||
|
||||
protected static $exceptionHandlers = array();
|
||||
|
||||
public static function start() {
|
||||
|
||||
Debug::getInstance()->add('Router initialised.');
|
||||
|
||||
// Load routes.php
|
||||
$file = $_ENV['basePath'] . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'routes.php';
|
||||
if(file_exists($file)) {
|
||||
require_once $file;
|
||||
}
|
||||
|
||||
// Init locale settings
|
||||
Locale::getInstance();
|
||||
|
||||
// Set default namespace for routes
|
||||
$defaultNamespace = '\\'.Registry::getInstance()->get('AppName') . '\\Controller';
|
||||
// change this to whatever makes sense in your project
|
||||
require_once 'routes.php';
|
||||
|
||||
// Add custom csrf verifier (must extend BaseCsrfVerifier)
|
||||
parent::csrfVerifier('MyProject\Middleware\CustomCsrfVerifier');
|
||||
// change default namespace for all routes
|
||||
parent::setDefaultNamespace('\Demo');
|
||||
|
||||
// Handle exceptions
|
||||
try {
|
||||
parent::start($defaultNamespace);
|
||||
} catch(\Exception $e) {
|
||||
/* @var $handler ExceptionHandler */
|
||||
foreach(self::$exceptionHandlers as $handler) {
|
||||
$class = new $handler();
|
||||
$class->handleError($e);
|
||||
}
|
||||
// Do initial stuff
|
||||
parent::start();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public static function addExceptionHandler($handler) {
|
||||
self::$exceptionHandlers[] = $handler;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
This is a basic example of a helper function for generating urls.
|
||||
## Helper functions
|
||||
|
||||
To simplify to use of simple-router functionality, we recommend you add these helper functions to your project.
|
||||
|
||||
```php
|
||||
use Pecee\SimpleRouter\RouterBase;
|
||||
function url($controller, $parameters = null, $getParams = null) {
|
||||
RouterBase::getInstance()->getRoute($controller, $parameters, $getParams);
|
||||
use Pecee\SimpleRouter\SimpleRouter;
|
||||
|
||||
/**
|
||||
* 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 $getParams
|
||||
* @return string
|
||||
*/
|
||||
function url($name = null, $parameters = null, array $getParams = array()) {
|
||||
SimpleRouter::getUrl($name, $parameters, $getParams);
|
||||
}
|
||||
```
|
||||
|
||||
This is a basic example for getting the current csrf token
|
||||
|
||||
```php
|
||||
/**
|
||||
* Get current csrf-token
|
||||
* @return null|string
|
||||
@@ -195,26 +305,101 @@ 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();
|
||||
}
|
||||
```
|
||||
|
||||
## Getting urls
|
||||
|
||||
**In ```routes.php``` we have added this route:**
|
||||
By default all controller and resource routes will use a simplified version of their url as name.
|
||||
|
||||
**Get routes using custom name (single route)**
|
||||
|
||||
```php
|
||||
SimpleRouter::get('/item/{id}', 'myController@show', ['as' => 'item']);
|
||||
SimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' => 'product']);
|
||||
|
||||
url('product', ['id' => 22], ['category' => 'shoes']);
|
||||
|
||||
# output
|
||||
# /product-view/22/?category=shoes
|
||||
```
|
||||
|
||||
**In the template we then call:**
|
||||
**Getting the url using the name (controller route)**
|
||||
|
||||
```php
|
||||
url('item', ['id' => 22], ['category' => 'shoes']);
|
||||
SimpleRouter::controller('/images', 'ImagesController', ['as' => 'picture']);
|
||||
|
||||
url('picture@getView', null, ['category' => 'shoes']);
|
||||
url('picture', 'getView', ['category' => 'shoes']);
|
||||
|
||||
# output
|
||||
# /images/view/?category=shows
|
||||
# /images/view/?category=shows
|
||||
```
|
||||
|
||||
**Result url is:**
|
||||
**Getting the url using class**
|
||||
|
||||
```php
|
||||
/item/22/?category=shoes
|
||||
SimpleRouter::get('/product-view/{id}', 'ProductsController@show', ['as' => 'product']);
|
||||
SimpleRouter::controller('/images', 'ImagesController');
|
||||
|
||||
url('ProductsController@show', ['id' => 22], ['category' => 'shoes']);
|
||||
url('ImagesController@getImage', null, ['id' => 22]);
|
||||
|
||||
# output
|
||||
# /product-view/22/?category=shoes
|
||||
# /images/image/?category=shows
|
||||
```
|
||||
|
||||
**Using custom names for methods on a controller/resource route**
|
||||
|
||||
```php
|
||||
SimpleRouter::controller('gadgets', 'GadgetsController', ['names' => ['getIphoneInfo' => 'iphone']]);
|
||||
|
||||
url('gadgets.iphone');
|
||||
|
||||
# output
|
||||
# /gadgets/iphoneinfo/
|
||||
```
|
||||
|
||||
**Getting REST/resource controller urls**
|
||||
|
||||
```php
|
||||
SimpleRouter::resource('/phones', 'PhonesController');
|
||||
|
||||
url('phones');
|
||||
url('phones.index');
|
||||
url('phones.create');
|
||||
url('phones.edit');
|
||||
|
||||
// etc..
|
||||
|
||||
# output
|
||||
# /phones/
|
||||
# /phones/create/
|
||||
# /phones/edit/
|
||||
```
|
||||
|
||||
## Custom CSRF verifier
|
||||
@@ -229,8 +414,11 @@ Querystrings are ignored.
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
|
||||
class CsrfVerifier extends BaseCsrfVerifier {
|
||||
|
||||
protected $except = ['/companies/*', '/user/save'];
|
||||
|
||||
protected $except = [
|
||||
'/companies/*',
|
||||
'/api',
|
||||
];
|
||||
|
||||
}
|
||||
```
|
||||
@@ -241,6 +429,200 @@ Register the new class in your ```routes.php```, custom ```Router``` class or wh
|
||||
SimpleRouter::csrfVerifier(new \Demo\Middleware\CsrfVerifier());
|
||||
```
|
||||
|
||||
## Using router bootmanager to make custom rewrite rules
|
||||
|
||||
Sometimes it can be necessary to keep urls stored in the database, file or similar. In this example, we want the url ```/my-cat-is-beatiful``` to load the route ```/article/view/1``` which the router knows, because it's defined in the ```routes.php``` file.
|
||||
|
||||
To interfere with the router, we create a class that implements the ```IRouterBootManager``` interface. This class will be loaded before any other rules in ```routes.php``` and allow us to "change" the current route, if any of our criteria are fulfilled (like coming from the url ```/my-cat-is-beatiful```).
|
||||
|
||||
```php
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\IRouterBootManager;
|
||||
|
||||
class CustomRouterRules implement IRouterBootManager {
|
||||
|
||||
public function boot(Request $request) {
|
||||
|
||||
$rewriteRules = [
|
||||
'/my-cat-is-beatiful' => '/article/view/1',
|
||||
'/horses-are-great' => '/article/view/2'
|
||||
];
|
||||
|
||||
foreach($rewriteRules as $url => $rule) {
|
||||
|
||||
// If the current uri matches the url, we use our custom route
|
||||
|
||||
if($request->getUri() === $url) {
|
||||
$request->setUri($rule);
|
||||
}
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The above should be pretty self-explanatory and can easily be changed to loop through urls store in the database, file or cache.
|
||||
|
||||
What happens is that if the current route matches the route defined in the index of our ```$rewriteRules``` array, we set the route to the array value instead.
|
||||
|
||||
By doing this the route will now load the url ```/article/view/1``` instead of ```/my-cat-is-beatiful```.
|
||||
|
||||
The last thing we need to do, is to add our custom boot-manager to the ```routes.php``` file. You can create as many bootmanagers as you like and easily add them in your ```routes.php``` file.
|
||||
|
||||
## Easily overwrite route about to be loaded
|
||||
Sometimes it can be useful to manipulate the route about to be loaded.
|
||||
simple-php-router allows you to easily change the route about to be executed.
|
||||
All information about the current route is stored in the ```\Pecee\SimpleRouter\Router``` instance's `loadedRoute` property.
|
||||
|
||||
For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::router()`.
|
||||
|
||||
|
||||
```php
|
||||
use Pecee\SimpleRouter;
|
||||
$route = SimpleRouter::router()->getLoadedRoute();
|
||||
|
||||
$route->setCallback('Example\MyCustomClass@hello');
|
||||
|
||||
// -- or you can rewrite by doing --
|
||||
|
||||
$route->setClass('Example\MyCustomClass');
|
||||
$route->setMethod('hello');
|
||||
```
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
It's only possible to change the route BEFORE the route has initially been loaded. If you want to redirect to another route, we highly recommend that you
|
||||
modify the `IRoute` object from a `Middleware` or `ExceptionHandler`, like the examples below.
|
||||
|
||||
#### Rewriting to new route
|
||||
|
||||
The example below will cause the router to re-route the request with another url. We are using the `url()` helper function to get the uri to another route added in the `routes.php` file.
|
||||
|
||||
**NOTE: Use this method if you want to fully load another route using it's settings (request method etc).**
|
||||
|
||||
|
||||
```php
|
||||
namespace Demo\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
class CustomMiddleware implements Middleware {
|
||||
|
||||
public function handle(Request $request, ILoadableRoute &$route) {
|
||||
|
||||
$request->setUri(url('home'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### Changing callback
|
||||
You can also change the callback by modifying the `$route` parameter. This is perfect if you just want to display a view quickly - or change the callback depending
|
||||
on some criteria's for the request.
|
||||
|
||||
The callback below will fire immediately after the `Middleware` or `ExceptionHandler` has been loaded, as they are loaded before the route is rendered.
|
||||
If you wish to change the callback from outside, please have this in mind.
|
||||
|
||||
**NOTE: Use this method if you want to load another controller. No additional middlewares or rules will be loaded.**
|
||||
|
||||
```php
|
||||
namespace Demo\Middlewares;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
class CustomMiddleware implements Middleware {
|
||||
|
||||
public function handle(Request $request, ILoadableRoute &$route) {
|
||||
|
||||
$route->callback('DefaultController@home');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Using the Input class to manage parameters
|
||||
|
||||
We've added the `Input` class to easy access parameters from your Controller-classes.
|
||||
|
||||
**Return single parameter value (matches both GET, POST, FILE):**
|
||||
|
||||
```php
|
||||
$value = input()->get('name');
|
||||
```
|
||||
|
||||
**Return parameter object (matches both GET, POST, FILE):**
|
||||
|
||||
```php
|
||||
$object = input()->getObject('name');
|
||||
```
|
||||
|
||||
**Return specific GET parameter (where name is the name of your parameter):**
|
||||
|
||||
```php
|
||||
$object = input()->get->name;
|
||||
$object = input()->post->name;
|
||||
$object = input()->file->name;
|
||||
|
||||
# -- or --
|
||||
|
||||
$object = input()->get->get($key, $defaultValue);
|
||||
$object = input()->post->get($key, $defaultValue);
|
||||
$object = input()->file->get($key, $defaultValue);
|
||||
```
|
||||
|
||||
**Return all parameters:**
|
||||
|
||||
```php
|
||||
// Get all
|
||||
$values = input()->all();
|
||||
|
||||
// Only match certain keys
|
||||
$values = input()->all([
|
||||
'company_name',
|
||||
'user_id'
|
||||
]);
|
||||
```
|
||||
|
||||
All object inherits from `InputItem` class and will always contain these methods:
|
||||
|
||||
- `getValue()` - returns the value of the input.
|
||||
- `getIndex()` - returns the index/key of the input.
|
||||
- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).
|
||||
|
||||
`InputFile` has the same methods as above along with some other file-specific methods like:
|
||||
- `getTmpName()` - get file temporary name.
|
||||
- `getSize()` - get file size.
|
||||
- `move($destination)` - move file to destination.
|
||||
- `getContents()` - get file content.
|
||||
- `getType()` - get mime-type for file.
|
||||
- `getError()` - get file upload error.
|
||||
|
||||
Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation.
|
||||
|
||||
```php
|
||||
// Get parameter site_id or default-value 2
|
||||
$siteId = input()->get('site_id', 2);
|
||||
```
|
||||
|
||||
## Sites
|
||||
This is some sites that uses the simple-router project in production.
|
||||
|
||||
- [holla.dk](http://www.holla.dk)
|
||||
- [ninjaimg.com](http://ninjaimg.com)
|
||||
- [bookandbegin.com](https://bookandbegin.com)
|
||||
- [dscuz.com](https://www.dscuz.com)
|
||||
|
||||
## Documentation
|
||||
While I work on a better documentation, please refer to the Laravel 5 routing documentation here:
|
||||
|
||||
@@ -249,9 +631,12 @@ http://laravel.com/docs/5.1/routing
|
||||
## Easily extendable
|
||||
The router can be easily extended to customize your needs.
|
||||
|
||||
## Ideas and issues
|
||||
If you want a great new feature or experience any issues what-so-ever, please feel free to leave an issue and i'll look into it whenever possible.
|
||||
|
||||
## The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Simon Sessing� / simple-php-router
|
||||
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
|
||||
@@ -269,4 +654,4 @@ 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.
|
||||
SOFTWARE.
|
||||
|
||||
+2
-2
@@ -13,14 +13,14 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.7.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Pecee\\": "src/"
|
||||
"Pecee\\": "src/Pecee/"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,16 @@
|
||||
<?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
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?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/*'];
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"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/"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
RewriteEngine on
|
||||
RewriteCond %{SCRIPT_FILENAME} !-f
|
||||
RewriteCond %{SCRIPT_FILENAME} !-d
|
||||
RewriteCond %{SCRIPT_FILENAME} !-l
|
||||
RewriteRule ^(.*)$ index.php/$1
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
// load composer dependencies
|
||||
require '../vendor/autoload.php';
|
||||
|
||||
// Start the routing
|
||||
\Demo\Router::start();
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace Pecee\Controllers;
|
||||
|
||||
interface IRestController {
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function index();
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return void
|
||||
*/
|
||||
function show($id);
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function store();
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function create();
|
||||
|
||||
/**
|
||||
* View
|
||||
* @param mixed $id
|
||||
* @return void
|
||||
*/
|
||||
function edit($id);
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return void
|
||||
*/
|
||||
function update($id);
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return void
|
||||
*/
|
||||
function destroy($id);
|
||||
|
||||
}
|
||||
+57
-49
@@ -1,60 +1,68 @@
|
||||
<?php
|
||||
namespace Pecee;
|
||||
|
||||
class CsrfToken {
|
||||
class CsrfToken
|
||||
{
|
||||
const CSRF_KEY = 'XSRF-TOKEN';
|
||||
|
||||
const CSRF_KEY = 'XSRF-TOKEN';
|
||||
protected $token;
|
||||
|
||||
protected $token;
|
||||
/**
|
||||
* Generate random identifier for CSRF token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generateToken()
|
||||
{
|
||||
if (function_exists('mcrypt_create_iv')) {
|
||||
return bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
|
||||
}
|
||||
return bin2hex(openssl_random_pseudo_bytes(32));
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
if($this->getToken() === null) {
|
||||
$this->setToken($this->generateToken());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Get csrf token
|
||||
* @return string|null
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
if ($this->hasToken()) {
|
||||
return $_COOKIE[static::CSRF_KEY];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set csrf token cookie
|
||||
*
|
||||
* @param $token
|
||||
*/
|
||||
public function setToken($token) {
|
||||
setcookie(self::CSRF_KEY, $token, time() + 60 * 120, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get csrf token
|
||||
* @return string|null
|
||||
*/
|
||||
public function getToken(){
|
||||
if(isset($_COOKIE[self::CSRF_KEY])) {
|
||||
return $_COOKIE[self::CSRF_KEY];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns whether the csrf token has been defined
|
||||
* @return bool
|
||||
*/
|
||||
public function hasToken()
|
||||
{
|
||||
return isset($_COOKIE[static::CSRF_KEY]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace Pecee\Handlers;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
namespace Pecee\Http\Input;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class Input
|
||||
{
|
||||
/**
|
||||
* @var \Pecee\Http\Input\InputCollection
|
||||
*/
|
||||
public $get;
|
||||
|
||||
/**
|
||||
* @var \Pecee\Http\Input\InputCollection
|
||||
*/
|
||||
public $post;
|
||||
|
||||
/**
|
||||
* @var \Pecee\Http\Input\InputCollection
|
||||
*/
|
||||
public $file;
|
||||
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->setGet();
|
||||
$this->setPost();
|
||||
$this->setFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (stripos(trim($contents), '{') === 0) {
|
||||
$output = json_decode($contents, true);
|
||||
if ($output === false) {
|
||||
$output = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output = array_merge($_GET, $output);
|
||||
|
||||
if ($filter !== null) {
|
||||
$output = array_filter($output, function ($key) use ($filter) {
|
||||
if (in_array($key, $filter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
$element = $this->get->findFirst($index);
|
||||
|
||||
if ($element !== null) {
|
||||
return ($key !== null) ? $element[$key] : $element;
|
||||
}
|
||||
|
||||
if ($this->request->getMethod() !== 'get') {
|
||||
|
||||
$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 $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
if ($item !== null) {
|
||||
|
||||
if ($item instanceof InputCollection || $item instanceof InputFile) {
|
||||
return $item;
|
||||
}
|
||||
|
||||
return (trim($item->getValue()) === '') ? $default : $item->getValue();
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
public function exists($index)
|
||||
{
|
||||
return ($this->getObject($index) !== null);
|
||||
}
|
||||
|
||||
public function setGet()
|
||||
{
|
||||
$this->get = new InputCollection();
|
||||
|
||||
if (count($_GET) > 0) {
|
||||
foreach ($_GET as $key => $get) {
|
||||
if (is_array($get) === false) {
|
||||
$this->get->{$key} = new InputItem($key, $get);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output = new InputCollection();
|
||||
|
||||
foreach ($get as $k => $g) {
|
||||
$output->{$k} = new InputItem($k, $g);
|
||||
}
|
||||
|
||||
$this->get->{$key} = $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setPost()
|
||||
{
|
||||
$this->post = new InputCollection();
|
||||
|
||||
$postVars = $_POST;
|
||||
|
||||
if (in_array($this->request->getMethod(), ['put', 'patch', 'delete']) === true) {
|
||||
parse_str(file_get_contents('php://input'), $postVars);
|
||||
}
|
||||
|
||||
if (count($postVars) > 0) {
|
||||
|
||||
foreach ($postVars as $key => $post) {
|
||||
if (is_array($post) === false) {
|
||||
$this->post->{strtolower($key)} = new InputItem($key, $post);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output = new InputCollection();
|
||||
|
||||
foreach ($post as $k => $p) {
|
||||
$output->{$k} = new InputItem($k, $p);
|
||||
}
|
||||
|
||||
$this->post->{strtolower($key)} = $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setFile()
|
||||
{
|
||||
$this->file = new InputCollection();
|
||||
|
||||
if (count($_FILES) > 0) {
|
||||
foreach ($_FILES as $key => $values) {
|
||||
|
||||
// Handle array input
|
||||
if (is_array($values['name']) === false && trim($values['error']) !== '4') {
|
||||
$values['index'] = $key;
|
||||
$this->file->{strtolower($key)} = InputFile::createFromArray($values);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output = new InputCollection();
|
||||
|
||||
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]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->file->{strtolower($key)} = $output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
namespace Pecee\Http\Input;
|
||||
|
||||
class InputFile extends InputItem
|
||||
{
|
||||
public $size;
|
||||
public $type;
|
||||
public $error;
|
||||
public $tmpName;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
public function getMime()
|
||||
{
|
||||
return $this->getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTmpName()
|
||||
{
|
||||
return $this->tmpName;
|
||||
}
|
||||
|
||||
public function getExtension()
|
||||
{
|
||||
return pathinfo($this->getName(), PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
public function move($destination)
|
||||
{
|
||||
return move_uploaded_file($this->tmpName, $destination);
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
return file_get_contents($this->tmpName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file temp. name
|
||||
* @param string $name
|
||||
* @return static $this
|
||||
*/
|
||||
public function setTmpName($name)
|
||||
{
|
||||
$this->tmpName = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set file size
|
||||
* @param int $size
|
||||
* @return static $this
|
||||
*/
|
||||
public function setSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set type
|
||||
* @param string $type
|
||||
* @return static $this
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set error
|
||||
* @param int $error
|
||||
* @return static $this
|
||||
*/
|
||||
public function setError($error)
|
||||
{
|
||||
$this->error = $error;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from array
|
||||
* @param array $values
|
||||
* @return static
|
||||
*/
|
||||
public static function createFromArray(array $values)
|
||||
{
|
||||
if(!isset($values['index'])) {
|
||||
throw new \InvalidArgumentException('Index key is required');
|
||||
}
|
||||
|
||||
$input = new static($values['index']);
|
||||
$input->setTmpName((isset($values['error']) ? $values['error'] : null));
|
||||
$input->setName((isset($values['name']) ? $values['name'] : null));
|
||||
$input->setSize((isset($values['size']) ? $values['size'] : null));
|
||||
$input->setType((isset($values['type']) ? $values['type'] : null));
|
||||
$input->setError((isset($values['tmp_name']) ? $values['tmp_name'] : null));
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->tmpName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
namespace Pecee\Http\Input;
|
||||
|
||||
class InputItem
|
||||
{
|
||||
public $index;
|
||||
public $name;
|
||||
public $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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set input name
|
||||
* @param string $name
|
||||
* @return static $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,64 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Http\Middleware;
|
||||
|
||||
use Pecee\CsrfToken;
|
||||
use Pecee\Exceptions\TokenMismatchException;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\RouterException;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
class BaseCsrfVerifier extends Middleware {
|
||||
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;
|
||||
public function __construct()
|
||||
{
|
||||
$this->csrfToken = new CsrfToken();
|
||||
|
||||
/**
|
||||
* Check if the url matches the urls in the except property
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function skip(Request $request) {
|
||||
// Generate or get the CSRF-Token from Cookie.
|
||||
$this->token = (!$this->hasToken()) ? $this->generateToken() : $this->csrfToken->getToken();
|
||||
}
|
||||
|
||||
if($this->except === null || !is_array($this->except)) {
|
||||
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(), '/'));
|
||||
}
|
||||
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(), '/'));
|
||||
}
|
||||
|
||||
if($skip) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($skip) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handle(Request $request) {
|
||||
public function handle(Request $request, ILoadableRoute &$route = null)
|
||||
{
|
||||
|
||||
if($request->getMethod() != 'get' && !$this->skip($request)) {
|
||||
if ($request->getMethod() !== 'get' && !$this->skip($request)) {
|
||||
|
||||
$token = (isset($_POST[self::POST_KEY])) ? $_POST[self::POST_KEY] : null;
|
||||
$token = $request->getInput()->post->get(static::POST_KEY);
|
||||
|
||||
// If the token is not posted, check headers for valid x-csrf-token
|
||||
if($token === null) {
|
||||
$token = $request->getHeader(self::HEADER_KEY);
|
||||
}
|
||||
// If the token is not posted, check headers for valid x-csrf-token
|
||||
if ($token === null) {
|
||||
$token = $request->getHeader(static::HEADER_KEY);
|
||||
}
|
||||
|
||||
$tokenValidator = new CsrfToken();
|
||||
if( !$tokenValidator->validate( $token ) ) {
|
||||
throw new RouterException('Invalid csrf-token.');
|
||||
}
|
||||
if (!$this->csrfToken->validate($token)) {
|
||||
throw new TokenMismatchException('Invalid csrf-token.');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public function generateToken()
|
||||
{
|
||||
$token = $this->csrfToken->generateToken();
|
||||
$this->csrfToken->setToken($token);
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function hasToken()
|
||||
{
|
||||
if ($this->token != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->csrfToken->hasToken();
|
||||
}
|
||||
|
||||
public function getToken()
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Pecee\Exceptions;
|
||||
|
||||
class TokenMismatchException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace Pecee\Http\Middleware;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
|
||||
interface IMiddleware
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ILoadableRoute $route
|
||||
* @return Request|null
|
||||
*/
|
||||
public function handle(Request $request, ILoadableRoute &$route);
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Http\Middleware;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\RouterEntry;
|
||||
|
||||
abstract class Middleware
|
||||
{
|
||||
abstract function handle(Request $request);
|
||||
}
|
||||
+192
-58
@@ -1,72 +1,206 @@
|
||||
<?php
|
||||
namespace Pecee\Http;
|
||||
|
||||
class Request {
|
||||
use Pecee\Http\Input\Input;
|
||||
|
||||
protected $uri;
|
||||
protected $host;
|
||||
protected $method;
|
||||
protected $headers;
|
||||
class Request
|
||||
{
|
||||
protected $data = array();
|
||||
protected $headers;
|
||||
protected $host;
|
||||
protected $uri;
|
||||
protected $method;
|
||||
protected $input;
|
||||
|
||||
public function __construct() {
|
||||
$this->host = $_SERVER['HTTP_HOST'];
|
||||
$this->uri = rtrim($_SERVER['REQUEST_URI'], '/') . '/';
|
||||
$this->method = (isset($_POST['_method'])) ? strtolower($_POST['_method']) : strtolower($_SERVER['REQUEST_METHOD']);
|
||||
$this->headers = getallheaders();
|
||||
}
|
||||
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')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUri() {
|
||||
return $this->uri;
|
||||
}
|
||||
protected function parseHeaders()
|
||||
{
|
||||
$this->headers = array();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHost() {
|
||||
return $this->host;
|
||||
}
|
||||
foreach ($_SERVER as $name => $value) {
|
||||
$this->headers[strtolower($name)] = $value;
|
||||
$this->headers[strtolower(str_replace('_', '-', $name))] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod() {
|
||||
return $this->method;
|
||||
}
|
||||
public function isSecure()
|
||||
{
|
||||
if ($this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || $this->getHeader('server-port') === 443) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get http basic auth user
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUser() {
|
||||
return (isset($_SERVER['PHP_AUTH_USER'])) ? $_SERVER['PHP_AUTH_USER']: null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get http basic auth password
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPassword() {
|
||||
return (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW']: null;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUri()
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get headers
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders() {
|
||||
return $this->headers;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get header value by name
|
||||
* @param string $name
|
||||
* @return string|null
|
||||
*/
|
||||
public function getHeader($name) {
|
||||
return (isset($this->headers[$name])) ? $this->headers[$name] : null;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod()
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get http basic auth user
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->getHeader('php-auth-user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get http basic auth password
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->getHeader('php-auth-pw');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id address
|
||||
* @return string
|
||||
*/
|
||||
public function getIp()
|
||||
{
|
||||
if ($this->getHeader('http-cf-connecting-ip') !== null) {
|
||||
return $this->getHeader('http-cf-connecting-ip');
|
||||
}
|
||||
|
||||
if ($this->getHeader('http-x-forwarded-for') !== null && strlen($this->getHeader('http-x-forwarded-for'))) {
|
||||
return $this->getHeader('http-x-forwarded_for');
|
||||
}
|
||||
|
||||
return $this->getHeader('remote-addr');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get referer
|
||||
* @return string
|
||||
*/
|
||||
public function getReferer()
|
||||
{
|
||||
return $this->getHeader('http-referer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user agent
|
||||
* @return string
|
||||
*/
|
||||
public function getUserAgent()
|
||||
{
|
||||
return $this->getHeader('http-user-agent');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 __set($name, $value = null)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
return isset($this->data[$name]) ? $this->data[$name] : null;
|
||||
}
|
||||
|
||||
}
|
||||
+109
-28
@@ -1,37 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Http;
|
||||
|
||||
class Response {
|
||||
class Response
|
||||
{
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Set the http status code
|
||||
*
|
||||
* @param int $code
|
||||
* @return self $this
|
||||
*/
|
||||
public function httpCode($code) {
|
||||
http_response_code($code);
|
||||
return $this;
|
||||
}
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect the response
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
public function redirect($url) {
|
||||
header('location: ' . $url);
|
||||
die();
|
||||
}
|
||||
/**
|
||||
* Set the http status code
|
||||
*
|
||||
* @param int $code
|
||||
* @return static
|
||||
*/
|
||||
public function httpCode($code)
|
||||
{
|
||||
http_response_code($code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function refresh() {
|
||||
$this->redirect(url());
|
||||
}
|
||||
/**
|
||||
* Redirect the response
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $httpCode
|
||||
*/
|
||||
public function redirect($url, $httpCode = null)
|
||||
{
|
||||
if ($httpCode !== null) {
|
||||
$this->httpCode($httpCode);
|
||||
}
|
||||
|
||||
public function auth($name = '') {
|
||||
header('WWW-Authenticate: Basic realm="' . $name . '"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
}
|
||||
$this->header('location: ' . $url);
|
||||
die();
|
||||
}
|
||||
|
||||
public function refresh()
|
||||
{
|
||||
$this->redirect($this->request->getUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add http authorisation
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function auth($name = '')
|
||||
{
|
||||
$this->headers([
|
||||
'WWW-Authenticate: Basic realm="' . $name . '"',
|
||||
'HTTP/1.0 401 Unauthorized'
|
||||
]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function cache($eTag, $lastModified = 2592000)
|
||||
{
|
||||
|
||||
$this->headers([
|
||||
'Cache-Control: public',
|
||||
'Last-Modified: ' . gmdate("D, d M Y H:i:s", $lastModified) . ' GMT',
|
||||
'Etag: ' . $eTag
|
||||
]);
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $lastModified ||
|
||||
isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $eTag
|
||||
) {
|
||||
|
||||
$this->headers([
|
||||
'HTTP/1.1 304 Not Modified'
|
||||
]);
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
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) {
|
||||
header($header);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
class HttpException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
class NotFoundHttpException extends HttpException
|
||||
{
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
interface IRouteEntry {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
interface IRouterBootManager
|
||||
{
|
||||
/**
|
||||
* Called when router loads it's routes
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Request
|
||||
*/
|
||||
public function boot(Request $request);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
interface IControllerRoute extends IRoute
|
||||
{
|
||||
/**
|
||||
* Get controller class-name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getController();
|
||||
|
||||
/**
|
||||
* Set controller class-name
|
||||
*
|
||||
* @param string $controller
|
||||
* @return static
|
||||
*/
|
||||
public function setController($controller);
|
||||
|
||||
/**
|
||||
* Return active method
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod();
|
||||
|
||||
/**
|
||||
* Set active method
|
||||
*
|
||||
* @param string $method
|
||||
* @return static
|
||||
*/
|
||||
public function setMethod($method);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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 domains for domain.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDomains();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Get prefix.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPrefix();
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Loads and renders middlewares-classes
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ILoadableRoute $route
|
||||
*/
|
||||
public function loadMiddleware(Request $request, ILoadableRoute &$route);
|
||||
|
||||
public function getUrl();
|
||||
|
||||
public function setUrl($url);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
interface IRoute
|
||||
{
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Get allowed request methods
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRequestMethods();
|
||||
|
||||
/**
|
||||
* @return IRoute|null
|
||||
*/
|
||||
public function getParent();
|
||||
|
||||
/**
|
||||
* 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 parent route
|
||||
*
|
||||
* @param IRoute $parent
|
||||
* @return static $this
|
||||
*/
|
||||
public function setParent(IRoute $parent);
|
||||
|
||||
/**
|
||||
* Set callback
|
||||
*
|
||||
* @param string $callback
|
||||
* @return static
|
||||
*/
|
||||
public function setCallback($callback);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCallback();
|
||||
|
||||
public function getMethod();
|
||||
|
||||
public function getClass();
|
||||
|
||||
public function setMethod($method);
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @return static $this
|
||||
*/
|
||||
public function setNamespace($namespace);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace();
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @return static $this
|
||||
*/
|
||||
public function setDefaultNamespace($namespace);
|
||||
|
||||
public function getDefaultNamespace();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Get parameter names.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getWhere();
|
||||
|
||||
/**
|
||||
* Set parameter names.
|
||||
*
|
||||
* @param array $options
|
||||
* @return static
|
||||
*/
|
||||
public function setWhere(array $options);
|
||||
|
||||
/**
|
||||
* Get parameters
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getParameters();
|
||||
|
||||
/**
|
||||
* Get parameters
|
||||
*
|
||||
* @param array $parameters
|
||||
* @return static $this
|
||||
*/
|
||||
public function setParameters(array $parameters);
|
||||
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static $this
|
||||
*/
|
||||
public function setSettings(array $settings, $merge = false);
|
||||
|
||||
/**
|
||||
* Export route settings to array so they can be merged with another route.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\HttpException;
|
||||
|
||||
abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
{
|
||||
const PARAMETERS_REGEX_MATCH = '%s([\w\-\_]*?)\%s{0,1}%s';
|
||||
|
||||
protected $url;
|
||||
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) {
|
||||
|
||||
$middleware = $this->loadClass($middleware);
|
||||
if (!($middleware instanceof IMiddleware)) {
|
||||
throw new HttpException($middleware . ' must be instance of Middleware');
|
||||
}
|
||||
|
||||
$middleware->handle($request, $route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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]);
|
||||
|
||||
if (preg_match_all('/' . $regex . '/is', $this->url, $matches)) {
|
||||
foreach ($matches[1] as $key) {
|
||||
$this->parameters[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = '';
|
||||
|
||||
$parameters = (array)$parameters;
|
||||
|
||||
if ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
|
||||
$url .= '//' . $this->getGroup()->getDomains()[0];
|
||||
}
|
||||
|
||||
$url .= $this->getUrl();
|
||||
|
||||
$params = array_merge($this->getParameters(), $parameters);
|
||||
|
||||
/* 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 */
|
||||
foreach ($params as $param => $value) {
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
$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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,517 @@
|
||||
<?php
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
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 = [];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Remove method/type */
|
||||
if (stripos($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;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::hasName($name);
|
||||
}
|
||||
|
||||
public function findUrl($method = null, $parameters = null, $name = null)
|
||||
{
|
||||
|
||||
if (stripos($name, '.') !== false) {
|
||||
$found = array_search(substr($name, strrpos($name, '.') + 1), $this->names);
|
||||
if ($found !== false) {
|
||||
$method = $found;
|
||||
}
|
||||
}
|
||||
|
||||
$url = '';
|
||||
|
||||
$parameters = (array)$parameters;
|
||||
|
||||
/* 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 ($this->getGroup() !== null && count($this->getGroup()->getDomains()) > 0) {
|
||||
$url .= '//' . $this->getGroup()->getDomains()[0];
|
||||
}
|
||||
|
||||
$url .= '/' . trim($this->getUrl(), '/') . '/' . strtolower($method) . join('/', $parameters);
|
||||
|
||||
return '/' . trim($url, '/') . '/';
|
||||
}
|
||||
|
||||
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 = $request->getMethod() . ucfirst($controller[1]);
|
||||
|
||||
if (!method_exists($class, $method)) {
|
||||
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
|
||||
}
|
||||
|
||||
call_user_func_array([$class, $method], $this->getParameters());
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request)
|
||||
{
|
||||
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
if (strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
|
||||
|
||||
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
|
||||
|
||||
$path = explode('/', $strippedUrl);
|
||||
|
||||
if (count($path) > 0) {
|
||||
|
||||
$method = (!isset($path[0]) || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
|
||||
$this->method = $method;
|
||||
|
||||
array_shift($path);
|
||||
$this->parameters = $path;
|
||||
|
||||
// Set callback
|
||||
$this->setCallback($this->controller . '@' . $this->method);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get controller class-name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getController()
|
||||
{
|
||||
return $this->controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get controller class-name.
|
||||
*
|
||||
* @param string $controller
|
||||
* @return static
|
||||
*/
|
||||
public function setController($controller)
|
||||
{
|
||||
$this->controller = $controller;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouteGroup extends Route implements IGroupRoute
|
||||
{
|
||||
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) {
|
||||
|
||||
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
|
||||
|
||||
if ($parameters !== null) {
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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 $this->matchDomain($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set exception-handlers for group
|
||||
*
|
||||
* @param array $handlers
|
||||
* @return static $this
|
||||
*/
|
||||
public function setExceptionHandlers(array $handlers)
|
||||
{
|
||||
$this->exceptionHandlers = $handlers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get exception-handlers for group
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExceptionHandlers()
|
||||
{
|
||||
return $this->exceptionHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get allowed domains for domain.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDomains()
|
||||
{
|
||||
return $this->domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set allowed domains for group.
|
||||
*
|
||||
* @param array $domains
|
||||
* @return $this
|
||||
*/
|
||||
public function setDomains(array $domains)
|
||||
{
|
||||
$this->domains = $domains;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return static
|
||||
*/
|
||||
public function setPrefix($prefix)
|
||||
{
|
||||
$this->prefix = '/' . trim($prefix, '/');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set prefix that child-routes will inherit.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPrefix()
|
||||
{
|
||||
return $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['prefix'])) {
|
||||
$this->setPrefix($values['prefix'] . $this->prefix);
|
||||
}
|
||||
|
||||
if (isset($values['exceptionHandler'])) {
|
||||
$this->setExceptionHandlers((array)$values['exceptionHandler']);
|
||||
}
|
||||
|
||||
if (isset($values['domain'])) {
|
||||
$this->setDomains((array)$values['domain']);
|
||||
}
|
||||
|
||||
if (isset($values['as'])) {
|
||||
if ($this->name !== null && $merge !== false) {
|
||||
$this->name = $values['as'] . '.' . $this->name;
|
||||
} else {
|
||||
$this->name = $values['as'];
|
||||
}
|
||||
}
|
||||
|
||||
parent::setSettings($values, $merge);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export route settings to array so they can be merged with another route.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$values = [];
|
||||
|
||||
if ($this->prefix !== null) {
|
||||
$values['prefix'] = $this->getPrefix();
|
||||
}
|
||||
|
||||
if ($this->name !== null) {
|
||||
$values['as'] = $this->name;
|
||||
}
|
||||
|
||||
return array_merge($values, parent::toArray());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
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;
|
||||
|
||||
public function __construct($url, $controller)
|
||||
{
|
||||
$this->setUrl($url);
|
||||
$this->controller = $controller;
|
||||
$this->setName(trim(str_replace('/', '.', $url), '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if route has given name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasName($name)
|
||||
{
|
||||
if ($this->name === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strtolower($this->name) === strtolower($name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Remove method/type */
|
||||
if (stripos($name, '.') !== false) {
|
||||
$name = substr($name, 0, strrpos($name, '.'));
|
||||
}
|
||||
|
||||
return (strtolower($this->name) === strtolower($name));
|
||||
}
|
||||
|
||||
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], '/') . '/';
|
||||
}
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
if (!method_exists($class, $method)) {
|
||||
throw new NotFoundHttpException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
|
||||
}
|
||||
|
||||
call_user_func_array([$class, $method], $this->getParameters());
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function call($method, $parameters)
|
||||
{
|
||||
$this->setCallback($this->controller . '@' . $method);
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request)
|
||||
{
|
||||
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
$route = rtrim($this->url, '/') . '/{id?}/{action?}';
|
||||
|
||||
$parameters = $this->parseParameters($route, $url);
|
||||
|
||||
if ($parameters !== null) {
|
||||
|
||||
$parameters = array_merge($this->parameters, (array)$parameters);
|
||||
|
||||
$action = isset($parameters['action']) ? $parameters['action'] : null;
|
||||
unset($parameters['action']);
|
||||
|
||||
$method = request()->getMethod();
|
||||
|
||||
// Delete
|
||||
if (isset($parameters['id']) && $method === static::REQUEST_TYPE_DELETE) {
|
||||
return $this->call('destroy', $parameters);
|
||||
}
|
||||
|
||||
// Update
|
||||
if (isset($parameters['id']) && in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT])) {
|
||||
return $this->call('update', $parameters);
|
||||
}
|
||||
|
||||
// Edit
|
||||
if (isset($parameters['id']) && strtolower($action) === 'edit' && $method === static::REQUEST_TYPE_GET) {
|
||||
return $this->call('edit', $parameters);
|
||||
}
|
||||
|
||||
// Create
|
||||
if (strtolower($action) === 'create' && $method === static::REQUEST_TYPE_GET) {
|
||||
return $this->call('create', $parameters);
|
||||
}
|
||||
|
||||
// Save
|
||||
if ($method === static::REQUEST_TYPE_POST) {
|
||||
return $this->call('store', $parameters);
|
||||
}
|
||||
|
||||
// Show
|
||||
if (isset($parameters['id']) && $method === static::REQUEST_TYPE_GET) {
|
||||
return $this->call('show', $parameters);
|
||||
}
|
||||
|
||||
// Index
|
||||
return $this->call('index', $parameters);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getController()
|
||||
{
|
||||
return $this->controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
* @return static
|
||||
*/
|
||||
public function setController($controller)
|
||||
{
|
||||
$this->controller = $controller;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
$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',
|
||||
];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouteUrl extends LoadableRoute
|
||||
{
|
||||
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, '/') . '/';
|
||||
|
||||
// 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];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make regular expression based on route
|
||||
$route = rtrim($this->url, '/') . '/';
|
||||
|
||||
$parameters = $this->parseParameters($route, $url);
|
||||
|
||||
if ($parameters !== null) {
|
||||
$this->parameters = array_merge($this->parameters, $parameters);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Handlers\IExceptionHandler;
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\HttpException;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
|
||||
use Pecee\SimpleRouter\Route\IControllerRoute;
|
||||
use Pecee\SimpleRouter\Route\IGroupRoute;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
use Pecee\SimpleRouter\Route\IRoute;
|
||||
|
||||
class Router
|
||||
{
|
||||
|
||||
/**
|
||||
* The instance of this class
|
||||
* @var static
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* Current request
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Defines if a route is currently being processed.
|
||||
* @var bool
|
||||
*/
|
||||
protected $processingRoute;
|
||||
|
||||
/**
|
||||
* All added routes
|
||||
* @var array
|
||||
*/
|
||||
protected $routes;
|
||||
|
||||
/**
|
||||
* List of processed routes
|
||||
* @var array
|
||||
*/
|
||||
protected $processedRoutes;
|
||||
|
||||
/**
|
||||
* Stack of routes used to keep track of sub-routes added
|
||||
* when a route is being processed.
|
||||
* @var array
|
||||
*/
|
||||
protected $routeStack;
|
||||
|
||||
/**
|
||||
* List of added bootmanagers
|
||||
* @var array
|
||||
*/
|
||||
protected $bootManagers;
|
||||
|
||||
/**
|
||||
* Csrf verifier class
|
||||
* @var BaseCsrfVerifier
|
||||
*/
|
||||
protected $csrfVerifier;
|
||||
|
||||
/**
|
||||
* Get exception handlers
|
||||
* @var array
|
||||
*/
|
||||
protected $exceptionHandlers;
|
||||
|
||||
/**
|
||||
* The current loaded route
|
||||
* @var ILoadableRoute|null
|
||||
*/
|
||||
protected $loadedRoute;
|
||||
|
||||
/**
|
||||
* List over route changes (to avoid endless-looping)
|
||||
* @var array
|
||||
*/
|
||||
protected $routeRewrites = [];
|
||||
|
||||
/**
|
||||
* If the route has been rewritten/changed this property will contain the original url.
|
||||
* @var string
|
||||
*/
|
||||
protected $originalUrl;
|
||||
|
||||
/**
|
||||
* Get current router instance
|
||||
* @return static
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (static::$instance === null) {
|
||||
static::$instance = new static();
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->processingRoute = false;
|
||||
$this->request = new Request();
|
||||
$this->routes = [];
|
||||
$this->bootManagers = [];
|
||||
$this->routeStack = [];
|
||||
$this->processedRoutes = [];
|
||||
$this->exceptionHandlers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add route
|
||||
* @param IRoute $route
|
||||
* @return IRoute
|
||||
*/
|
||||
public function addRoute(IRoute $route)
|
||||
{
|
||||
/*
|
||||
* If a route is currently being processed, that means that the
|
||||
* route being added are rendered from the parent routes callback,
|
||||
* so we add them to the stack instead.
|
||||
*/
|
||||
if ($this->processingRoute === true) {
|
||||
$this->routeStack[] = $route;
|
||||
} else {
|
||||
$this->routes[] = $route;
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
protected function processRoutes(array $routes, IGroupRoute $group = null, IRoute $parent = null)
|
||||
{
|
||||
// Loop through each route-request
|
||||
/* @var $route IRoute */
|
||||
foreach ($routes as $route) {
|
||||
|
||||
if ($route instanceof IGroupRoute) {
|
||||
|
||||
$group = $route;
|
||||
|
||||
if ($route->getCallback() !== null && is_callable($route->getCallback())) {
|
||||
|
||||
$this->processingRoute = true;
|
||||
$route->renderRoute($this->request);
|
||||
$this->processingRoute = false;
|
||||
|
||||
if ($route->matchRoute($this->request)) {
|
||||
|
||||
/* Add exceptionhandlers */
|
||||
if (count($route->getExceptionHandlers()) > 0) {
|
||||
$this->exceptionHandlers = array_merge($route->getExceptionHandlers(), $this->exceptionHandlers);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($group !== null) {
|
||||
|
||||
/* Add the parent group */
|
||||
$route->setGroup($group);
|
||||
|
||||
}
|
||||
|
||||
if ($parent !== null) {
|
||||
|
||||
/* Add the parent route */
|
||||
$route->setParent($parent);
|
||||
|
||||
/* Add/merge parent settings with child */
|
||||
$route->setSettings($parent->toArray(), true);
|
||||
|
||||
}
|
||||
|
||||
if ($route instanceof ILoadableRoute) {
|
||||
|
||||
/* Add the route to the map, so we can find the active one when all routes has been loaded */
|
||||
$this->processedRoutes[] = $route;
|
||||
}
|
||||
|
||||
if (count($this->routeStack) > 0) {
|
||||
|
||||
/* Pop and grap the routes added when executing group callback earlier */
|
||||
$stack = $this->routeStack;
|
||||
$this->routeStack = [];
|
||||
|
||||
/* Route any routes added to the stack */
|
||||
$this->processRoutes($stack, $route, $group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function routeRequest($rewrite = false)
|
||||
{
|
||||
$this->loadedRoute = null;
|
||||
$routeNotAllowed = false;
|
||||
|
||||
try {
|
||||
|
||||
/* Initialize boot-managers */
|
||||
if (count($this->bootManagers) > 0) {
|
||||
/* @var $manager IRouterBootManager */
|
||||
foreach ($this->bootManagers as $manager) {
|
||||
$this->request = $manager->boot($this->request);
|
||||
|
||||
if (!($this->request instanceof Request)) {
|
||||
throw new HttpException('Bootmanager "' . get_class($manager) . '" must return instance of ' . Request::class, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($rewrite === false) {
|
||||
|
||||
/* Loop through each route-request */
|
||||
$this->processRoutes($this->routes);
|
||||
|
||||
if ($this->csrfVerifier !== null) {
|
||||
|
||||
// Verify csrf token for request
|
||||
$this->csrfVerifier->handle($this->request);
|
||||
}
|
||||
|
||||
$this->originalUrl = $this->request->getUri();
|
||||
}
|
||||
|
||||
/* @var $route IRoute */
|
||||
foreach ($this->processedRoutes as $route) {
|
||||
|
||||
/* If the route matches */
|
||||
if ($route->matchRoute($this->request)) {
|
||||
|
||||
/* Check if request method matches */
|
||||
if (count($route->getRequestMethods()) > 0 && !in_array($this->request->getMethod(), $route->getRequestMethods())) {
|
||||
$routeNotAllowed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->loadedRoute = $route;
|
||||
$this->loadedRoute->loadMiddleware($this->request, $this->loadedRoute);
|
||||
|
||||
/* If the request has changed, we reinitialize the router */
|
||||
if ($this->request->getUri() !== $this->originalUrl && !in_array($this->request->getUri(), $this->routeRewrites)) {
|
||||
$this->routeRewrites[] = $this->request->getUri();
|
||||
$this->routeRequest(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Render route */
|
||||
$routeNotAllowed = false;
|
||||
$this->request->setUri($this->originalUrl);
|
||||
$this->loadedRoute->renderRoute($this->request);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->handleException($e);
|
||||
}
|
||||
|
||||
if ($routeNotAllowed === true) {
|
||||
$this->handleException(new HttpException('Route or method not allowed', 403));
|
||||
}
|
||||
|
||||
if ($this->loadedRoute === null) {
|
||||
$this->handleException(new NotFoundHttpException('Route not found: ' . $this->request->getUri(), 404));
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleException(\Exception $e)
|
||||
{
|
||||
/* @var $handler IExceptionHandler */
|
||||
foreach ($this->exceptionHandlers as $handler) {
|
||||
|
||||
$handler = new $handler();
|
||||
|
||||
if (!($handler instanceof IExceptionHandler)) {
|
||||
throw new HttpException('Exception handler must implement the IExceptionHandler interface.', 500);
|
||||
}
|
||||
|
||||
$request = $handler->handleError($this->request, $this->loadedRoute, $e);
|
||||
|
||||
/* If the request has changed */
|
||||
if ($request !== null && $this->request->getUri() !== $this->originalUrl && !in_array($request->getUri(), $this->routeRewrites)) {
|
||||
$this->request = $request;
|
||||
$this->routeRewrites[] = $request->getUri();
|
||||
$this->routeRequest(true);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
public function arrayToParams(array $getParams = [], $includeEmpty = true)
|
||||
{
|
||||
if (count($getParams) > 0) {
|
||||
|
||||
if ($includeEmpty === false) {
|
||||
$getParams = array_filter($getParams, function ($item) {
|
||||
return (!empty($item));
|
||||
});
|
||||
}
|
||||
|
||||
return '?' . http_build_query($getParams);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Find route by alias, class, callback or method.
|
||||
*
|
||||
* @param string $name
|
||||
* @return ILoadableRoute|null
|
||||
*/
|
||||
public function findRoute($name)
|
||||
{
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $route) {
|
||||
|
||||
/* Check if the name matches with a name on the route. Should match either router alias or controller alias. */
|
||||
if ($route->hasName($name)) {
|
||||
return $route;
|
||||
}
|
||||
|
||||
/* Direct match to controller */
|
||||
if ($route instanceof IControllerRoute && strtolower($route->getController()) === strtolower($name)) {
|
||||
return $route;
|
||||
}
|
||||
|
||||
/* Using @ is most definitely a controller@method or alias@method */
|
||||
if (strpos($name, '@') !== false) {
|
||||
list($controller, $method) = array_map('strtolower', explode('@', $name));
|
||||
|
||||
if ($controller === strtolower($route->getClass()) && $method === strtolower($route->getMethod())) {
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if callback matches (if it's not a function) */
|
||||
if (strpos($name, '@') !== false && strpos($route->getCallback(), '@') !== false && !is_callable($route->getCallback())) {
|
||||
|
||||
/* Check if the entire callback is matching */
|
||||
if (strtolower($route->getCallback()) === strtolower($name) || strpos($route->getCallback(), $name) === 0) {
|
||||
return $route;
|
||||
}
|
||||
|
||||
/* Check if the class part of the callback matches (class@method) */
|
||||
if (strtolower($name) === strtolower($route->getClass())) {
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 function getUrl($name = null, $parameters = null, $getParams = [])
|
||||
{
|
||||
if ($getParams !== null && is_array($getParams) === false) {
|
||||
throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null');
|
||||
}
|
||||
|
||||
if ($getParams === null) {
|
||||
$getParams = $_GET;
|
||||
}
|
||||
|
||||
/* Return current route if no options has been specified */
|
||||
if ($name === null && $parameters === null) {
|
||||
return '/' . trim(parse_url($this->request->getUri(), PHP_URL_PATH), '/') . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
/* If nothing is defined and a route is loaded we use that */
|
||||
if ($name === null && $this->loadedRoute !== null) {
|
||||
return $this->loadedRoute->findUrl($this->loadedRoute->getMethod(), $parameters, $name) . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
/* We try to find a match on the given name */
|
||||
$route = $this->findRoute($name);
|
||||
|
||||
if ($route !== null) {
|
||||
return $route->findUrl($route->getMethod(), $parameters, $name) . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
/* Using @ is most definitely a controller@method or alias@method */
|
||||
if (stripos($name, '@') !== false) {
|
||||
list($controller, $method) = explode('@', $name);
|
||||
|
||||
/* Loop through all the routes to see if we can find a match */
|
||||
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $route) {
|
||||
|
||||
/* Check if the route contains the name/alias */
|
||||
if ($route->hasName($controller)) {
|
||||
return $route->findUrl($method, $parameters, $name) . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
/* Check if the route controller is equal to the name */
|
||||
if ($route instanceof IControllerRoute && strtolower($route->getController()) === strtolower($controller)) {
|
||||
return $route->findUrl($method, $parameters, $name) . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* No result so we assume that someone is using a hardcoded url and join everything together. */
|
||||
return '/' . trim(join('/', array_merge((array)$name, (array)$parameters)), '/') . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bootmanagers
|
||||
* @return array
|
||||
*/
|
||||
public function getBootManagers()
|
||||
{
|
||||
return $this->bootManagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bootmanagers
|
||||
* @param array $bootManagers
|
||||
*/
|
||||
public function setBootManagers(array $bootManagers)
|
||||
{
|
||||
$this->bootManagers = $bootManagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bootmanager
|
||||
* @param IRouterBootManager $bootManager
|
||||
*/
|
||||
public function addBootManager(IRouterBootManager $bootManager)
|
||||
{
|
||||
$this->bootManagers[] = $bootManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getRoutes()
|
||||
{
|
||||
return $this->routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current request
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get csrf verifier class
|
||||
* @return BaseCsrfVerifier
|
||||
*/
|
||||
public function getCsrfVerifier()
|
||||
{
|
||||
return $this->csrfVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set csrf verifier class
|
||||
*
|
||||
* @param BaseCsrfVerifier $csrfVerifier
|
||||
* @return static
|
||||
*/
|
||||
public function setCsrfVerifier(BaseCsrfVerifier $csrfVerifier)
|
||||
{
|
||||
$this->csrfVerifier = $csrfVerifier;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get loaded route
|
||||
* @return ILoadableRoute|null
|
||||
*/
|
||||
public function getLoadedRoute()
|
||||
{
|
||||
return $this->loadedRoute;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\ArrayUtil;
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\Url;
|
||||
|
||||
class RouterBase {
|
||||
|
||||
protected static $instance;
|
||||
|
||||
protected $request;
|
||||
protected $currentRoute;
|
||||
protected $routes;
|
||||
protected $processedRoutes;
|
||||
protected $controllerUrlMap;
|
||||
protected $backstack;
|
||||
protected $loadedRoute;
|
||||
protected $defaultNamespace;
|
||||
protected $baseCsrfVerifier;
|
||||
|
||||
// TODO: make interface for controller routers, so they can be easily detected
|
||||
// TODO: clean up - cut some of the methods down to smaller pieces
|
||||
|
||||
public function __construct() {
|
||||
$this->routes = array();
|
||||
$this->backstack = array();
|
||||
$this->controllerUrlMap = array();
|
||||
$this->request = new Request();
|
||||
$this->baseCsrfVerifier = new BaseCsrfVerifier();
|
||||
}
|
||||
|
||||
public function addRoute(RouterEntry $route) {
|
||||
if($this->currentRoute !== null) {
|
||||
$this->backstack[] = $route;
|
||||
} else {
|
||||
$this->routes[] = $route;
|
||||
}
|
||||
}
|
||||
|
||||
protected function processRoutes(array $routes, array $settings = array(), array $prefixes = array(), $backstack = false) {
|
||||
// Loop through each route-request
|
||||
|
||||
/* @var $route RouterEntry */
|
||||
foreach($routes as $route) {
|
||||
|
||||
if($this->defaultNamespace && !$route->getNamespace()) {
|
||||
$namespace = null;
|
||||
if ($route->getNamespace()) {
|
||||
$namespace = $this->defaultNamespace . '\\' . $route->getNamespace();
|
||||
} else {
|
||||
$namespace = $this->defaultNamespace;
|
||||
}
|
||||
|
||||
$route->setNamespace($namespace);
|
||||
}
|
||||
|
||||
$newPrefixes = $prefixes;
|
||||
$mergedSettings = array_merge($settings, $route->getMergeableSettings());
|
||||
if($route->getPrefix()) {
|
||||
array_push($newPrefixes, rtrim($route->getPrefix(), '/'));
|
||||
}
|
||||
$route->addSettings($mergedSettings);
|
||||
|
||||
if(!($route instanceof RouterGroup)) {
|
||||
if(is_array($newPrefixes) && count($newPrefixes) && $backstack) {
|
||||
$route->setUrl( join('/', $newPrefixes) . $route->getUrl() );
|
||||
}
|
||||
|
||||
$this->controllerUrlMap[] = $route;
|
||||
}
|
||||
|
||||
$this->currentRoute = $route;
|
||||
if($route instanceof RouterGroup && is_callable($route->getCallback())) {
|
||||
$route->renderRoute($this->request);
|
||||
}
|
||||
$this->currentRoute = null;
|
||||
|
||||
if(count($this->backstack)) {
|
||||
$backstack = $this->backstack;
|
||||
$this->backstack = array();
|
||||
|
||||
// Route any routes added to the backstack
|
||||
$this->processRoutes($backstack, $mergedSettings, $newPrefixes, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function routeRequest() {
|
||||
|
||||
// Verify csrf token for request
|
||||
if($this->baseCsrfVerifier !== null) {
|
||||
/* @var $csrfVerifier BaseCsrfVerifier */
|
||||
$csrfVerifier = $this->baseCsrfVerifier;
|
||||
$csrfVerifier = new $csrfVerifier();
|
||||
$csrfVerifier->handle($this->request);
|
||||
}
|
||||
|
||||
// Loop through each route-request
|
||||
$this->processRoutes($this->routes);
|
||||
|
||||
// Make sure the urls is in the right order when comparing
|
||||
usort($this->controllerUrlMap, function($a, $b) {
|
||||
return strcmp($b->getUrl(), $a->getUrl());
|
||||
});
|
||||
|
||||
$routeNotAllowed = false;
|
||||
|
||||
/* @var $route RouterEntry */
|
||||
foreach($this->controllerUrlMap as $route) {
|
||||
$routeMatch = $route->matchRoute($this->request);
|
||||
|
||||
if($routeMatch && !($routeMatch instanceof RouterGroup)) {
|
||||
|
||||
if(count($route->getRequestMethods()) && !in_array($this->request->getMethod(), $route->getRequestMethods())) {
|
||||
$routeNotAllowed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$routeNotAllowed = false;
|
||||
|
||||
$this->loadedRoute = $routeMatch;
|
||||
$routeMatch->renderRoute($this->request);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($routeNotAllowed) {
|
||||
throw new RouterException('Route or method not allowed', 403);
|
||||
}
|
||||
|
||||
if(!$this->loadedRoute) {
|
||||
throw new RouterException(sprintf('Route not found: %s', $this->request->getUri()), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultNamespace(){
|
||||
return $this->defaultNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $defaultNamespace
|
||||
*/
|
||||
public function setDefaultNamespace($defaultNamespace) {
|
||||
$this->defaultNamespace = $defaultNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouterEntry
|
||||
*/
|
||||
public function getLoadedRoute() {
|
||||
if(!($this->loadedRoute instanceof RouterGroup)) {
|
||||
return $this->loadedRoute;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getBackstack() {
|
||||
return $this->backstack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouterEntry
|
||||
*/
|
||||
public function getCurrentRoute(){
|
||||
return $this->currentRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getRoutes(){
|
||||
return $this->routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current request
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
public function getRequest() {
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base csrf verifier class
|
||||
* @return BaseCsrfVerifier
|
||||
*/
|
||||
public function getBaseCsrfVerifier() {
|
||||
return $this->baseCsrfVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set base csrf verifier class
|
||||
*
|
||||
* @param BaseCsrfVerifier $baseCsrfVerifier
|
||||
* @return self
|
||||
*/
|
||||
public function setBaseCsrfVerifier(BaseCsrfVerifier $baseCsrfVerifier) {
|
||||
$this->baseCsrfVerifier = $baseCsrfVerifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function processUrl($route, $method = null, $parameters = null, $getParams = null) {
|
||||
|
||||
$url = '/' . trim($route->getUrl(), '/');
|
||||
|
||||
if(($route instanceof RouterController || $route instanceof RouterResource) && $method !== null) {
|
||||
$url .= $method;
|
||||
}
|
||||
|
||||
if($route instanceof RouterController || $route instanceof RouterResource) {
|
||||
if(count($parameters)) {
|
||||
$url .= join('/', $parameters);
|
||||
}
|
||||
} else {
|
||||
/* @var $route RouterEntry */
|
||||
$params = $route->getParameters();
|
||||
if(count($params)) {
|
||||
$i = 0;
|
||||
foreach($params as $param => $value) {
|
||||
$value = (isset($parameters[$param])) ? $parameters[$param] : $value;
|
||||
$url = str_ireplace('{' . $param. '}', $value, $url);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
if($getParams !== null && count($getParams)) {
|
||||
$url .= '?'.Url::arrayToParams($getParams);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function getRoute($controller = null, $parameters = null, $getParams = null) {
|
||||
|
||||
if($parameters !== null && !is_array($parameters)) {
|
||||
throw new \InvalidArgumentException('Invalid type for parameter. Must be array or null');
|
||||
}
|
||||
|
||||
if($getParams !== null && !is_array($getParams)) {
|
||||
throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null');
|
||||
}
|
||||
|
||||
if($controller === null && $parameters === null) {
|
||||
return $this->processUrl($this->loadedRoute, null, $getParams);
|
||||
}
|
||||
|
||||
$c = '';
|
||||
$method = null;
|
||||
|
||||
/* @var $route RouterRoute */
|
||||
foreach($this->controllerUrlMap as $route) {
|
||||
|
||||
// Check an alias exist, if the matches - use it
|
||||
if($route instanceof RouterRoute && strtolower($route->getAlias()) === strtolower($controller)) {
|
||||
return $this->processUrl($route, $route->getMethod(), $parameters, $getParams);
|
||||
}
|
||||
|
||||
if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) {
|
||||
$c = $route->getCallback();
|
||||
} else if($route instanceof RouterController || $route instanceof RouterResource) {
|
||||
$c = $route->getController();
|
||||
}
|
||||
|
||||
if($c === $controller || strpos($c, $controller) === 0) {
|
||||
return $this->processUrl($route, $route->getMethod(), $parameters, $getParams);
|
||||
}
|
||||
}
|
||||
|
||||
$c = '';
|
||||
|
||||
// No match has yet been found, let's try to guess what url that should be returned
|
||||
foreach($this->controllerUrlMap as $route) {
|
||||
if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) {
|
||||
$c = $route->getClass();
|
||||
} else if($route instanceof RouterController || $route instanceof RouterResource) {
|
||||
$c = $route->getController();
|
||||
}
|
||||
|
||||
if(stripos($controller, '@') !== false) {
|
||||
$tmp = explode('@', $controller);
|
||||
$controller = $tmp[0];
|
||||
$method = $tmp[1];
|
||||
}
|
||||
|
||||
if($controller === $c) {
|
||||
return $this->processUrl($route, $method, $parameters, $getParams);
|
||||
}
|
||||
}
|
||||
|
||||
$controller = ($controller === null) ? '/' : $controller;
|
||||
$url = array($controller);
|
||||
|
||||
if(is_array($parameters)) {
|
||||
ArrayUtil::append($url, $parameters);
|
||||
}
|
||||
|
||||
return '/' . join('/', $url);
|
||||
}
|
||||
|
||||
public static function getInstance() {
|
||||
if(self::$instance === null) {
|
||||
self::$instance = new static();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterController extends RouterEntry {
|
||||
|
||||
const DEFAULT_METHOD = 'index';
|
||||
|
||||
protected $url;
|
||||
protected $controller;
|
||||
protected $method;
|
||||
|
||||
public function __construct($url, $controller) {
|
||||
parent::__construct();
|
||||
$this->url = $url;
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
$url = parse_url($request->getUri());
|
||||
$url = rtrim($url['path'], '/') . '/';
|
||||
|
||||
if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
|
||||
|
||||
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
|
||||
|
||||
$path = explode('/', $strippedUrl);
|
||||
|
||||
if(count($path)) {
|
||||
|
||||
$method = (!isset($path[0]) || trim($path[0]) === '') ? self::DEFAULT_METHOD : $path[0];
|
||||
$this->method = $method;
|
||||
|
||||
array_shift($path);
|
||||
$this->parameters = $path;
|
||||
|
||||
// Set callback
|
||||
$this->setCallback($this->controller . '@' . $this->method);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl() {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*/
|
||||
public function setUrl($url) {
|
||||
$url = rtrim($url, '/') . '/';
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getController() {
|
||||
return $this->controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
*/
|
||||
public function setController($controller) {
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod() {
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
*/
|
||||
public function setMethod($method) {
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Middleware\Middleware;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
abstract class RouterEntry {
|
||||
|
||||
const REQUEST_TYPE_POST = 'post';
|
||||
const REQUEST_TYPE_GET = 'get';
|
||||
const REQUEST_TYPE_PUT = 'put';
|
||||
const REQUEST_TYPE_DELETE = 'delete';
|
||||
|
||||
public static $allowedRequestTypes = array(
|
||||
self::REQUEST_TYPE_DELETE,
|
||||
self::REQUEST_TYPE_GET,
|
||||
self::REQUEST_TYPE_POST,
|
||||
self::REQUEST_TYPE_PUT
|
||||
);
|
||||
|
||||
protected $settings;
|
||||
protected $callback;
|
||||
protected $parameters;
|
||||
protected $parametersRegex;
|
||||
protected $regexMatch;
|
||||
|
||||
public function __construct() {
|
||||
$this->settings = array();
|
||||
$this->settings['requestMethods'] = array();
|
||||
$this->parameters = array();
|
||||
$this->parametersRegex = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns callback name/identifier for the current route based on the callback.
|
||||
* Useful if you need to get a unique identifier for the loaded route, for instance
|
||||
* when using translations etc.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier() {
|
||||
if(strpos($this->callback, '@') !== false) {
|
||||
return $this->callback;
|
||||
}
|
||||
return 'function_' . md5($this->callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $callback
|
||||
* @return self;
|
||||
*/
|
||||
public function setCallback($callback) {
|
||||
$this->callback = $callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return self
|
||||
*/
|
||||
public function setPrefix($prefix) {
|
||||
$this->prefix = '/' . trim($prefix, '/') . '/';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $middleware
|
||||
* @return self
|
||||
*/
|
||||
public function setMiddleware($middleware) {
|
||||
$this->middleware = $middleware;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $namespace
|
||||
* @return self
|
||||
*/
|
||||
public function setNamespace($namespace) {
|
||||
$this->namespace = $namespace;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPrefix() {
|
||||
return $this->prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMiddleware() {
|
||||
return $this->middleware;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNamespace() {
|
||||
return $this->namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSettings() {
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParameters(){
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $parameters
|
||||
* @return self
|
||||
*/
|
||||
public function setParameters($parameters) {
|
||||
$this->parameters = $parameters;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add regular expression parameter match
|
||||
*
|
||||
* @param array $options
|
||||
* @return self
|
||||
*/
|
||||
public function where(array $options) {
|
||||
$this->parametersRegex = array_merge($this->parametersRegex, $options);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add regular expression match for url
|
||||
*
|
||||
* @param string $regex
|
||||
* @return self
|
||||
*/
|
||||
public function match($regex) {
|
||||
$this->regexMatch = $regex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get settings that are allowed to be inherited by child routes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMergeableSettings() {
|
||||
$settings = $this->settings;
|
||||
|
||||
if(isset($settings['middleware'])) {
|
||||
unset($settings['middleware']);
|
||||
}
|
||||
|
||||
if(isset($settings['prefix'])) {
|
||||
unset($settings['prefix']);
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @return self
|
||||
*/
|
||||
public function addSettings(array $settings = null) {
|
||||
if(is_array($settings)) {
|
||||
$this->settings = array_merge($this->settings, $settings);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @return self
|
||||
*/
|
||||
public function setSettings($settings) {
|
||||
$this->settings = $settings;
|
||||
|
||||
if($settings['prefix']) {
|
||||
$this->setPrefix($settings['prefix']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamicially access settings value
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function __get($name) {
|
||||
return (isset($this->settings[$name]) ? $this->settings[$name] : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamicially set settings value
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed|null $value
|
||||
*/
|
||||
public function __set($name, $value = null) {
|
||||
$this->settings[$name] = $value;
|
||||
}
|
||||
|
||||
protected function loadClass($name) {
|
||||
if(!class_exists($name)) {
|
||||
throw new RouterException(sprintf('Class %s does not exist', $name));
|
||||
}
|
||||
|
||||
return new $name();
|
||||
}
|
||||
|
||||
protected function loadMiddleware(Request $request) {
|
||||
if($this->getMiddleware()) {
|
||||
$middleware = $this->loadClass($this->getMiddleware());
|
||||
if (!($middleware instanceof Middleware)) {
|
||||
throw new RouterException($this->getMiddleware() . ' must be instance of Middleware');
|
||||
}
|
||||
|
||||
/* @var $class Middleware */
|
||||
$middleware->handle($request);
|
||||
}
|
||||
}
|
||||
|
||||
public function renderRoute(Request $request) {
|
||||
// Load middleware
|
||||
$this->loadMiddleware($request);
|
||||
|
||||
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
|
||||
|
||||
// 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 RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
|
||||
}
|
||||
|
||||
call_user_func_array(array($class, $method), $this->getParameters());
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set allowed request methods
|
||||
*
|
||||
* @param array $methods
|
||||
* @return self $this
|
||||
*/
|
||||
public function setRequestMethods(array $methods) {
|
||||
$this->settings['requestMethods'] = $methods;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get allowed requeset methods
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRequestMethods() {
|
||||
if(!isset($this->settings['requestMethods']) || isset($this->settings['requestMethods']) && !is_array($this->settings['requestMethods'])) {
|
||||
$value = isset($this->settings['requestMethods']) ? $this->settings['requestMethods'] : null;
|
||||
return array($value);
|
||||
}
|
||||
return $this->settings['requestMethods'];
|
||||
}
|
||||
|
||||
abstract function matchRoute(Request $request);
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
class RouterException extends \Exception { }
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterGroup extends RouterEntry {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
// Check if request method is allowed
|
||||
|
||||
if(strtolower($request->getUri()) == strtolower($this->prefix) || stripos($request->getUri(), $this->prefix) === 0) {
|
||||
|
||||
$hasAccess = (!$this->method);
|
||||
|
||||
if($this->method) {
|
||||
if(is_array($this->method)) {
|
||||
$hasAccess = (in_array($request->getMethod(), $this->getRequestMethods()));
|
||||
} else {
|
||||
$hasAccess = strtolower($this->getRequestMethods()) == strtolower($request->getMethod());
|
||||
}
|
||||
}
|
||||
|
||||
if(!$hasAccess) {
|
||||
throw new RouterException('Method not allowed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// No match here, move on...
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterResource extends RouterEntry {
|
||||
|
||||
const DEFAULT_METHOD = 'index';
|
||||
|
||||
protected $url;
|
||||
protected $controller;
|
||||
protected $method;
|
||||
protected $postMethod;
|
||||
|
||||
public function __construct($url, $controller) {
|
||||
parent::__construct();
|
||||
$this->url = $url;
|
||||
$this->controller = $controller;
|
||||
$this->postMethod = strtolower(($_SERVER['REQUEST_METHOD'] != 'GET') ? 'post' : 'get');
|
||||
}
|
||||
|
||||
public function renderRoute(Request $request) {
|
||||
// Load middleware
|
||||
$this->loadMiddleware($request);
|
||||
|
||||
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
|
||||
// When the callback is a function
|
||||
call_user_func_array($this->getCallback(), $this->getParameters());
|
||||
} else {
|
||||
// When the callback is a method
|
||||
$controller = explode('@', $this->getCallback());
|
||||
$className = $this->getNamespace() . '\\' . $controller[0];
|
||||
$class = $this->loadClass($className);
|
||||
$method = strtolower($controller[1]);
|
||||
|
||||
if (!method_exists($class, $method)) {
|
||||
throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
|
||||
}
|
||||
|
||||
call_user_func_array(array($class, $method), $this->getParameters());
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function call($method, $parameters) {
|
||||
$this->setCallback($this->controller . '@' . $method);
|
||||
$this->parameters = $parameters;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
$url = parse_url($request->getUri());
|
||||
$url = rtrim($url['path'], '/') . '/';
|
||||
|
||||
if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
|
||||
$url = rtrim($url, '/');
|
||||
|
||||
$strippedUrl = trim(substr($url, strlen($this->url)), '/');
|
||||
$path = explode('/', $strippedUrl);
|
||||
|
||||
$args = $path;
|
||||
$action = '';
|
||||
|
||||
if(count($args)) {
|
||||
$action = $args[0];
|
||||
array_shift($args);
|
||||
}
|
||||
|
||||
if (count($path)) {
|
||||
|
||||
// Delete
|
||||
if($request->getMethod() === self::REQUEST_TYPE_DELETE && $this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('destroy', $args);
|
||||
}
|
||||
|
||||
// Update
|
||||
if(in_array($request->getMethod(), array('put', 'patch')) && $this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('update', array_merge(array($action), $args));
|
||||
}
|
||||
|
||||
// Edit
|
||||
if(isset($args[0]) && strtolower($args[0]) === 'edit' && $this->postMethod === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('edit', array_merge(array($action), array_slice($args, 1)));
|
||||
}
|
||||
|
||||
// Create
|
||||
if(strtolower($action) === 'create' && $request->getMethod() === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('create', $args);
|
||||
}
|
||||
|
||||
// Save
|
||||
if($this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('store', $args);
|
||||
}
|
||||
|
||||
// Show
|
||||
if($action && $this->postMethod === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('show', array_merge(array($action), $args));
|
||||
}
|
||||
|
||||
// Index
|
||||
return $this->call('index', $args);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl() {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*/
|
||||
public function setUrl($url) {
|
||||
$url = rtrim($url, '/') . '/';
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getController() {
|
||||
return $this->controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
*/
|
||||
public function setController($controller) {
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod() {
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
*/
|
||||
public function setMethod($method) {
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterRoute extends RouterEntry {
|
||||
|
||||
const PARAMETERS_REGEX_MATCH = '{([A-Za-z\-\_]*?)}';
|
||||
|
||||
protected $url;
|
||||
|
||||
public function __construct($url, $callback) {
|
||||
parent::__construct();
|
||||
$this->setUrl($url);
|
||||
$this->setCallback($callback);
|
||||
|
||||
$this->settings['aliases'] = array();
|
||||
}
|
||||
|
||||
protected function parseParameters($url, $multiple = false, $regex = self::PARAMETERS_REGEX_MATCH) {
|
||||
$parameters = array();
|
||||
|
||||
if($multiple) {
|
||||
preg_match_all('/'.$regex.'/is', $url, $parameters);
|
||||
} else {
|
||||
preg_match('/'.$regex.'/is', $url, $parameters);
|
||||
}
|
||||
|
||||
if(isset($parameters[1]) && count($parameters[1]) > 0) {
|
||||
return $parameters[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
|
||||
// Check if request method is allowed
|
||||
|
||||
$url = parse_url($request->getUri());
|
||||
$url = $url['path'];
|
||||
|
||||
$route = $this->url;
|
||||
|
||||
$routeMatch = preg_replace('/'.self::PARAMETERS_REGEX_MATCH.'/is', '', $route);
|
||||
|
||||
// Check if url parameter count matches
|
||||
if(stripos($url, $routeMatch) === 0) {
|
||||
|
||||
$matches = true;
|
||||
|
||||
if($this->regexMatch) {
|
||||
$parameters = $this->parseParameters($url, true, $this->regexMatch);
|
||||
|
||||
// If regex doesn't match, make sure to return an array
|
||||
if(!is_array($parameters)) {
|
||||
$parameters = array();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$url = explode('/', $url);
|
||||
$route = explode('/', $route);
|
||||
|
||||
$parameters = array();
|
||||
|
||||
// Check if url matches
|
||||
foreach ($route as $i => $path) {
|
||||
$parameter = $this->parseParameters($path, false);
|
||||
|
||||
// Check if parameter of path matches, otherwise quit..
|
||||
if (is_null($parameter) && strtolower($path) != strtolower($url[$i])) {
|
||||
$matches = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Save parameter if we have one
|
||||
if ($parameter) {
|
||||
$parameterValue = $url[$i];
|
||||
$regex = (isset($this->parametersRegex[$parameter]) ? $this->parametersRegex[$parameter] : null);
|
||||
|
||||
if ($regex !== null) {
|
||||
// Use the regular expression rule provided to filter the value
|
||||
$matches = array();
|
||||
preg_match('/' . $regex . '/is', $url[$i], $matches);
|
||||
|
||||
if (count($matches)) {
|
||||
$parameterValue = $matches[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Add parameter value
|
||||
$parameters[$parameter] = $parameterValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This route matches
|
||||
if($matches) {
|
||||
$this->parameters = $parameters;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
// No match here, move on...
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl() {
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return self
|
||||
*/
|
||||
public function setUrl($url) {
|
||||
|
||||
$parameters = $this->parseParameters($url, true);
|
||||
|
||||
if($parameters !== null) {
|
||||
foreach($parameters as $param) {
|
||||
$this->parameters[$param] = '';
|
||||
}
|
||||
}
|
||||
|
||||
$this->url = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alias for the url which can be used when getting the url route.
|
||||
* @return string
|
||||
*/
|
||||
public function getAlias(){
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the url alias for easier getting the url route.
|
||||
* @param string $alias
|
||||
* @return self
|
||||
*/
|
||||
public function setAlias($alias){
|
||||
$this->alias = $alias;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSettings($settings) {
|
||||
|
||||
// Change as to alias
|
||||
if(isset($settings{'as'})) {
|
||||
$this->setAlias($settings['as']);
|
||||
}
|
||||
|
||||
return parent::setSettings($settings);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,135 +1,374 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ---------------------------
|
||||
* Router helper class
|
||||
* ---------------------------
|
||||
* This class is added so calls can be made staticly like Router::get() making the code look more pretty.
|
||||
*
|
||||
* This class is added so calls can be made statically like Router::get() making the code look pretty.
|
||||
* It also adds some extra functionality like default-namespace.
|
||||
*/
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
use Pecee\Http\Response;
|
||||
use Pecee\SimpleRouter\Exceptions\HttpException;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
|
||||
use Pecee\SimpleRouter\Route\IRoute;
|
||||
use Pecee\SimpleRouter\Route\RouteController;
|
||||
use Pecee\SimpleRouter\Route\RouteGroup;
|
||||
use Pecee\SimpleRouter\Route\RouteResource;
|
||||
use Pecee\SimpleRouter\Route\RouteUrl;
|
||||
|
||||
class SimpleRouter {
|
||||
class SimpleRouter
|
||||
{
|
||||
/**
|
||||
* Default namespace added to all routes
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultNamespace;
|
||||
|
||||
/**
|
||||
* Start/route request
|
||||
* @param null $defaultNamespace
|
||||
* @throws RouterException
|
||||
*/
|
||||
public static function start($defaultNamespace = null) {
|
||||
$router = RouterBase::GetInstance();
|
||||
$router->setDefaultNamespace($defaultNamespace);
|
||||
$router->routeRequest();
|
||||
}
|
||||
/**
|
||||
* The response object
|
||||
* @var Response
|
||||
*/
|
||||
protected static $response;
|
||||
|
||||
/**
|
||||
* Set base csrf verifier
|
||||
* @param BaseCsrfVerifier $baseCsrfVerifier
|
||||
*/
|
||||
public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier) {
|
||||
RouterBase::getInstance()->setBaseCsrfVerifier($baseCsrfVerifier);
|
||||
}
|
||||
/**
|
||||
* Start/route request
|
||||
*
|
||||
* @throws HttpException
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public static function start()
|
||||
{
|
||||
static::router()->routeRequest();
|
||||
}
|
||||
|
||||
public static function get($url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->addSettings($settings);
|
||||
$route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_GET));
|
||||
/**
|
||||
* Set default namespace which will be prepended to all routes.
|
||||
*
|
||||
* @param string $defaultNamespace
|
||||
*/
|
||||
public static function setDefaultNamespace($defaultNamespace)
|
||||
{
|
||||
static::$defaultNamespace = $defaultNamespace;
|
||||
}
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($route);
|
||||
/**
|
||||
* Base CSRF verifier
|
||||
*
|
||||
* @param BaseCsrfVerifier $baseCsrfVerifier
|
||||
*/
|
||||
public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier)
|
||||
{
|
||||
static::router()->setCsrfVerifier($baseCsrfVerifier);
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
public static function post($url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->addSettings($settings);
|
||||
$route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_POST));
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($route);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
public static function put($url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->addSettings($settings);
|
||||
$route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_PUT));
|
||||
/**
|
||||
* Route 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);
|
||||
}
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($route);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
public static function delete($url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->addSettings($settings);
|
||||
$route->setRequestMethods(array(RouterRoute::REQUEST_TYPE_DELETE));
|
||||
/**
|
||||
* 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);
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($route);
|
||||
if (is_callable($callback) === false) {
|
||||
throw new \InvalidArgumentException('Invalid callback provided. Only functions or methods supported');
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
static::router()->addRoute($group);
|
||||
|
||||
public static function group($settings = array(), $callback) {
|
||||
$group = new RouterGroup();
|
||||
$group->setCallback($callback);
|
||||
return $group;
|
||||
}
|
||||
|
||||
if($settings !== null && is_array($settings)) {
|
||||
$group->setSettings($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);
|
||||
}
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($group);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
|
||||
public static function match(array $requestMethods, $url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->setRequestMethods($requestMethods);
|
||||
$route->addSettings($settings);
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
}
|
||||
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($route);
|
||||
static::router()->addRoute($route);
|
||||
|
||||
return $route;
|
||||
}
|
||||
return $route;
|
||||
}
|
||||
|
||||
public static function all($url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->addSettings($settings);
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($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);
|
||||
|
||||
return $route;
|
||||
}
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
}
|
||||
|
||||
public static function controller($url, $controller, array $settings = null) {
|
||||
$route = new RouterController($url, $controller);
|
||||
$route->addSettings($settings);
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($route);
|
||||
static::router()->addRoute($route);
|
||||
|
||||
return $route;
|
||||
}
|
||||
return $route;
|
||||
}
|
||||
|
||||
public static function resource($url, $controller, array $settings = null) {
|
||||
$route = new RouterResource($url, $controller);
|
||||
$route->addSettings($settings);
|
||||
$router = RouterBase::getInstance();
|
||||
$router->addRoute($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);
|
||||
|
||||
return $route;
|
||||
}
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
}
|
||||
|
||||
public function getRoute($controller = null, $parameters = null, $getParams = null) {
|
||||
return RouterBase::getInstance()->getRoute($controller, $parameters, $getParams);
|
||||
}
|
||||
static::router()->addRoute($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);
|
||||
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
}
|
||||
|
||||
static::router()->addRoute($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 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());
|
||||
}
|
||||
|
||||
return static::$response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
if ($route->getNamespace() !== null) {
|
||||
$namespace .= '\\' . $route->getNamespace();
|
||||
}
|
||||
|
||||
$route->setDefaultNamespace($namespace);
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
class DummyController
|
||||
{
|
||||
public function start()
|
||||
{
|
||||
echo static::class . '@' . 'start() OK';
|
||||
}
|
||||
|
||||
public function param($params = null)
|
||||
{
|
||||
$params = func_get_args();
|
||||
echo 'Params: ' . join(', ', $params);
|
||||
}
|
||||
|
||||
public function notFound()
|
||||
{
|
||||
echo 'not found';
|
||||
}
|
||||
|
||||
public function silent() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
require_once 'Exceptions/MiddlewareLoadedException.php';
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class DummyMiddleware implements IMiddleware
|
||||
{
|
||||
public function handle(Request $request, \Pecee\SimpleRouter\Route\ILoadableRoute &$route)
|
||||
{
|
||||
throw new MiddlewareLoadedException('Middleware loaded!');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
class MiddlewareLoadedException extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class ExceptionHandler implements \Pecee\Handlers\IExceptionHandler
|
||||
{
|
||||
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\Route\ILoadableRoute &$route = null, \Exception $error)
|
||||
{
|
||||
throw $error;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
|
||||
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
|
||||
|
||||
class GroupTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $result;
|
||||
|
||||
public function testGroupLoad()
|
||||
{
|
||||
$this->result = false;
|
||||
|
||||
SimpleRouter::group(['prefix' => '/group'], function () {
|
||||
$this->result = true;
|
||||
});
|
||||
|
||||
try {
|
||||
SimpleRouter::start();
|
||||
} catch (Exception $e) {
|
||||
// ignore RouteNotFound exception
|
||||
}
|
||||
|
||||
$this->assertTrue($this->result);
|
||||
}
|
||||
|
||||
public function testNestedGroup()
|
||||
{
|
||||
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setUri('/api/v1/test');
|
||||
SimpleRouter::request()->setMethod('get');
|
||||
|
||||
SimpleRouter::group(['prefix' => '/api'], function () {
|
||||
|
||||
SimpleRouter::group(['prefix' => '/v1'], function () {
|
||||
SimpleRouter::get('/test', 'DummyController@start');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::start();
|
||||
}
|
||||
|
||||
public function testManyRoutes()
|
||||
{
|
||||
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setUri('/my/match');
|
||||
SimpleRouter::request()->setMethod('get');
|
||||
|
||||
SimpleRouter::group(['prefix' => '/api'], function () {
|
||||
|
||||
SimpleRouter::group(['prefix' => '/v1'], function () {
|
||||
SimpleRouter::get('/test', 'DummyController@start');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::get('/my/match', 'DummyController@start');
|
||||
|
||||
SimpleRouter::group(['prefix' => '/service'], function () {
|
||||
|
||||
SimpleRouter::group(['prefix' => '/v1'], function () {
|
||||
SimpleRouter::get('/no-match', 'DummyController@start');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::start();
|
||||
}
|
||||
|
||||
public function testUrls()
|
||||
{
|
||||
|
||||
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 method name
|
||||
SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setName('fancy2');
|
||||
|
||||
SimpleRouter::start();
|
||||
|
||||
$this->assertEquals('/my/fancy/url/1/', SimpleRouter::getUrl('fancy1'));
|
||||
$this->assertEquals('/my/fancy/url/2/', SimpleRouter::getUrl('fancy2'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandler.php';
|
||||
|
||||
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');
|
||||
|
||||
SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function () {
|
||||
SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
|
||||
});
|
||||
|
||||
$found = false;
|
||||
|
||||
try {
|
||||
SimpleRouter::start();
|
||||
} catch (\Exception $e) {
|
||||
$found = ($e instanceof MiddlewareLoadedException);
|
||||
}
|
||||
|
||||
$this->assertTrue($found);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandler.php';
|
||||
|
||||
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException as NotFoundHttpException;
|
||||
|
||||
class RouterRouteTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $result = false;
|
||||
|
||||
public function testNotFound()
|
||||
{
|
||||
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');
|
||||
});
|
||||
|
||||
$found = false;
|
||||
|
||||
try {
|
||||
SimpleRouter::start();
|
||||
} catch (\Exception $e) {
|
||||
$found = ($e instanceof NotFoundHttpException && $e->getCode() == 404);
|
||||
}
|
||||
|
||||
$this->assertTrue($found);
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setUri('/my/test/url');
|
||||
SimpleRouter::request()->setMethod('get');
|
||||
|
||||
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');
|
||||
|
||||
SimpleRouter::post('/my/test/url', 'DummyController@start');
|
||||
SimpleRouter::start();
|
||||
}
|
||||
|
||||
public function testPut()
|
||||
{
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setUri('/my/test/url');
|
||||
SimpleRouter::request()->setMethod('put');
|
||||
|
||||
SimpleRouter::put('/my/test/url', 'DummyController@start');
|
||||
SimpleRouter::start();
|
||||
}
|
||||
|
||||
public function testDelete()
|
||||
{
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setUri('/my/test/url');
|
||||
SimpleRouter::request()->setMethod('delete');
|
||||
|
||||
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::get('/my/test/url', 'DummyController@start');
|
||||
|
||||
try {
|
||||
SimpleRouter::start();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals(403, $e->getCode());
|
||||
}
|
||||
}
|
||||
|
||||
public function testSimpleParam()
|
||||
{
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setMethod('get');
|
||||
SimpleRouter::request()->setUri('/test-param1');
|
||||
|
||||
SimpleRouter::get('/test-{param1}', 'DummyController@param');
|
||||
SimpleRouter::start();
|
||||
}
|
||||
|
||||
public function testMultiParam()
|
||||
{
|
||||
SimpleRouter::router()->reset();
|
||||
SimpleRouter::request()->setMethod('get');
|
||||
SimpleRouter::request()->setUri('/test-param1-param2');
|
||||
|
||||
SimpleRouter::get('/test-{param1}-{param2}', '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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandler.php';
|
||||
|
||||
use Pecee\SimpleRouter\SimpleRouter as SimpleRouter;
|
||||
|
||||
class RouterUrlTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $result = false;
|
||||
|
||||
protected function getUrl($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('/');
|
||||
|
||||
// Match normal route on alias
|
||||
SimpleRouter::get('/', 'DummyController@silent', ['as' => 'home']);
|
||||
|
||||
SimpleRouter::get('/about', 'DummyController@about');
|
||||
|
||||
SimpleRouter::group(['prefix' => '/admin', 'as' => 'admin'], function() {
|
||||
|
||||
// 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 NO alias
|
||||
SimpleRouter::controller('/pages', 'DummyController');
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::group(['prefix' => 'api', 'as' => 'api'], function() {
|
||||
|
||||
// Match resource controller
|
||||
SimpleRouter::resource('phones', 'DummyController');
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::controller('gadgets', 'DummyController', ['names' => ['getIphoneInfo' => 'iphone']]);
|
||||
|
||||
// Match controller with no prefix and no alias
|
||||
SimpleRouter::controller('/cats', 'CatsController');
|
||||
|
||||
// Pretend to load page
|
||||
SimpleRouter::start();
|
||||
|
||||
$this->assertEquals('/gadgets/iphoneinfo/', $this->getUrl('gadgets.iphone'));
|
||||
|
||||
$this->assertEquals('/api/phones/create/', $this->getUrl('api.phones.create'));
|
||||
|
||||
// Should match /
|
||||
$this->assertEquals('/', $this->getUrl('home'));
|
||||
|
||||
// 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('admin.home'));
|
||||
|
||||
// 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/home/
|
||||
$this->assertEquals('/admin/users/home/', $this->getUrl('admin.users@home'));
|
||||
|
||||
// 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/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 /?jackdaniels=true&cola=yeah
|
||||
$this->assertEquals('/?jackdaniels=true&cola=yeah', $this->getUrl('home', null, ['jackdaniels' => 'true', 'cola' => 'yeah']));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user