Compare commits

..

31 Commits

Author SHA1 Message Date
Simon Sessingø 0cc0a59fd5 Merge pull request #105 from skipperbent/development
Development
2016-06-04 15:13:47 +02:00
Simon Sessingø 498fd6b07d Merge pull request #103 from skipperbent/development
Added setValue method to InputItem class.
2016-05-04 13:41:36 +02:00
Simon Sessingø 96ab22a4f8 Merge pull request #102 from skipperbent/development
Added exist method to Input class.
2016-05-03 07:21:16 +02:00
Simon Sessingø 7f528c133b Merge pull request #101 from skipperbent/development
Development
2016-05-01 02:01:47 +02:00
Simon Sessingø 5a50190293 Merge pull request #100 from skipperbent/development
Development
2016-04-25 00:41:50 +02:00
Simon Sessingø 355ef01d63 Merge pull request #99 from skipperbent/development
Development
2016-04-22 15:38:02 +02:00
Simon Sessingø d3162b5a2b Merge pull request #98 from skipperbent/development
Development
2016-04-22 14:30:40 +02:00
Simon Sessingø 810b80487d Merge pull request #97 from skipperbent/development
- Added custom ExceptionHandler example to documentation.
2016-04-21 08:30:34 +02:00
Simon Sessingø 18a9df56ca Merge pull request #96 from skipperbent/development
Development
2016-04-20 08:10:18 +02:00
Simon Sessingø 6e14ded03f Merge pull request #95 from skipperbent/development
Development
2016-04-16 23:23:56 +02:00
Simon Sessingø 899081f8d8 Merge pull request #94 from skipperbent/development
Update README.md
2016-04-16 00:01:22 +02:00
Simon Sessingø e7b9206bc9 Merge pull request #93 from skipperbent/development
Development
2016-04-15 23:21:00 +02:00
Simon Sessingø cd6e800984 Merge pull request #91 from skipperbent/development
Development
2016-04-15 23:14:55 +02:00
Simon Sessingø 11bd5a7d11 Merge pull request #89 from skipperbent/development
[BUGFIX] Fixed notice
2016-04-09 15:39:12 +02:00
Simon Sessingø be32796b01 Merge pull request #88 from skipperbent/development
[TASK] Moved group-middleware rendering to routeRequest to ensure all…
2016-04-09 15:32:45 +02:00
Simon Sessingø 8b3d71a328 Merge pull request #87 from skipperbent/development
[BUGFIX] Fixed only match group route if prefix is set
2016-04-09 10:02:22 +02:00
Simon Sessingø 1fae638aaf Merge pull request #86 from skipperbent/development
Development
2016-04-09 09:50:56 +02:00
Simon Sessingø 37c8bc9f32 Merge pull request #79 from skipperbent/development
[BUGFIX] Bugfixes and optimisations
2016-04-07 23:21:13 +02:00
Simon Sessingø 75029b330a Merge pull request #78 from skipperbent/development
[BUGFIX] Fixed nested groups not merging settings to routes
2016-04-07 19:34:02 +02:00
Simon Sessingø fd5d893040 Merge pull request #77 from skipperbent/development
[TASK] Added rewrite_uri parameter to Request class
2016-03-19 19:12:42 +01:00
Simon Sessingø c1512740af Merge pull request #76 from skipperbent/development
[BUGFIX] Readded rendering of groups
2016-03-19 18:59:01 +01:00
Simon Sessingø 212ae133de Merge pull request #75 from skipperbent/development
[TASK] Readded merging
2016-03-19 17:40:26 +01:00
Simon Sessingø ae58231fa1 Merge pull request #74 from skipperbent/development
Custom boot-managers
2016-03-19 16:29:03 +01:00
Simon Sessingø 358b25d4f1 Merge pull request #73 from skipperbent/development
Development
2016-03-18 17:55:31 +01:00
Simon Sessingø 3d45851d9b Merge pull request #72 from skipperbent/development
[BUGFIX] Only render group if prefix matches.
2016-03-16 19:58:03 +01:00
Simon Sessingø ee5c2207f8 Merge pull request #71 from skipperbent/development
Added support for x-forwarded-proto http header
2016-03-14 01:08:25 +01:00
Simon Sessingø b1ca3fc9ef Merge pull request #70 from skipperbent/development
[FEATURE] Added http code to redirect method.
2016-03-14 00:59:09 +01:00
Simon Sessingø 253c0c70d4 Merge pull request #69 from skipperbent/development
[BUGFIX] Bugfix
2016-03-01 22:52:38 +01:00
Simon Sessingø 53ba2d7ac5 Merge pull request #68 from skipperbent/development
[TASK] Fixed regex causing optional parameters to sometimes catch req…
2016-01-23 16:12:27 +01:00
Simon Sessingø 315fe05769 Merge pull request #67 from skipperbent/development
Development
2016-01-17 04:57:39 +01:00
Simon Sessingø a57113309a Merge pull request #66 from skipperbent/development
Development
2016-01-15 11:56:04 +01:00
38 changed files with 973 additions and 1531 deletions
+1 -2
View File
@@ -1,4 +1,3 @@
.idea
composer.lock
vendor/
demo-project/vendor
vendor/
+140 -151
View File
@@ -18,7 +18,7 @@ The goal of this project is to create a router that is 100% compatible with the
### Features
- Basic routing (`GET`, `POST`, `PUT`, `DELETE`) with support for custom multiple verbs.
- Basic routing (get, post, put, delete) with support for custom multiple verbs.
- Regular Expression Constraints for parameters.
- Named routes.
- Generating url to routes.
@@ -32,14 +32,6 @@ The goal of this project is to create a router that is 100% compatible with the
- Custom boot managers to redirect urls to other routes
- Input manager; to manage `GET`, `POST` params.
## Installation and demo
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
In your ```index.php``` require your ```routes.php``` and call the ```routeRequest()``` method when all your custom routes has been loaded. This will trigger and do the actual routing of the requests.
@@ -49,18 +41,13 @@ This is an example of a basic ```index.php``` file:
```php
use \Pecee\SimpleRouter\SimpleRouter;
// Load external routes file
require_once 'routes.php';
require_once 'routes.php'; // change this to whatever makes sense in your project
/*
* 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.
*/
SimpleRouter::setDefaultNamespace('MyWebsite\Controller');
// The apps default namespace (so we don't have to specify it each time we use MyController@home)
$defaultControllerNamespace = 'MyWebsite\\Controller';
// Start the routing
SimpleRouter::start();
// Do the routing
SimpleRouter::start($defaultControllerNamespace);
```
## Adding routes
@@ -86,9 +73,7 @@ use Pecee\SimpleRouter\SimpleRouter;
// Add CSRF support (if needed)
SimpleRouter::csrfVerifier(new \Pecee\Http\Middleware\BaseCsrfVerifier());
SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfound']);
SimpleRouter::group(['prefix' => '/v1', 'middleware' => '\MyWebsite\Middleware\SomeMiddlewareClass'], function() {
SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\SomeMiddlewareClass'], function() {
SimpleRouter::group(['prefix' => '/services', 'exceptionHandler' => '\MyProject\Handler\CustomExceptionHandler'], function() {
@@ -123,7 +108,7 @@ SimpleRouter::group(['prefix' => '/v1', 'middleware' => '\MyWebsite\Middleware\S
This is a basic example of an ExceptionHandler implementation:
```php
namespace Demo\Handlers;
namespace BB\Handlers;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
@@ -134,14 +119,7 @@ class CustomExceptionHandler implements IExceptionHandler {
// If the error-code is 404; show another route which contains the page-not-found
if($error->getCode() === 404) {
// Throw your custom 404-page view
// - or -
// load another route with our 404 page
// - or -
// you can return the $request object to ignore the error and continue on rendering the route.
return $request->setUri(url('page.notfound'));
// Load your custom 404-page view
}
// Output error as json if on api path.
@@ -154,7 +132,7 @@ class CustomExceptionHandler implements IExceptionHandler {
}
}
```
``
### Sub-domain routing
@@ -198,39 +176,111 @@ 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.
```php
namespace Demo;
<?php
<?php
namespace Pecee;
use Pecee\Exception\RouterException;
use Pecee\Handler\ExceptionHandler;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\SimpleRouter\RouterBase;
use Pecee\SimpleRouter\SimpleRouter;
class Router extends SimpleRouter {
public static function start() {
protected static $defaultExceptionHandler;
protected static $defaultMiddlewares = array();
// change this to whatever makes sense in your project
require_once 'routes.php';
// change default namespace for all routes
parent::setDefaultNamespace('\Demo\Controllers');
public static function start($defaultNamespace = null) {
// Do initial stuff
parent::start();
// Debug information
Debug::getInstance()->add('Router initialised.');
// Load framework specific controllers
static::get('/js-wrap', 'ControllerJs@wrap', ['namespace' => '\Pecee\Controller'])->setAlias('pecee.js.wrap');
static::get('/css-wrap', 'ControllerCss@wrap', ['namespace' => '\Pecee\Controller'])->setAlias('pecee.css.wrap');
static::get('/captcha', 'ControllerCaptcha@show', ['namespace' => '\Pecee\Controller']);
// Load routes.php
$file = $_ENV['base_path'] . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'routes.php';
if(file_exists($file)) {
require_once $file;
}
// Set default namespace
$defaultNamespace = '\\'.$_ENV['app_name'] . '\\Controller';
// Handle exceptions
try {
if(count(static::$defaultMiddlewares)) {
/* @var $middleware \Pecee\Http\Middleware\IMiddleware */
foreach(static::$defaultMiddlewares as $middleware) {
$middleware = new $middleware();
if(!($middleware instanceof IMiddleware)) {
throw new RouterException('Middleware must be implement the IMiddleware interface.');
}
$middleware->handle(RouterBase::getInstance()->getRequest());
}
}
parent::start($defaultNamespace);
} catch(\Exception $e) {
$route = RouterBase::getInstance()->getLoadedRoute();
// Otherwise use the fallback default exceptions handler
if(static::$defaultExceptionHandler !== null) {
static::loadExceptionHandler(static::$defaultExceptionHandler, $route, $e);
}
throw $e;
}
}
protected static function loadExceptionHandler($class, $route, $e) {
$class = new $class();
if(!($class instanceof ExceptionHandler)) {
throw new \ErrorException('Exception handler must be an instance of \Pecee\Handler\ExceptionHandler');
}
$class->handleError(RouterBase::getInstance()->getRequest(), $route, $e);
}
public static function defaultExceptionHandler($handler) {
static::$defaultExceptionHandler = $handler;
}
/**
* Add default middleware that will be loaded before any route
* @param string|array $middlewares
*/
public static function defaultMiddleware($middlewares) {
if(is_array($middlewares)) {
static::$defaultMiddlewares = $middlewares;
} else {
static::$defaultMiddlewares[] = $middlewares;
}
}
}
```
## Helper functions
To simplify to use of simple-router functionality, we recommend you add these helper functions to your project.
#### Helper functions examples
**This is a basic example of a helper function for generating urls.**
```php
use Pecee\SimpleRouter\SimpleRouter;
use Pecee\SimpleRouter\RouterBase;
function url($controller, $parameters = null, $getParams = null) {
SimpleRouter::getRoute($controller, $parameters, $getParams);
RouterBase::getInstance()->getRoute($controller, $parameters, $getParams);
}
```
**This is a basic example for getting the current csrf token**
```php
/**
* Get current csrf-token
* @return null|string
@@ -239,30 +289,6 @@ 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
@@ -298,10 +324,7 @@ use Pecee\Http\Middleware\BaseCsrfVerifier;
class CsrfVerifier extends BaseCsrfVerifier {
protected $except = [
'/companies/*',
'/api'
];
protected $except = ['/companies/*', '/user/save'];
}
```
@@ -319,6 +342,7 @@ Sometimes it can be necessary to keep urls stored in the database, file or simil
To interfere with the router, we create a class that inherits from ```RouterBootManager```. 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\RouterBootManager;
@@ -355,109 +379,62 @@ By doing this the route will now load the url ```/article/view/1``` instead of `
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\RouterBase``` instance's `loadedRoute` property.
For easy access you can use the shortcut method `\Pecee\SimpleRouter\SimpleRouter::router()`.
**routes.php example:**
```php
use Pecee\SimpleRouter;
$route = SimpleRouter::router()->getLoadedRoute();
// Add new bootmanager
SimpleRouter::addBootManager(new CustomRouterRules());
// This rule is what our custom bootmanager will use.
SimpleRouter::get('/article/view/{id}', 'ControllerArticle@view');
```
## Easily overwrite route about to be loaded
Sometimes it can be useful to manipulate the route that's about to be loaded, for instance if a user is not authenticated or if an error occurred within your Middleware that requires
some other route to be initialised. 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\Http\Request``` object.
**Note:** Please note that it's only possible to change the route BEFORE any route has initially been loaded, so doing this in your custom ExceptionHandler or Middleware is highly recommended.
```php
$route = Request::getInstance()->getLoadedRoute();
$route->setCallback('Example\MyCustomClass@hello');
// -- or you can rewrite by doing --
// -- or --
$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 `RouterEntry` 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\RouterEntry;
class CustomMiddleware implements Middleware {
public function handle(Request $request, RouterEntry &$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\RouterEntry;
class CustomMiddleware implements Middleware {
public function handle(Request $request, RouterEntry &$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');
$value = Request::getInstance()->getInput()->get('name');
```
**Return parameter object (matches both GET, POST, FILE):**
```php
$object = input()->getObject('name');
$object = Request::getInstance()->getInput()->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;
$object = Request::getInstance()->getInput()->get->name;
$object = Request::getInstance()->getInput()->post->name;
$object = Request::getInstance()->getInput()->file->name;
```
**Return all parameters:**
```php
// Get all
$values = input()->all();
$objects = Request::getInstance()->getInput()->all();
// Only match certain keys
$values = input()->all([
$objects = Request::getInstance()->getInput()->all([
'company_name',
'user_id'
]);
@@ -477,13 +454,26 @@ All object inherits from `InputItem` class and will always contain these methods
- `getError()` - get file upload error.
### Easy access to methods
### Easy access your input
Create a helper function to easily get access to the input elements.
Below example requires you to have the helper functions added. Please refer to the helper functions section in the documentation.
Example:
```php
/**
* Get input class
* @return \Pecee\Http\Input\Input
*/
function input() {
return \Pecee\Http\Request::getInstance()->getInput();
}
```
Then you can easily do something like this in your controller:
```php
// Get parameter site_id or default-value 2
$siteId = input()->get('site_id', 2);
$value = input()->get('site_id', '2');
```
## Sites
@@ -492,7 +482,6 @@ 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:
-100
View File
@@ -1,100 +0,0 @@
# Simple PHP router demo project
This project is here to give you a basic understanding of how to setup and using simple-php-router.
Please note that this demo-project only covers how to integrate the `simple-php-router` in a project without a framework. If you are using some sort of PHP framework in your project the implementation might vary.
**What we won't cover:**
- How to setup a solution that fits your need. This is a basic demo to help you get started.
- Understanding of MVC; including Controllers, Middlewares or ExceptionHandlers.
- How to integrate into third party frameworks.
**What we cover:**
- How to get up and running fast - from scratch.
- How to get ExceptionHandlers, Middlewares and Controllers working.
- How to setup your webservers.
## Installation
- Navigate to the `demo-project` folder in terminal and run `composer update` to install the latest version.
- Point your webserver to `demo-project/public`.
### Setting up Nginx
If you are using Nginx please make sure that url-rewriting is enabled.
You can easily enable url-rewriting by adding the following configuration for the Nginx configuration-file for the demo-project.
```
location / {
try_files $uri $uri/ /index.php?$query_string;
}
```
### Setting up Apache
Nothing special is required for Apache to work. We've include the `.htaccess` file in the `public` folder. If rewriting is not working for you, please check that the `mod_rewrite` module (htaccess support) is enabled in the Apache configuration.
## Folder structure
| Folder | Description |
| ------------- |-------------|
| app |Contains projects-specific PHP classes|
| public |Public folder which are accessible through the web.|
## Notes
The demo project has it's own `Router` class implementation which extends the `SimpleRouter` class with further functionality.
This class can be useful adding additional functionality that are required before and after routing occurs or any extra functionality belonging to the router itself.
In this project we also use our custom router-class to autoload the `routes.php` file from our custom location (`app/routes.php`).
Please check the `routes.php` file in `demo-project/app` for all the urls/rules available in the project.
### CSRF-verifier
For the purpose of this demo, we've added a custom CSRF-verifier middleware called `CsrfVerifier` and disabled CSRF checks for all calls to `/api/*`. This will ensure that CSRF form-checks are not applied when calling our demo api url.
### Exception handlers
The included `CustomExceptionHandler` class returns a very basic json response for errors received on calls to `/api/*` or otherwise just a simple formatted error response.
### Middlewares
`ApiVerification` class is added to all calls to `/api/*`. This simple class just adds some data to the `Request` object, which is returned in one of the methods in the `ApiController` class. We've added this class to demonstrate that you can use middlewares to ensure that the user has the correct authentication - before router loads the controller itself.
### Urls
Please see `routes.php` for all routes and rules.
| URL |
| ------------- |
| / |
| /api/demo |
| /companies |
| /companies/[id] |
| /contact |
## The MIT License (MIT)
Copyright (c) 2016 Simon Sessingø / simple-php-router
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -1,20 +0,0 @@
<?php
namespace Demo\Controllers;
use Pecee\SimpleRouter\SimpleRouter;
class ApiController {
public function index() {
// The variable authenticated is set to true in the ApiVerification middleware class.
header('content-type: application/json');
echo json_encode([
'authenticated' => request()->authenticated
]);
}
}
@@ -1,29 +0,0 @@
<?php
namespace Demo\Controllers;
class DefaultController {
public function index() {
// implement
echo sprintf('DefaultController -> index (?fun=%s)', input()->get('fun'));
}
public function contact() {
echo 'DefaultController -> contact';
}
public function companies($id = null) {
echo 'DefaultController -> companies -> id: ' . $id;
}
public function notFound() {
echo 'Page not found';
}
}
@@ -1,34 +0,0 @@
<?php
namespace Demo\Handlers;
use Pecee\Handler\IExceptionHandler;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
class CustomExceptionHandler implements IExceptionHandler {
public function handleError( Request $request, RouterEntry &$route = null, \Exception $error) {
// Return json errors if we encounter an error on /api.
if(stripos($request->getUri(), '/api') !== false) {
header('content-type: application/json');
echo json_encode([
'error' => $error->getMessage(),
'code' => $error->getCode()
]);
die();
}
// else we just throw the error
if($error->getCode() == 404) {
// Return 404 path
$request->setUri('/404');
return $request;
}
throw $error;
}
}
@@ -1,19 +0,0 @@
<?php
namespace Demo\Middlewares;
use Pecee\Http\Middleware\IMiddleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
class ApiVerification implements IMiddleware {
public function handle(Request $request, RouterEntry &$route) {
// Do authentication
$request->authenticated = true;
return $request;
}
}
@@ -1,13 +0,0 @@
<?php
namespace Demo\Middlewares;
use Pecee\Http\Middleware\BaseCsrfVerifier;
class CsrfVerifier extends BaseCsrfVerifier {
/**
* CSRF validation will be ignored on the following urls.
*/
protected $except = ['/api/*'];
}
-29
View File
@@ -1,29 +0,0 @@
<?php
/**
* Custom router which handles default middlewares, default exceptions and things
* that should be happen before and after the router is initialised.
*/
namespace Demo;
use Pecee\SimpleRouter\SimpleRouter;
class Router extends SimpleRouter {
public static function start($defaultNamespace = null) {
// Load our helpers
require_once 'helpers.php';
// Load our custom routes
require_once 'routes.php';
parent::setDefaultNamespace('\Demo\Controllers');
// Do initial stuff
parent::start();
}
}
-39
View File
@@ -1,39 +0,0 @@
<?php
use Pecee\SimpleRouter\SimpleRouter;
function url($controller, $parameters = null, $getParams = null) {
SimpleRouter::getRoute($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();
}
-23
View File
@@ -1,23 +0,0 @@
<?php
/**
* This file contains all the routes for the project
*/
use Demo\Router;
Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
Router::group(['exceptionHandler' => 'Demo\Handlers\CustomExceptionHandler'], function() {
Router::get('/', 'DefaultController@index')->setAlias('home');
Router::get('/contact', 'DefaultController@contact')->setAlias('contact');
Router::get('/404', 'DefaultController@notFound')->setAlias('404');
Router::basic('/companies', 'DefaultController@companies')->setAlias('companies');
Router::basic('/companies/{id}', 'DefaultController@companies')->setAlias('companies');
// Api
Router::group(['prefix' => '/api', 'middleware' => 'Demo\Middlewares\ApiVerification'], function() {
Router::resource('/demo', 'ApiController');
});
});
-26
View File
@@ -1,26 +0,0 @@
{
"name": "pecee/simple-router-demo",
"description": "Simple router demo project",
"keywords": [
"simple-router",
"php",
"php-simple-router"
],
"license": "MIT",
"type": "project",
"require": {
"php": ">=5.4.0",
"pecee/simple-router": "2.*"
},
"require-dev": {
},
"config": {
"preferred-install": "dist"
},
"autoload": {
"psr-4": {
"Demo\\": "app/"
}
}
}
-5
View File
@@ -1,5 +0,0 @@
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-l
RewriteRule ^(.*)$ index.php/$1
-7
View File
@@ -1,7 +0,0 @@
<?php
// load composer dependencies
require '../vendor/autoload.php';
// Start the routing
\Demo\Router::start();
-1
View File
@@ -1,4 +1,3 @@
<?php
namespace Pecee\Exception;
class RouterException extends \Exception { }
+1 -7
View File
@@ -6,12 +6,6 @@ use Pecee\SimpleRouter\RouterEntry;
interface IExceptionHandler {
/**
* @param Request $request
* @param RouterEntry|null $route
* @param \Exception $error
* @return Request|null
*/
public function handleError(Request $request, RouterEntry &$route = null, \Exception $error);
public function handleError(Request $request, RouterEntry $router = null, \Exception $error);
}
+22 -40
View File
@@ -20,13 +20,7 @@ class Input {
*/
public $file;
/**
* @var Request
*/
protected $request;
public function __construct(Request $request) {
$this->request = $request;
public function __construct() {
$this->setGet();
$this->setPost();
$this->setFile();
@@ -38,31 +32,17 @@ class Input {
* @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);
$output = $this->get->getData();
$output = array_merge($output, $this->post->getData());
if($filter !== null) {
$output = array_filter($output, function ($key) use ($filter) {
if (in_array($key, $filter)) {
return true;
$tmp = array();
foreach($output as $key => $val) {
if(in_array($key, $filter)) {
$tmp[$key] = $val;
}
return false;
}, ARRAY_FILTER_USE_KEY);
}
return $tmp;
}
return $output;
@@ -78,7 +58,7 @@ class Input {
return ($key !== null) ? $element[$key] : $element;
}
if($this->request->getMethod() !== 'get') {
if(Request::getInstance()->getMethod() !== 'get') {
$element = $this->post->findFirst($index);
@@ -107,7 +87,7 @@ class Input {
if($item !== null) {
if($item instanceof InputCollection || $item instanceof InputFile) {
if(is_array($item) || $item instanceof InputFile) {
return $item;
}
@@ -131,10 +111,10 @@ class Input {
continue;
}
$output = new InputCollection();
$output = array();
foreach($get as $k => $g) {
$output->{$k} = new InputItem($k, $g);
$output[$k] = new InputItem($k, $g);
}
$this->get->{$key} = $output;
@@ -145,10 +125,12 @@ class Input {
public function setPost() {
$this->post = new InputCollection();
$postVars = $_POST;
$postVars = array();
if(in_array($this->request->getMethod(), ['put', 'patch', 'delete'])) {
if(isset($_SERVER['REQUEST_METHOD']) && in_array($_SERVER['REQUEST_METHOD'], ['PUT', 'PATCH', 'DELETE'])) {
parse_str(file_get_contents('php://input'), $postVars);
} else {
$postVars = $_POST;
}
if(count($postVars)) {
@@ -159,10 +141,10 @@ class Input {
continue;
}
$output = new InputCollection();
$output = array();
foreach($post as $k => $p) {
$output->{$k} = new InputItem($k, $p);
foreach($post as $k=>$p) {
$output[$k] = new InputItem($k, $p);
}
$this->post->{strtolower($key)} = $output;
@@ -190,7 +172,7 @@ class Input {
continue;
}
$output = new InputCollection();
$output = array();
foreach($value['name'] as $k=>$val) {
// Strip empty values
@@ -201,7 +183,7 @@ class Input {
$file->setType($value['type'][$k]);
$file->setTmpName($value['tmp_name'][$k]);
$file->setError($value['error'][$k]);
$output->{$k} = $file;
$output[$k] = $file;
}
}
+2 -20
View File
@@ -10,10 +10,9 @@ class InputCollection implements \IteratorAggregate {
* Useful for searching for finding items where $index doesn't contain form name.
*
* @param string $index
* @param string|null $defaultValue
* @return mixed
*/
public function findFirst($index, $defaultValue = null) {
public function findFirst($index) {
if(count($this->data)) {
if(isset($this->data[$index])) {
@@ -27,24 +26,7 @@ class InputCollection implements \IteratorAggregate {
}
}
return $defaultValue;
}
public function getValue($index, $defaultValue = null) {
if(count($this->data)) {
if(isset($this->data[$index])) {
return $this->data[$index]->getValue();
}
foreach($this->data as $key => $value) {
if(strtolower($index) === strtolower($key)) {
return $value->getValue();
}
}
}
return $defaultValue;
return null;
}
/**
@@ -4,7 +4,6 @@ namespace Pecee\Http\Middleware;
use Pecee\CsrfToken;
use Pecee\Exception\TokenMismatchException;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
class BaseCsrfVerifier implements IMiddleware {
@@ -50,11 +49,11 @@ class BaseCsrfVerifier implements IMiddleware {
return false;
}
public function handle(Request $request, RouterEntry &$route = null) {
public function handle(Request $request) {
if($request->getMethod() !== 'get' && !$this->skip($request)) {
if($request->getMethod() != 'get' && !$this->skip($request)) {
$token = $request->getInput()->post->getValue(static::POST_KEY);
$token = (isset($_POST[static::POST_KEY])) ? $_POST[static::POST_KEY] : null;
// If the token is not posted, check headers for valid x-csrf-token
if($token === null) {
+1 -9
View File
@@ -2,15 +2,7 @@
namespace Pecee\Http\Middleware;
use Pecee\Http\Request;
use Pecee\SimpleRouter\RouterEntry;
interface IMiddleware {
/**
* @param Request $request
* @param RouterEntry $route
* @return Request|null
*/
public function handle(Request $request, RouterEntry &$route);
public function handle(Request $request);
}
+70 -73
View File
@@ -5,41 +5,45 @@ use Pecee\Http\Input\Input;
class Request {
protected $data = array();
protected $headers;
protected $host;
protected $uri;
protected $method;
protected $input;
protected static $instance;
protected $data;
/**
* Return new instance
* @return static
*/
public static function getInstance() {
if(self::$instance === null) {
self::$instance = new static();
}
return self::$instance;
}
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')));
$this->data = array();
$this->host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : array();
$this->uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : array();
$this->method = (isset($_POST['_method'])) ? strtolower($_POST['_method']) : (isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : array());
$this->headers = $this->getAllHeaders();
$this->input = new Input();
}
protected function parseHeaders() {
$this->headers = array();
protected function getAllHeaders() {
$headers = array();
foreach ($_SERVER as $name => $value) {
$this->headers[strtolower($name)] = $value;
if (substr($name, 0, 5) === 'HTTP_') {
$headers[strtolower(str_replace('_', '-', substr($name, 5)))] = $value;
}
}
return $headers;
}
public function isSecure() {
if($this->getHeader('http_x_forwarded_proto') === 'https') {
public function getIsSecure() {
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https') {
return true;
}
if($this->getHeader('https') !== null) {
return true;
}
return ($this->getHeader('server_port') === 443);
return isset($_SERVER['HTTPS']) ? true : (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] === 443);
}
/**
@@ -68,7 +72,7 @@ class Request {
* @return string|null
*/
public function getUser() {
return $this->getHeader('php_auth_user');
return (isset($_SERVER['PHP_AUTH_USER'])) ? $_SERVER['PHP_AUTH_USER']: null;
}
/**
@@ -76,11 +80,11 @@ class Request {
* @return string|null
*/
public function getPassword() {
return $this->getHeader('php_auth_pw');
return (isset($_SERVER['PHP_AUTH_PW'])) ? $_SERVER['PHP_AUTH_PW']: null;
}
/**
* Get all headers
* Get headers
* @return array
*/
public function getHeaders() {
@@ -92,15 +96,7 @@ class Request {
* @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');
return ((isset($_SERVER['HTTP_X_FORWARDED_FOR']) && strlen($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']);
}
/**
@@ -108,7 +104,7 @@ class Request {
* @return string
*/
public function getReferer() {
return $this->getHeader('http_referer');
return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
}
/**
@@ -116,17 +112,16 @@ class Request {
* @return string
*/
public function getUserAgent() {
return $this->getHeader('http_user_agent');
return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['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;
public function getHeader($name) {
return (isset($this->headers[strtolower($name)])) ? $this->headers[strtolower($name)] : null;
}
/**
@@ -137,42 +132,15 @@ class Request {
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);
return (isset($_SERVER['HTTP_ACCEPT']) && stripos($_SERVER['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;
if(isset($_SERVER['HTTP_ACCEPT'])) {
return explode(',', $_SERVER['HTTP_ACCEPT']);
}
return array();
}
public function __set($name, $value = null) {
@@ -183,4 +151,33 @@ class Request {
return isset($this->data[$name]) ? $this->data[$name] : null;
}
/**
* Get the currently loaded route.
* @return \Pecee\SimpleRouter\RouterEntry
*/
public function getLoadedRoute() {
return $this->loadedRoute;
}
/**
* @param mixed $uri
*/
public function setUri($uri) {
$this->uri = $uri;
}
/**
* @param mixed $host
*/
public function setHost($host) {
$this->host = $host;
}
/**
* @param mixed $method
*/
public function setMethod($method) {
$this->method = $method;
}
}
+5 -11
View File
@@ -4,17 +4,11 @@ namespace Pecee\Http;
class Response {
protected $request;
public function __construct(Request $request) {
$this->request = $request;
}
/**
* Set the http status code
*
* @param int $code
* @return static
* @return self $this
*/
public function httpCode($code) {
http_response_code($code);
@@ -37,13 +31,13 @@ class Response {
}
public function refresh() {
$this->redirect($this->request->getUri());
$this->redirect(Request::getInstance()->getUri());
}
/**
* Add http authorisation
* @param string $name
* @return static
* @return self $this
*/
public function auth($name = '') {
$this->headers([
@@ -87,7 +81,7 @@ class Response {
/**
* Add header to response
* @param string $value
* @return static
* @return self $this
*/
public function header($value) {
header($value);
@@ -97,7 +91,7 @@ class Response {
/**
* Add multiple headers to response
* @param array $headers
* @return static
* @return self $this
*/
public function headers(array $headers) {
foreach($headers as $header) {
@@ -1,11 +0,0 @@
<?php
namespace Pecee\SimpleRouter;
interface IControllerRoute {
public function getController();
public function setController($controller);
public function getMethod();
public function setMethod($method);
}
@@ -1,9 +0,0 @@
<?php
namespace Pecee\SimpleRouter;
interface ILoadableRoute {
public function getUrl();
public function setUrl($url);
}
-84
View File
@@ -1,84 +0,0 @@
<?php
namespace Pecee\SimpleRouter;
abstract class LoadableRoute extends RouterEntry implements ILoadableRoute {
const PARAMETERS_REGEX_MATCH = '{([A-Za-z\-\_]*?)\?{0,1}}';
protected $url;
protected $alias;
public function getUrl() {
return $this->url;
}
/**
* Set url
*
* @param string $url
* @return static
*/
public function setUrl($url) {
$this->url = '/' . trim($url, '/') . '/';
if(preg_match_all('/' . static::PARAMETERS_REGEX_MATCH . '/is', $this->url, $matches)) {
if (count($matches[1])) {
foreach ($matches[1] as $key) {
$this->parameters[$key] = null;
}
}
}
return $this;
}
/**
* Get alias for the url which can be used when getting the url route.
* @return string|array
*/
public function getAlias(){
return $this->alias;
}
/**
* Check if route has given alias.
*
* @param string $name
* @return bool
*/
public function hasAlias($name) {
if ($this->getAlias() !== null) {
if (is_array($this->getAlias())) {
foreach ($this->getAlias() as $alias) {
if (strtolower($alias) === strtolower($name)) {
return true;
}
}
}
return strtolower($this->getAlias()) === strtolower($name);
}
return false;
}
/**
* Set the url alias for easier getting the url route.
* @param string|array $alias
* @return static
*/
public function setAlias($alias){
$this->alias = $alias;
return $this;
}
public function setData(array $settings) {
// Change as to alias
if(isset($settings['as'])) {
$this->setAlias($settings['as']);
}
return parent::setData($settings);
}
}
+178 -249
View File
@@ -5,139 +5,59 @@ use Pecee\Exception\RouterException;
use Pecee\Handler\IExceptionHandler;
use Pecee\Http\Middleware\BaseCsrfVerifier;
use Pecee\Http\Request;
use Pecee\Http\Response;
class RouterBase {
protected static $instance;
/**
* Current request
* @var Request
*/
protected $request;
/**
* Response
* @var Response
*/
protected $response;
/**
* Used to keep track of whether or not a should should be added to
* the backstack-list for group-processing or not.
* @var bool
*/
protected $processingRoute;
/**
* All added routes
* @var array
*/
protected $currentRoute;
protected $routes;
/**
* List of
* @var array
*/
protected $processedRoutes;
protected $controllerUrlMap;
/**
* Backstack array used to keep track of sub-routes
* @var array
*/
protected $backStack;
/**
* The default namespace that all routes will inherit
* @var string
*/
protected $defaultNamespace;
/**
* List of added bootmanagers
* @var array
*/
protected $bootManagers;
/**
* Csrf verifier class
* @var BaseCsrfVerifier
*/
protected $csrfVerifier;
/**
* Get exception handlers
* @var array
*/
protected $baseCsrfVerifier;
protected $exceptionHandlers;
/**
* The current loaded route
* @var RouterRoute|null
*/
protected $loadedRoute;
/**
* List over route changes (to avoid endless-looping)
* @var array
*/
protected $routeRewrites = array();
protected $originalUrl;
// TODO: clean up - cut some of the methods down to smaller pieces
public function __construct() {
$this->reset();
}
public function reset() {
$this->processingRoute = false;
$this->request = new Request();
$this->response = new Response($this->request);
$this->request = Request::getInstance();
$this->routes = array();
$this->bootManagers = array();
$this->backStack = array();
$this->controllerUrlMap = array();
$this->bootManagers = array();
$this->exceptionHandlers = array();
}
/**
* Add route
* @param RouterEntry $route
* @return RouterEntry
*/
public function addRoute(RouterEntry $route) {
if($this->processingRoute) {
if($this->currentRoute !== null) {
$this->backStack[] = $route;
} else {
$this->routes[] = $route;
}
return $route;
}
protected function processRoutes(array $routes, array $settings = array(), array $prefixes = array(), RouterEntry $parent = null) {
protected function processRoutes(array $routes, array $settings = array(), array $prefixes = array(), $backStack = false, $group = null) {
// Loop through each route-request
$routesCount = count($routes);
$mergedSettings = array();
/* @var $route RouterEntry */
for($i = 0; $i < count($routes); $i++) {
for($i = 0; $i < $routesCount; $i++) {
$route = $routes[$i];
$route->setData($settings);
$route->addSettings($settings);
if($parent !== null) {
if($parent instanceof RouterGroup) {
if ($parent->getPrefix() !== null && trim($parent->getPrefix(), '/') !== '') {
$prefixes[] = trim($parent->getPrefix(), '/');
}
}
$route->setParent($parent);
if($backStack) {
$route->setGroup($group);
}
if($route->getNamespace() === null && $this->defaultNamespace !== null) {
if($this->defaultNamespace && !$route->getNamespace()) {
$namespace = $this->defaultNamespace;
if ($route->getNamespace()) {
$namespace .= '\\' . $route->getNamespace();
@@ -146,142 +66,143 @@ class RouterBase {
$route->setNamespace($namespace);
}
if($route instanceof ILoadableRoute) {
$newPrefixes = $prefixes;
$route->setUrl( trim(join('/', $prefixes) . $route->getUrl(), '/') );
if($route->getPrefix() && trim($route->getPrefix(), '/') !== '') {
array_push($newPrefixes, trim($route->getPrefix(), '/'));
}
if(!($route instanceof RouterGroup)) {
if(is_array($newPrefixes) && count($newPrefixes) && $backStack) {
$route->setUrl( '/' . join('/', $newPrefixes) . $route->getUrl() );
}
$group = null;
$this->controllerUrlMap[] = $route;
} elseif($route instanceof RouterGroup) {
}
if ($route->getCallback() !== null && is_callable($route->getCallback())) {
$this->processingRoute = true;
$route->renderRoute($this->request);
$this->processingRoute = false;
$this->currentRoute = $route;
if ($route->matchRoute($this->request)) {
if($route instanceof RouterGroup && is_callable($route->getCallback())) {
$group = $route;
$settings = array_merge($settings, $route->getMergeableData());
// Add ExceptionHandler
if (count($route->getExceptionHandlers())) {
$this->exceptionHandlers = array_merge($route->getExceptionHandlers(), $this->exceptionHandlers);
}
}
$route->renderRoute($this->request);
$mergedSettings = array_merge($settings, $route->getMergeableSettings());
// Add ExceptionHandler
if($route->matchRoute($this->request) && $route->getExceptionHandler() !== null) {
$this->exceptionHandlers[] = $route;
}
}
$this->currentRoute = null;
if(count($this->backStack)) {
$backStack = $this->backStack;
$this->backStack = array();
// Route any routes added to the backstack
$this->processRoutes($backStack, $settings, $prefixes, $route);
$this->processRoutes($backStack, $mergedSettings, $newPrefixes, true, $group);
}
$prefixes = [];
}
}
public function routeRequest($rewrite = false) {
public function routeRequest() {
$originalUri = $this->request->getUri();
// Initialize boot-managers
if(count($this->bootManagers)) {
/* @var $manager RouterBootManager */
foreach($this->bootManagers as $manager) {
$this->request = $manager->boot($this->request);
if(!($this->request instanceof Request)) {
throw new RouterException('Custom router bootmanager "'. get_class($manager) .'" must return instance of Request.');
}
}
}
// Verify csrf token for request
if($this->baseCsrfVerifier !== null) {
$this->baseCsrfVerifier->handle($this->request);
}
// Loop through each route-request
$this->processRoutes($this->routes);
// Make sure routes with longer urls are rendered first
usort($this->controllerUrlMap, function($a, $b) {
if(strlen($a->getUrl()) < strlen($b->getUrl())) {
return 1;
}
return -1;
});
$this->loadedRoute = null;
$routeNotAllowed = false;
try {
$max = count($this->controllerUrlMap);
// Initialize boot-managers
if(count($this->bootManagers)) {
/* @var $manager RouterBootManager */
foreach($this->bootManagers as $manager) {
$this->request = $manager->boot($this->request);
/* @var $route RouterEntry */
for($i = 0; $i < $max; $i++) {
if(!($this->request instanceof Request)) {
throw new RouterException('Custom router bootmanager "'. get_class($manager) .'" must return instance of Request.');
}
}
}
$route = $this->controllerUrlMap[$i];
if($rewrite === false) {
$routeMatch = $route->matchRoute($this->request);
// Loop through each route-request
$this->processRoutes($this->routes);
if($routeMatch) {
if($this->csrfVerifier !== null) {
// Verify csrf token for request
$this->csrfVerifier->handle($this->request);
if(count($route->getRequestMethods()) && !in_array($this->request->getMethod(), $route->getRequestMethods())) {
$routeNotAllowed = true;
continue;
}
$this->originalUrl = $this->request->getUri();
}
$routeNotAllowed = false;
/* @var $route RouterEntry */
for ($i = 0; $i < count($this->controllerUrlMap); $i++) {
$this->request->rewrite_uri = $this->request->uri;
$this->request->setUri($originalUri);
$route = $this->controllerUrlMap[$i];
$this->request->loadedRoute = $route;
$route->loadMiddleware($this->request);
if ($route->matchRoute($this->request)) {
if (count($route->getRequestMethods()) && !in_array($this->request->getMethod(), $route->getRequestMethods())) {
$routeNotAllowed = true;
continue;
}
$this->loadedRoute = $route;
$this->loadedRoute->loadMiddleware($this->request, $this->loadedRoute);
if($this->request->getUri() !== $this->originalUrl && !in_array($this->request->getUri(), $this->routeRewrites)) {
$this->routeRewrites[] = $this->request->getUri();
$this->routeRequest(true);
return;
}
$routeNotAllowed = false;
$this->request->setUri($this->originalUrl);
$this->loadedRoute->renderRoute($this->request);
break;
try {
$this->request->loadedRoute->renderRoute($this->request);
} catch(\Exception $e) {
$this->handleException($e);
}
}
} catch(\Exception $e) {
$this->handleException($e);
break;
}
}
if($routeNotAllowed) {
$this->handleException(new RouterException('Route or method not allowed', 403));
}
if($this->loadedRoute === null) {
if(!$this->request->loadedRoute) {
$this->handleException(new RouterException(sprintf('Route not found: %s', $this->request->getUri()), 404));
}
}
protected function handleException(\Exception $e) {
/* @var $handler IExceptionHandler */
foreach ($this->exceptionHandlers as $handler) {
/* @var $route RouterEntry */
foreach ($this->exceptionHandlers as $route) {
$route->loadMiddleware($this->request);
$handler = $route->getExceptionHandler();
$handler = new $handler();
if (!($handler instanceof IExceptionHandler)) {
throw new RouterException('Exception handler must implement the IExceptionHandler interface.');
}
$request = $handler->handleError($this->request, $this->loadedRoute, $e);
if($request !== null && $request->getUri() !== $this->originalUrl && !in_array($request->getUri(), $this->routeRewrites)) {
$this->routeRewrites[] = $request->getUri();
$this->routeRequest(true);
return;
}
$handler->handleError($this->request, $this->request->loadedRoute, $e);
}
throw $e;
}
/**
* Get default namespace
* @return string
*/
public function getDefaultNamespace(){
@@ -289,7 +210,6 @@ class RouterBase {
}
/**
* Set the main default namespace that all routes will inherit
* @param string $defaultNamespace
* @return static
*/
@@ -299,7 +219,6 @@ class RouterBase {
}
/**
* Get bootmanagers
* @return array
*/
public function getBootManagers() {
@@ -307,21 +226,40 @@ class RouterBase {
}
/**
* Set bootmanagers
* @param array $bootManagers
*/
public function setBootManagers(array $bootManagers) {
$this->bootManagers = $bootManagers;
}
/**
* Add bootmanager
* @param RouterBootManager $bootManager
*/
public function addBootManager(RouterBootManager $bootManager) {
$this->bootManagers[] = $bootManager;
}
/**
* @return RouterEntry
*/
public function getLoadedRoute() {
if(!($this->request->loadedRoute instanceof RouterGroup)) {
return $this->request->loadedRoute;
}
return null;
}
/**
* @return array
*/
public function getBackstack() {
return $this->backStack;
}
/**
* @return RouterEntry
*/
public function getCurrentRoute(){
return $this->currentRoute;
}
/**
* @return array
*/
@@ -339,44 +277,37 @@ class RouterBase {
}
/**
* Get response
* @return Response
*/
public function getResponse() {
return $this->response;
}
/**
* Get csrf verifier class
* Get base csrf verifier class
* @return BaseCsrfVerifier
*/
public function getCsrfVerifier() {
return $this->csrfVerifier;
public function getBaseCsrfVerifier() {
return $this->baseCsrfVerifier;
}
/**
* Set csrf verifier class
* Set base csrf verifier class
*
* @param BaseCsrfVerifier $csrfVerifier
* @return static
* @param BaseCsrfVerifier $baseCsrfVerifier
* @return self
*/
public function setCsrfVerifier(BaseCsrfVerifier $csrfVerifier) {
$this->csrfVerifier = $csrfVerifier;
public function setBaseCsrfVerifier(BaseCsrfVerifier $baseCsrfVerifier) {
$this->baseCsrfVerifier = $baseCsrfVerifier;
return $this;
}
public function arrayToParams(array $getParams = null, $includeEmpty = true) {
if(is_array($getParams) && count($getParams)) {
if(is_array($getParams)) {
if ($includeEmpty === false) {
$getParams = array_filter($getParams, function ($item) {
return (!empty($item));
if (!empty($item)) {
return $item;
}
});
}
return '?' . http_build_query($getParams);
return http_build_query($getParams);
}
return '';
}
@@ -384,31 +315,38 @@ class RouterBase {
$domain = '';
$parent = $route->getParent();
if($route->getGroup() !== null && $route->getGroup()->getDomain() !== null) {
if(is_array($route->getGroup()->getDomain())) {
$domains = $route->getGroup()->getDomain();
$domain = array_shift($domains);
} else {
$domain = $route->getGroup()->getDomain();
}
if($parent !== null && $parent instanceof RouterGroup && count($parent->getDomains())) {
$domain = $parent->getDomains();
$domain = '//' . $domain[0];
$domain = '//' . $domain;
}
$url = $domain . '/' . trim($route->getUrl(), '/');
if($route instanceof IControllerRoute && $method !== null) {
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 {
if($parameters !== null && is_array($parameters)) {
/* @var $route RouterEntry */
if(is_array($parameters)) {
$params = array_merge($route->getParameters(), $parameters);
} else {
$params = $route->getParameters();
}
$otherParams = array();
$i = 0;
$otherParams = [];
$i = 0;
foreach($params as $param => $value) {
$value = (isset($parameters[$param])) ? $parameters[$param] : $value;
if(stripos($url, '{' . $param. '}') !== false || stripos($url, '{' . $param . '?}') !== false) {
@@ -424,8 +362,8 @@ class RouterBase {
$url = rtrim($url, '/') . '/';
if($getParams !== null) {
$url .= $this->arrayToParams($getParams);
if($getParams !== null && count($getParams)) {
$url .= '?' . $this->arrayToParams($getParams);
}
return $url;
@@ -443,23 +381,24 @@ class RouterBase {
// Return current route if no options has been specified
if($controller === null && $parameters === null) {
$getParams = ($getParams !== null && is_array($getParams)) ? array_merge($_GET, $getParams) : $_GET;
$getParams = (is_array($getParams)) ? array_merge($_GET, $getParams) : $_GET;
$url = parse_url($this->request->getUri(), PHP_URL_PATH);
if($getParams !== null) {
$url .= $this->arrayToParams($getParams);
if(count($getParams)) {
$url .= '?' . $this->arrayToParams($getParams);
}
return $url;
}
if($controller === null && $this->loadedRoute !== null) {
return $this->processUrl($this->loadedRoute, $this->loadedRoute->getMethod(), $parameters, $getParams);
if($controller === null && $this->request->loadedRoute !== null) {
return $this->processUrl($this->request->loadedRoute, $this->request->loadedRoute->getMethod(), $parameters, $getParams);
}
$c = '';
$method = null;
$max = count($this->controllerUrlMap);
/* @var $route RouterRoute */
@@ -468,25 +407,14 @@ class RouterBase {
$route = $this->controllerUrlMap[$i];
// Check an alias exist, if the matches - use it
if($route instanceof LoadableRoute) {
// Check for alias
if ($route->hasAlias($controller)) {
return $this->processUrl($route, $route->getMethod(), $parameters, $getParams);
}
// Use controller name
if($route instanceof RouterController) {
$c = $route->getController();
} else {
// Use callback if it's not a function
if (stripos($route->getCallback(), '@') !== false && !is_callable($route->getCallback())) {
$c = $route->getCallback();
}
}
if($route instanceof RouterRoute && $route->hasAlias($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) {
@@ -501,10 +429,10 @@ class RouterBase {
$route = $this->controllerUrlMap[$i];
if($route instanceof IControllerRoute) {
$c = $route->getController();
} else if(!is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) {
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) {
@@ -521,29 +449,30 @@ class RouterBase {
$controller = ($controller === null) ? '/' : $controller;
$url = array($controller);
if($parameters !== null && is_array($parameters) && count($parameters)) {
$url = array_merge($url, $parameters);
if(is_array($parameters)) {
foreach($parameters as $key => $value) {
array_push($url,$value);
}
}
$url = '/' . trim(join('/', $url), '/') . '/';
if($getParams !== null) {
$url .= $this->arrayToParams($getParams);
if($getParams !== null && count($getParams)) {
$url .= '?' . $this->arrayToParams($getParams);
}
return $url;
}
/**
* Get current router instance
* @return static
*/
public static function getInstance() {
if(static::$instance === null) {
static::$instance = new static();
if(self::$instance === null) {
self::$instance = new static();
}
return self::$instance;
}
return static::$instance;
public static function reset() {
self::$instance = null;
}
}
+25 -6
View File
@@ -4,20 +4,22 @@ namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException;
use Pecee\Http\Request;
class RouterController extends LoadableRoute implements IControllerRoute {
class RouterController extends RouterEntry {
const DEFAULT_METHOD = 'index';
protected $url;
protected $controller;
protected $method;
public function __construct($url, $controller) {
$this->setUrl($url);
parent::__construct();
$this->url = $url;
$this->controller = $controller;
}
public function renderRoute(Request $request) {
if($this->getCallback() !== null && is_callable($this->getCallback())) {
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
// When the callback is a function
call_user_func_array($this->getCallback(), $this->getParameters());
@@ -42,8 +44,8 @@ class RouterController extends LoadableRoute implements IControllerRoute {
}
public function matchRoute(Request $request) {
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$url = parse_url(urldecode($request->getUri()));
$url = rtrim($url['path'], '/') . '/';
if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
@@ -53,7 +55,7 @@ class RouterController extends LoadableRoute implements IControllerRoute {
if(count($path)) {
$method = (!isset($path[0]) || trim($path[0]) === '') ? static::DEFAULT_METHOD : $path[0];
$method = (!isset($path[0]) || trim($path[0]) === '') ? self::DEFAULT_METHOD : $path[0];
$this->method = $method;
array_shift($path);
@@ -68,6 +70,23 @@ class RouterController extends LoadableRoute implements IControllerRoute {
return null;
}
/**
* @return string
*/
public function getUrl() {
return $this->url;
}
/**
* @param string $url
* @return static
*/
public function setUrl($url) {
$url = rtrim($url, '/') . '/';
$this->url = $url;
return $this;
}
/**
* @return string
*/
+267 -233
View File
@@ -8,206 +8,47 @@ use Pecee\Http\Request;
abstract class RouterEntry {
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_POST = 'post';
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_PUT = 'put';
const REQUEST_TYPE_PATCH = 'patch';
const REQUEST_TYPE_OPTIONS = 'options';
const REQUEST_TYPE_DELETE = 'delete';
public static $allowedRequestTypes = [
public static $allowedRequestTypes = array(
self::REQUEST_TYPE_DELETE,
self::REQUEST_TYPE_GET,
self::REQUEST_TYPE_POST,
self::REQUEST_TYPE_PUT,
self::REQUEST_TYPE_PATCH,
self::REQUEST_TYPE_OPTIONS,
self::REQUEST_TYPE_DELETE,
];
self::REQUEST_TYPE_PATCH
);
protected $parent;
protected $settings;
protected $callback;
protected $namespace;
protected $regex;
protected $requestMethods = array();
protected $where = array();
protected $parameters = array();
protected $middlewares = array();
protected function loadClass($name) {
if(!class_exists($name)) {
throw new RouterException(sprintf('Class %s does not exist', $name));
}
return new $name();
}
protected function parseParameters($route, $url, $parameterRegex = '[\w]+') {
$parameterNames = array();
$regex = '';
$lastCharacter = '';
$isParameter = false;
$parameter = '';
$routeLength = strlen($route);
for($i = 0; $i < $routeLength; $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
// Use custom parameter regex if it exists
if(is_array($this->where) && 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 = array();
if(preg_match('/^'.$regex.'\/?$/is', $url, $parameterValues)) {
$parameters = array();
$max = count($parameterNames);
for($i = 0; $i < $max; $i++) {
$name = $parameterNames[$i];
$parameterValue = isset($parameterValues[$name['name']]) ? $parameterValues[$name['name']] : null;
if($name['required'] && $parameterValue === null) {
throw new RouterException('Missing required parameter ' . $name['name'], 404);
}
if(!$name['required'] && $parameterValue === null) {
continue;
}
$parameters[$name['name']] = $parameterValue;
}
return $parameters;
}
return null;
}
public function loadMiddleware(Request $request, RouterEntry &$route) {
if(count($this->getMiddlewares())) {
foreach($this->getMiddlewares() as $middleware) {
$middleware = $this->loadClass($middleware);
if (!($middleware instanceof IMiddleware)) {
throw new RouterException($middleware . ' must be instance of Middleware');
}
/* @var $class IMiddleware */
$middleware->handle($request, $route);
}
}
}
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 RouterException(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(array($class, $method), $parameters);
return $class;
}
return null;
public function __construct() {
$this->settings = array();
$this->settings['requestMethods'] = array();
$this->settings['where'] = array();
$this->settings['parameters'] = array();
}
/**
* Set allowed request methods
* 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.
*
* @param array $methods
* @return static $this
* @return string
*/
public function setRequestMethods(array $methods) {
$this->requestMethods = $methods;
return $this;
}
/**
* Get allowed request methods
*
* @return array
*/
public function getRequestMethods() {
return $this->requestMethods;
}
/**
* @return RouterEntry
*/
public function getParent() {
return $this->parent;
}
/**
* Set parent route
* @param RouterEntry $parent
* @return static $this
*/
public function setParent(RouterEntry $parent) {
$this->parent = $parent;
return $this;
public function getIdentifier() {
if(strpos($this->callback, '@') !== false) {
return $this->callback;
}
return 'function_' . md5($this->callback);
}
/**
* @param string $callback
* @return static
* @return self;
*/
public function setCallback($callback) {
$this->callback = $callback;
@@ -248,33 +89,44 @@ abstract class RouterEntry {
}
/**
* @param string $middleware
* @return static
* @param string $prefix
* @return self
*/
public function setMiddleware($middleware) {
$this->middlewares[] = $middleware;
public function setPrefix($prefix) {
$this->prefix = '/' . ltrim($prefix, '/');
return $this;
}
public function setMiddlewares(array $middlewares) {
$this->middlewares = $middlewares;
/**
* @param string $middleware
* @return self
*/
public function setMiddleware($middleware) {
$this->middleware = $middleware;
return $this;
}
/**
* @param string $namespace
* @return static
* @return self
*/
public function setNamespace($namespace) {
$this->namespace = $namespace;
return $this;
}
/**
* @return string
*/
public function getPrefix() {
return $this->prefix;
}
/**
* @return string|array
*/
public function getMiddlewares() {
return $this->middlewares;
public function getMiddleware() {
return $this->middleware;
}
/**
@@ -287,13 +139,20 @@ abstract class RouterEntry {
/**
* @return array
*/
public function getSettings() {
return $this->settings;
}
/**
* @return mixed
*/
public function getParameters(){
return $this->parameters;
return ($this->parameters === null) ? array() : $this->parameters;
}
/**
* @param mixed $parameters
* @return static
* @return self
*/
public function setParameters($parameters) {
$this->parameters = $parameters;
@@ -304,10 +163,10 @@ abstract class RouterEntry {
* Add regular expression parameter match
*
* @param array $options
* @return static
* @return self
*/
public function where(array $options) {
$this->where = $options;
$this->where = array_merge($this->where, $options);
return $this;
}
@@ -315,74 +174,249 @@ abstract class RouterEntry {
* Add regular expression match for url
*
* @param string $regex
* @return static
* @return self
*/
public function match($regex) {
$this->regex = $regex;
$this->regexMatch = $regex;
return $this;
}
/**
* Get arguments that can be inherited by child routes.
* Get settings that are allowed to be inherited by child routes.
*
* @return array
*/
public function getMergeableData() {
public function getMergeableSettings() {
$settings = $this->settings;
$output = array();
if($this->namespace !== null) {
$output['namespace'] = $this->namespace;
if(isset($settings['prefix'])) {
unset($settings['prefix']);
}
if(count($this->middlewares)) {
$output['middleware'] = $this->middlewares;
}
if(count($this->where)) {
$output['where'] = $this->where;
}
if(count($this->requestMethods)) {
$output['method'] = $this->requestMethods;
}
if(count($this->parameters)) {
$output['parameters'] = $this->parameters;
}
return $output;
return $settings;
}
/**
* Set arguments/data by array
*
* @param array $settings
* @return static
* @return self
*/
public function setData(array $settings) {
public function addSettings(array $settings = null) {
if(is_array($settings)) {
$this->settings = array_merge($this->settings, $settings);
}
return $this;
}
if (isset($settings['namespace']) && $this->namespace === null) {
$this->setNamespace($settings['namespace']);
/**
* @param array $settings
* @return self
*/
public function setSettings($settings) {
$this->settings = $settings;
if(isset($settings['prefix'])) {
$this->setPrefix($settings['prefix']);
}
// Push middleware if multiple
if (isset($settings['middleware'])) {
$this->middlewares = array_merge((array)$settings['middleware'], $this->middlewares);
return $this;
}
/**
* Dynamically 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));
}
if(isset($settings['method'])) {
$this->setRequestMethods((array)$settings['method']);
return new $name();
}
protected function parseParameters($route, $url, $parameterRegex = '[\w]+') {
$parameterNames = array();
$regex = '';
$lastCharacter = '';
$isParameter = false;
$parameter = '';
$routeLength = strlen($route);
for($i = 0; $i < $routeLength; $i++) {
$character = $route[$i];
// Skip "/" if we are at the end of a parameter
if($lastCharacter === '}' && $character === '/') {
$lastCharacter = $character;
continue;
}
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
// Use custom parameter regex if it exists
if(is_array($this->where) && isset($this->where[$parameter])) {
$parameterRegex = $this->where[$parameter];
}
if($lastCharacter === '?') {
$parameter = substr($parameter, 0, strlen($parameter)-1);
$regex .= '(?:\\/?(?P<'.$parameter.'>[^\/]+)?\\/?)';
$required = false;
} else {
$regex .= '.*?(?P<' . $parameter . '>'. $parameterRegex .').*?';
}
$parameterNames[] = array('name' => $parameter, 'required' => $required);
$parameter = '';
$isParameter = false;
} elseif($isParameter) {
$parameter .= $character;
} elseif($character === '/') {
$regex .= '\\' . $character;
} else {
$regex .= str_replace('.', '\\.', $character);
}
$lastCharacter = $character;
}
if(isset($settings['where'])) {
$this->where($settings['where']);
$parameterValues = array();
if(preg_match('/^'.$regex.'.?$/is', $url, $parameterValues)) {
$parameters = array();
$max = count($parameterNames);
if($max) {
for($i = 0; $i < $max; $i++) {
$name = $parameterNames[$i];
$parameterValue = (isset($parameterValues[$name['name']]) && !empty($parameterValues[$name['name']])) ? $parameterValues[$name['name']] : null;
if($name['required'] && $parameterValue === null) {
throw new RouterException('Missing required parameter ' . $name['name'], 404);
}
if(!$name['required'] && $parameterValue === null) {
continue;
}
$parameters[$name['name']] = $parameterValue;
}
}
return $parameters;
}
if(isset($settings['parameters'])) {
$this->setParameters($settings['parameters']);
return null;
}
public function loadMiddleware(Request $request) {
if($this->getMiddleware()) {
if(is_array($this->getMiddleware())) {
foreach($this->getMiddleware() as $middleware) {
$middleware = $this->loadClass($middleware);
if (!($middleware instanceof IMiddleware)) {
throw new RouterException($middleware . ' must be instance of Middleware');
}
/* @var $class IMiddleware */
$middleware->handle($request);
}
} else {
$middleware = $this->loadClass($this->getMiddleware());
if (!($middleware instanceof IMiddleware)) {
throw new RouterException($this->getMiddleware() . ' must be instance of Middleware');
}
/* @var $class IMiddleware */
$middleware->handle($request);
}
}
}
public function renderRoute(Request $request) {
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
// When the callback is a function
call_user_func_array($this->getCallback(), $this->getParameters());
} else {
// When the callback is a method
$controller = explode('@', $this->getCallback());
$className = $this->getNamespace() . '\\' . $controller[0];
$class = $this->loadClass($className);
$method = $controller[1];
if (!method_exists($class, $method)) {
throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
}
$parameters = array_filter($this->getParameters(), function($var){
return !is_null($var);
});
call_user_func_array(array($class, $method), $parameters);
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'];
}
public function getGroup() {
return $this->group;
}
public function setGroup($group) {
$this->group = $group;
return $this;
}
+61 -52
View File
@@ -2,25 +2,37 @@
namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException;
use Pecee\Http\Request;
class RouterGroup extends RouterEntry {
protected $prefix;
protected $domains = array();
protected $exceptionHandlers = array();
public function matchDomain(Request $request) {
if(count($this->domains)) {
for($i = 0; $i < count($this->domains); $i++) {
$domain = $this->domains[$i];
if($this->domain !== null) {
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
if(is_array($this->domain)) {
if($parameters !== null) {
$this->parameters = $parameters;
return true;
$max = count($this->domain);
for($i = 0; $i < $max; $i++) {
$domain = $this->domain[$i];
$parameters = $this->parseParameters($domain, $request->getHost(), '[^.]*');
if($parameters !== null) {
$this->parameters = $parameters;
return true;
}
}
return false;
}
$parameters = $this->parseParameters($this->domain, $request->getHost(), '[^.]*');
if ($parameters !== null) {
$this->parameters = $parameters;
return true;
}
return false;
@@ -29,65 +41,62 @@ class RouterGroup extends RouterEntry {
return true;
}
public function renderRoute(Request $request) {
// Check if request method is allowed
$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');
}
$this->matchDomain($request);
return parent::renderRoute($request);
}
public function matchRoute(Request $request) {
// Skip if prefix doesn't match
if($this->prefix !== null && stripos($request->getUri(), $this->prefix) === false) {
if($this->getPrefix() !== null && stripos($request->getUri(), $this->getPrefix()) === false) {
return false;
}
return $this->matchDomain($request);
}
public function setExceptionHandlers(array $handlers) {
$this->exceptionHandlers = $handlers;
public function setExceptionHandler($class) {
$this->exceptionHandler = $class;
return $this;
}
public function getExceptionHandlers() {
return $this->exceptionHandlers;
public function getExceptionHandler() {
return $this->exceptionHandler;
}
public function getDomains() {
return $this->domains;
}
public function setDomains(array $domains) {
$this->domains = $domains;
return $this;
public function getDomain() {
return $this->domain;
}
/**
* @param string $prefix
* @return static
* @param array $settings
* @return self
*/
public function setPrefix($prefix) {
$this->prefix = '/' . trim($prefix, '/');
public function addSettings(array $settings = null) {
if($this->getNamespace() !== null && isset($settings['namespace'])) {
unset($settings['namespace']);
}
if(is_array($settings)) {
$this->settings = array_merge($this->settings, $settings);
}
return $this;
}
/**
* @return string
*/
public function getPrefix() {
return $this->prefix;
}
public function setData(array $settings) {
if(isset($settings['prefix'])) {
$this->setPrefix($settings['prefix']);
}
if(isset($settings['exceptionHandler'])) {
$this->setExceptionHandlers((array)$settings['exceptionHandler']);
}
if(isset($settings['domain'])) {
$this->setDomains((array)$settings['domain']);
}
return parent::setData($settings);
}
}
+33 -12
View File
@@ -4,17 +4,21 @@ namespace Pecee\SimpleRouter;
use Pecee\Exception\RouterException;
use Pecee\Http\Request;
class RouterResource extends LoadableRoute implements IControllerRoute {
class RouterResource extends RouterEntry {
protected $url;
protected $controller;
protected $postMethod;
public function __construct($url, $controller) {
$this->setUrl($url);
parent::__construct();
$this->url = $url;
$this->controller = $controller;
$this->postMethod = strtolower(($_SERVER['REQUEST_METHOD'] != 'GET') ? 'post' : 'get');
}
public function renderRoute(Request $request) {
if($this->getCallback() !== null && is_callable($this->getCallback())) {
if(is_object($this->getCallback()) && is_callable($this->getCallback())) {
// When the callback is a function
call_user_func_array($this->getCallback(), $this->getParameters());
} else {
@@ -43,12 +47,12 @@ class RouterResource extends LoadableRoute implements IControllerRoute {
}
public function matchRoute(Request $request) {
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$url = parse_url(urldecode($request->getUri()));
$url = rtrim($url['path'], '/') . '/';
$route = rtrim($this->url, '/') . '/{id?}/{action?}';
$parameters = $this->parseParameters($route, $url);
$parameters = $this->parseParameters($route, $url, '[0-9]+?');
if($parameters !== null) {
@@ -60,32 +64,32 @@ class RouterResource extends LoadableRoute implements IControllerRoute {
unset($parameters['action']);
// Delete
if($request->getMethod() === static::REQUEST_TYPE_DELETE && $request->getMethod() === static::REQUEST_TYPE_POST) {
if($request->getMethod() === self::REQUEST_TYPE_DELETE && $this->postMethod === self::REQUEST_TYPE_POST) {
return $this->call('destroy', $parameters);
}
// Update
if(in_array($request->getMethod(), array(static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT)) && $request->getMethod() === static::REQUEST_TYPE_POST) {
if(in_array($request->getMethod(), array(self::REQUEST_TYPE_PATCH, self::REQUEST_TYPE_PUT)) && $this->postMethod === self::REQUEST_TYPE_POST) {
return $this->call('update', $parameters);
}
// Edit
if(isset($action) && strtolower($action) === 'edit' && $request->getMethod() === static::REQUEST_TYPE_GET) {
if(isset($action) && strtolower($action) === 'edit' && $this->postMethod === self::REQUEST_TYPE_GET) {
return $this->call('edit', $parameters);
}
// Create
if(strtolower($action) === 'create' && $request->getMethod() === static::REQUEST_TYPE_GET) {
if(strtolower($action) === 'create' && $request->getMethod() === self::REQUEST_TYPE_GET) {
return $this->call('create', $parameters);
}
// Save
if($request->getMethod() === static::REQUEST_TYPE_POST) {
if($this->postMethod === self::REQUEST_TYPE_POST) {
return $this->call('store', $parameters);
}
// Show
if(isset($parameters['id']) && $request->getMethod() === static::REQUEST_TYPE_GET) {
if(isset($parameters['id']) && $this->postMethod === self::REQUEST_TYPE_GET) {
return $this->call('show', $parameters);
}
@@ -96,6 +100,23 @@ class RouterResource extends LoadableRoute implements IControllerRoute {
return null;
}
/**
* @return string
*/
public function getUrl() {
return $this->url;
}
/**
* @param string $url
* @return static
*/
public function setUrl($url) {
$url = rtrim($url, '/') . '/';
$this->url = $url;
return $this;
}
/**
* @return string
*/
+96 -6
View File
@@ -4,22 +4,27 @@ namespace Pecee\SimpleRouter;
use Pecee\Http\Request;
class RouterRoute extends LoadableRoute {
class RouterRoute extends RouterEntry {
const PARAMETERS_REGEX_MATCH = '{([A-Za-z\-\_]*?)\?{0,1}}';
protected $url;
public function __construct($url, $callback) {
parent::__construct();
$this->setUrl($url);
$this->setCallback($callback);
}
public function matchRoute(Request $request) {
$url = parse_url(urldecode($request->getUri()), PHP_URL_PATH);
$url = rtrim($url, '/') . '/';
$url = parse_url(urldecode($request->getUri()));
$url = rtrim($url['path'], '/') . '/';
// Match on custom defined regular expression
if($this->regex !== null) {
if($this->regexMatch) {
$parameters = array();
if(preg_match('/(' . $this->regex . ')/is', $request->getHost() . $url, $parameters)) {
if(preg_match('/('.$this->regexMatch.')/is', $request->getHost() . $url, $parameters)) {
$this->parameters = (!is_array($parameters[0]) ? array($parameters[0]) : $parameters[0]);
return true;
}
@@ -32,11 +37,96 @@ class RouterRoute extends LoadableRoute {
$parameters = $this->parseParameters($route, $url);
if($parameters !== null) {
$this->parameters = array_merge($this->parameters, $parameters);
if(is_array($this->parameters)) {
$this->parameters = array_merge($this->parameters, $parameters);
} else {
$this->parameters = $parameters;
}
return true;
}
return null;
}
/**
* @return string
*/
public function getUrl() {
return $this->url;
}
/**
* @param string $url
* @return self
*/
public function setUrl($url) {
$parameters = array();
$matches = array();
if(preg_match_all('/'.self::PARAMETERS_REGEX_MATCH.'/is', $url, $matches)) {
$parameters = $matches[1];
}
if(count($parameters)) {
$tmp = array();
foreach($parameters as $param) {
$tmp[$param] = null;
}
$this->parameters = $tmp;
}
$this->url = $url;
return $this;
}
/**
* Get alias for the url which can be used when getting the url route.
* @return string|array
*/
public function getAlias(){
return $this->alias;
}
/**
* Check if route has given alias.
*
* @param $name
* @return bool
*/
public function hasAlias($name) {
if(is_array($this->alias)) {
foreach($this->alias as $alias) {
if(strtolower($alias) === strtolower($name)) {
return true;
}
}
} else {
return strtolower($this->getAlias()) === strtolower($name);
}
return false;
}
/**
* Set the url alias for easier getting the url route.
* @param string|array $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);
}
}
+16 -43
View File
@@ -15,18 +15,11 @@ class SimpleRouter {
/**
* Start/route request
* @param null $defaultNamespace
* @throws \Pecee\Exception\RouterException
*/
public static function start() {
RouterBase::getInstance()->routeRequest();
}
/**
* Set default namespace for all routes
* @param string $defaultNamespace
*/
public static function setDefaultNamespace($defaultNamespace) {
RouterBase::getInstance()->setDefaultNamespace($defaultNamespace);
public static function start($defaultNamespace = null) {
RouterBase::getInstance()->setDefaultNamespace($defaultNamespace)->routeRequest();
}
/**
@@ -34,7 +27,7 @@ class SimpleRouter {
* @param BaseCsrfVerifier $baseCsrfVerifier
*/
public static function csrfVerifier(BaseCsrfVerifier $baseCsrfVerifier) {
RouterBase::getInstance()->setCsrfVerifier($baseCsrfVerifier);
RouterBase::getInstance()->setBaseCsrfVerifier($baseCsrfVerifier);
}
public static function addBootManager(RouterBootManager $bootManager) {
@@ -42,27 +35,19 @@ class SimpleRouter {
}
public static function get($url, $callback, array $settings = null) {
return static::match(['get'], $url, $callback, $settings);
return self::match(['get'], $url, $callback, $settings);
}
public static function post($url, $callback, array $settings = null) {
return static::match(['post'], $url, $callback, $settings);
return self::match(['post'], $url, $callback, $settings);
}
public static function put($url, $callback, array $settings = null) {
return static::match(['put'], $url, $callback, $settings);
}
public static function patch($url, $callback, array $settings = null) {
return static::match(['patch'], $url, $callback, $settings);
}
public static function options($url, $callback, array $settings = null) {
return static::match(['options'], $url, $callback, $settings);
return self::match(['put'], $url, $callback, $settings);
}
public static function delete($url, $callback, array $settings = null) {
return static::match(['delete'], $url, $callback, $settings);
return self::match(['delete'], $url, $callback, $settings);
}
public static function group($settings = array(), $callback) {
@@ -70,7 +55,7 @@ class SimpleRouter {
$group->setCallback($callback);
if($settings !== null && is_array($settings)) {
$group->setData($settings);
$group->setSettings($settings);
}
RouterBase::getInstance()->addRoute($group);
@@ -87,7 +72,7 @@ class SimpleRouter {
* @return RouterRoute
*/
public static function basic($url, $callback, array $settings = null) {
return static::match(['get', 'post'], $url, $callback, $settings);
return self::match(['get', 'post'], $url, $callback, $settings);
}
public static function match(array $requestMethods, $url, $callback, array $settings = null) {
@@ -95,7 +80,7 @@ class SimpleRouter {
$route->setRequestMethods($requestMethods);
if($settings !== null) {
$route->setData($settings);
$route->addSettings($settings);
}
RouterBase::getInstance()->addRoute($route);
@@ -107,7 +92,7 @@ class SimpleRouter {
$route = new RouterRoute($url, $callback);
if($settings !== null) {
$route->setData($settings);
$route->addSettings($settings);
}
RouterBase::getInstance()->addRoute($route);
@@ -119,7 +104,7 @@ class SimpleRouter {
$route = new RouterController($url, $controller);
if($settings !== null) {
$route->setData($settings);
$route->addSettings($settings);
}
RouterBase::getInstance()->addRoute($route);
@@ -131,28 +116,16 @@ class SimpleRouter {
$route = new RouterResource($url, $controller);
if($settings !== null) {
$route->setData($settings);
$route->addSettings($settings);
}
static::router()->addRoute($route);
RouterBase::getInstance()->addRoute($route);
return $route;
}
public static function getRoute($controller = null, $parameters = null, $getParams = null) {
return static::router()->getRoute($controller, $parameters, $getParams);
}
public static function request() {
return static::router()->getRequest();
}
public static function response() {
return static::router()->getResponse();
}
protected static function router() {
return RouterBase::getInstance();
return RouterBase::getInstance()->getRoute($controller, $parameters, $getParams);
}
}
-9
View File
@@ -6,13 +6,4 @@ class DummyController {
echo static::class . '@' .'start() OK';
}
public function param($params = null) {
$params = func_get_args();
echo 'Params: ' . join(', ', $params);
}
public function notFound() {
echo 'not found';
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ use Pecee\Http\Request;
class DummyMiddleware implements IMiddleware {
public function handle(Request $request, \Pecee\SimpleRouter\RouterEntry &$route = null) {
public function handle(Request $request) {
throw new MiddlewareLoadedException('Middleware loaded!');
}
-8
View File
@@ -1,8 +0,0 @@
<?php
class ExceptionHandler implements \Pecee\Handler\IExceptionHandler {
public function handleError(\Pecee\Http\Request $request, \Pecee\SimpleRouter\RouterEntry &$route = null, \Exception $error){
throw $error;
}
}
+17 -47
View File
@@ -7,28 +7,37 @@ class GroupTest extends PHPUnit_Framework_TestCase {
protected $result;
public function testGroupLoad() {
public function __construct() {
// Initial setup
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/api/v1/test';
$_SERVER['REQUEST_METHOD'] = 'get';
}
protected function group() {
$this->result = true;
}
public function testGroup() {
\Pecee\SimpleRouter\RouterBase::reset();
$this->result = false;
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/group'], function() {
$this->result = true;
});
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/group'], $this->group());
try {
\Pecee\SimpleRouter\SimpleRouter::start();
} catch(Exception $e) {
// ignore RouteNotFound exception
}
$this->assertTrue($this->result);
}
public function testNestedGroup() {
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/api/v1/test');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\Http\Request::getInstance()->setUri('/api/v1/test');
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/api'], function() {
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/v1'], function() {
@@ -39,43 +48,4 @@ class GroupTest extends PHPUnit_Framework_TestCase {
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testManyRoutes() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/match');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/api'], function() {
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/v1'], function() {
\Pecee\SimpleRouter\SimpleRouter::get('/test', 'DummyController@start');
});
});
\Pecee\SimpleRouter\SimpleRouter::get('/my/match', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/service'], function() {
\Pecee\SimpleRouter\SimpleRouter::group(['prefix' => '/v1'], function() {
\Pecee\SimpleRouter\SimpleRouter::get('/no-match', 'DummyController@start');
});
});
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testUrls() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/fancy/url/1');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::get('/my/fancy/url/1', 'DummyController@start', ['as' => 'fancy1']);
\Pecee\SimpleRouter\SimpleRouter::get('/my/fancy/url/2', 'DummyController@start')->setAlias('fancy2');
\Pecee\SimpleRouter\SimpleRouter::start();
$this->assertTrue((\Pecee\SimpleRouter\SimpleRouter::getRoute('fancy1') === '/my/fancy/url/1/'));
$this->assertTrue((\Pecee\SimpleRouter\SimpleRouter::getRoute('fancy2') === '/my/fancy/url/2/'));
}
}
+12 -8
View File
@@ -2,25 +2,29 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php';
class MiddlewareTest extends PHPUnit_Framework_TestCase {
public function __construct() {
// Initial setup
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/my/test/url';
$_SERVER['REQUEST_METHOD'] = 'get';
}
public function testMiddlewareFound() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url');
\Pecee\Http\Request::getInstance()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function() {
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
});
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start', ['middleware' => 'DummyMiddleware']);
$found = false;
try {
\Pecee\SimpleRouter\SimpleRouter::start();
}catch(\Exception $e) {
}catch(Exception $e) {
$found = ($e instanceof MiddlewareLoadedException);
}
+22 -91
View File
@@ -2,64 +2,48 @@
require_once 'Dummy/DummyMiddleware.php';
require_once 'Dummy/DummyController.php';
require_once 'Dummy/Handler/ExceptionHandler.php';
class RouterRouteTest extends PHPUnit_Framework_TestCase {
protected $result = false;
public function testNotFound() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test-param1-param2');
\Pecee\SimpleRouter\SimpleRouter::group(['exceptionHandler' => 'ExceptionHandler'], function() {
\Pecee\SimpleRouter\SimpleRouter::get('/non-existing-path', 'DummyController@start');
});
$found = false;
try {
\Pecee\SimpleRouter\SimpleRouter::start();
}catch(\Exception $e) {
$found = ($e instanceof \Pecee\Exception\RouterException && $e->getCode() == 404);
}
$this->assertTrue($found);
public function __construct() {
// Initial setup
$_SERVER['HTTP_HOST'] = 'example.com';
$_SERVER['REQUEST_URI'] = '/my/test/url';
$_SERVER['REQUEST_METHOD'] = 'get';
}
public function testGet() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\Http\Request::getInstance()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testPost() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('post');
\Pecee\Http\Request::getInstance()->setMethod('post');
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\SimpleRouter\SimpleRouter::post('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testPut() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('put');
\Pecee\Http\Request::getInstance()->setMethod('put');
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\SimpleRouter\SimpleRouter::put('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testDelete() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('delete');
\Pecee\Http\Request::getInstance()->setMethod('delete');
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\SimpleRouter\SimpleRouter::delete('/my/test/url', 'DummyController@start');
\Pecee\SimpleRouter\SimpleRouter::start();
@@ -67,9 +51,10 @@ class RouterRouteTest extends PHPUnit_Framework_TestCase {
}
public function testMethodNotAllowed() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/my/test/url');
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('post');
\Pecee\SimpleRouter\RouterBase::reset();
\Pecee\Http\Request::getInstance()->setMethod('post');
\Pecee\SimpleRouter\SimpleRouter::get('/my/test/url', 'DummyController@start');
@@ -81,58 +66,4 @@ class RouterRouteTest extends PHPUnit_Framework_TestCase {
}
public function testSimpleParam() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test-param1');
\Pecee\SimpleRouter\SimpleRouter::get('/test-{param1}', 'DummyController@param');
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testMultiParam() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test-param1-param2');
\Pecee\SimpleRouter\SimpleRouter::get('/test-{param1}-{param2}', 'DummyController@param');
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testPathParamRegex() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test/path/123123');
\Pecee\SimpleRouter\SimpleRouter::get('/test/path/{myParam}', 'DummyController@param', ['where' => ['myParam' => '([0-9]+)']]);
\Pecee\SimpleRouter\SimpleRouter::start();
}
public function testDomainRoute() {
\Pecee\SimpleRouter\RouterBase::getInstance()->reset();
\Pecee\SimpleRouter\SimpleRouter::request()->setMethod('get');
\Pecee\SimpleRouter\SimpleRouter::request()->setUri('/test');
\Pecee\SimpleRouter\SimpleRouter::request()->setHost('hello.world.com');
$this->result = false;
\Pecee\SimpleRouter\SimpleRouter::group(['domain' => '{subdomain}.world.com'], function() {
\Pecee\SimpleRouter\SimpleRouter::get('test', function($subdomain = null) {
$this->result = ($subdomain === 'hello');
});
});
\Pecee\SimpleRouter\SimpleRouter::start();
$this->assertTrue($this->result);
}
}