mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-17 16:57:53 +00:00
Compare commits
85 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1512740af | |||
| 35bb58818e | |||
| 212ae133de | |||
| 438d3c258b | |||
| ae58231fa1 | |||
| a58ec1544d | |||
| 1bafbab56b | |||
| 6395801a06 | |||
| 060479f1fe | |||
| b29f2ce37d | |||
| 358b25d4f1 | |||
| 5483ffe458 | |||
| 6d8e95fcaa | |||
| 3d45851d9b | |||
| db78135d19 | |||
| c4fcf750d4 | |||
| ee5c2207f8 | |||
| a92b6008fa | |||
| b1ca3fc9ef | |||
| 253c0c70d4 | |||
| 115c8e510a | |||
| 53ba2d7ac5 | |||
| 35ee79d02c | |||
| 315fe05769 | |||
| 6306b604e8 | |||
| 4dd0739df9 | |||
| a57113309a | |||
| 0bd234d996 | |||
| 27d24758b1 | |||
| 4d08f08c68 | |||
| aeacda1812 | |||
| 765204f552 | |||
| 4267cb8751 | |||
| 714edf7902 | |||
| c3b12ba053 | |||
| b096742d6b | |||
| 3298970798 | |||
| bb6f56ef8c | |||
| 6c675124fa | |||
| 14a030294e | |||
| 8bc8124366 | |||
| 1332ef7139 | |||
| 12bbc98a82 | |||
| 69b0f4320e | |||
| 4c60055c7e | |||
| 89aeeeb593 | |||
| 849749969d | |||
| c37a7159d2 | |||
| df2545dd37 | |||
| bd0a6af41f | |||
| 3510c4c5a4 | |||
| 7ff88bc658 | |||
| ce27196083 | |||
| 9304b9f866 | |||
| ed886cb7b3 | |||
| cbaa0bcaac | |||
| 98b1759967 | |||
| b9be7695a7 | |||
| 97e2edd207 | |||
| 87fbbcbba2 | |||
| 5a501db767 | |||
| 669bfa0a86 | |||
| 4f07f38cf5 | |||
| c67ab20ddd | |||
| ad1ce21c66 | |||
| 5a19d6339c | |||
| 23ee53060e | |||
| 77ba9f165e | |||
| 4dd6417f71 | |||
| 3012435caa | |||
| 0bec524606 | |||
| d4e9ef7744 | |||
| cede827a45 | |||
| 9da90d1435 | |||
| 4d70efcc4d | |||
| e1c549bfdb | |||
| b9f426989b | |||
| f1f5faa81e | |||
| 6c56947792 | |||
| 925b9761f4 | |||
| 59956d5fca | |||
| 3ba2cec8af | |||
| d36880e9a0 | |||
| c74d83796f | |||
| 2128a24f1c |
@@ -1,22 +1,17 @@
|
||||
# Simple PHP router
|
||||
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the Laravel router.
|
||||
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expandability in mind.
|
||||
|
||||
## Installation
|
||||
Add the latest version pf Simple PHP Router to your ```composer.json```
|
||||
Add the latest version of Simple PHP Router running this command.
|
||||
|
||||
```json
|
||||
{
|
||||
"require": {
|
||||
"pecee/simple-php-router": "1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"pecee/simple-php-router": "1.*"
|
||||
}
|
||||
}
|
||||
```
|
||||
composer require pecee/framework
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
The goal of this project is to create a router that is 100% compatible with the Laravel documentation, but as simple as possible and as easy to integrate and change as possible.
|
||||
|
||||
### Features
|
||||
|
||||
- Basic routing (get, post, put, delete) with support for custom multiple verbs.
|
||||
@@ -29,11 +24,8 @@ Add the latest version pf Simple PHP Router to your ```composer.json```
|
||||
- Route prefixes.
|
||||
- CSRF protection.
|
||||
- Optional parameters
|
||||
|
||||
### Features currently "in-the-works"
|
||||
|
||||
- Global Constraints
|
||||
- Sub-domain routing
|
||||
- Custom boot managers to redirect urls to other routes
|
||||
|
||||
## Initialising the router
|
||||
|
||||
@@ -75,15 +67,15 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So
|
||||
SimpleRouter::group(['prefix' => '/services', 'exceptionHandler' => '\MyProject\Handler\CustomExceptionHandler'], function() {
|
||||
|
||||
SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show')->where(['id' => '[0-9]+');
|
||||
|
||||
|
||||
// Optional parameter
|
||||
SimpleRouter::get('/answers/{id?}', 'ControllerAnswers@show');
|
||||
|
||||
/**
|
||||
* This example will route url when matching the regular expression to the method.
|
||||
* For example route: /ajax/music/world -> ControllerAjax@process (parameter: music/world)
|
||||
* For example route: domain.com/ajax/music/world -> ControllerAjax@process (parameter: music/world)
|
||||
*/
|
||||
SimpleRouter::all('/ajax', 'ControllerAjax@process')->match('ajax\\/([A-Za-z0-9\\/]+)');
|
||||
SimpleRouter::all('/ajax', 'ControllerAjax@process')->match('.*?\\/ajax\\/([A-Za-z0-9\\/]+)');
|
||||
|
||||
// Restful resource
|
||||
SimpleRouter::resource('/rest', 'ControllerRessource');
|
||||
@@ -100,6 +92,20 @@ SimpleRouter::group(['prefix' => 'v1', 'middleware' => '\MyWebsite\Middleware\So
|
||||
});
|
||||
```
|
||||
|
||||
### Sub-domain routing
|
||||
|
||||
Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the ```domain``` key on the group attribute array:
|
||||
|
||||
```php
|
||||
Route::group(['domain' => '{account}.myapp.com'], function () {
|
||||
Route::get('user/{id}', function ($account, $id) {
|
||||
//
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
The prefix group array attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with admin:
|
||||
|
||||
### Doing it the object oriented (hardcore) way
|
||||
|
||||
The ```SimpleRouter``` class referenced in the previous example, is just a simple helper class that knows how to communicate with the ```RouterBase``` class.
|
||||
@@ -159,10 +165,10 @@ class Router extends SimpleRouter {
|
||||
$exceptionHandler = null;
|
||||
|
||||
// Load and use exception-handler defined on group
|
||||
|
||||
|
||||
if($route && $route->getGroup()) {
|
||||
$exceptionHandler = $route->getGroup()->getExceptionHandler();
|
||||
|
||||
|
||||
if($exceptionHandler !== null) {
|
||||
$class = new $exceptionHandler();
|
||||
$class->handleError(RouterBase::getInstance()->getRequest(), $route, $e);
|
||||
@@ -170,7 +176,7 @@ class Router extends SimpleRouter {
|
||||
}
|
||||
|
||||
// Otherwise use the fallback default exceptions handler
|
||||
|
||||
|
||||
if(self::$defaultExceptionHandler !== null) {
|
||||
$class = new self::$defaultExceptionHandler();
|
||||
$class->handleError(RouterBase::getInstance()->getRequest(), $route, $e);
|
||||
@@ -187,7 +193,8 @@ class Router extends SimpleRouter {
|
||||
}
|
||||
```
|
||||
|
||||
This is a basic example of a helper function for generating urls.
|
||||
#### Helper functions examples
|
||||
**This is a basic example of a helper function for generating urls.**
|
||||
|
||||
```php
|
||||
use Pecee\SimpleRouter\RouterBase;
|
||||
@@ -196,7 +203,7 @@ function url($controller, $parameters = null, $getParams = null) {
|
||||
}
|
||||
```
|
||||
|
||||
This is a basic example for getting the current csrf token
|
||||
**This is a basic example for getting the current csrf token**
|
||||
|
||||
```php
|
||||
/**
|
||||
@@ -253,6 +260,78 @@ Register the new class in your ```routes.php```, custom ```Router``` class or wh
|
||||
SimpleRouter::csrfVerifier(new \Demo\Middleware\CsrfVerifier());
|
||||
```
|
||||
|
||||
## Using router bootmanager to make custom rewrite rules
|
||||
|
||||
Sometimes it can be necessary to keep urls stored in the database, file or similar. In this example, we want the url ```/my-cat-is-beatiful``` to load the route ```/article/view/1``` which the router knows, because it's defined in the ```routes.php``` file.
|
||||
|
||||
To interfere with the router, we create a class that 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 comming from the url ```/my-cat-is-beatiful```).
|
||||
|
||||
```php
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\RouterBootManager;
|
||||
|
||||
class CustomRouterRules extends RouterBootManager{
|
||||
|
||||
public function boot(Request $request) {
|
||||
|
||||
$rewriteRules = [
|
||||
'/my-cat-is-beatiful' => '/article/view/1',
|
||||
'/horses-are-great' => '/article/view/2'
|
||||
];
|
||||
|
||||
foreach($rewriteRules as $url => $rule) {
|
||||
|
||||
// If the current uri matches the url, we use our custom route
|
||||
|
||||
if($request->getUri() === $url) {
|
||||
$request->setUri($rule);
|
||||
}
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The above should be pretty self-explanatory and can easily be changed to loop through urls store in the database, file or cache.
|
||||
|
||||
What happens is that if the current route matches the route defined in the index of our ```$rewriteRules``` array, we set the route to the array value instead.
|
||||
|
||||
By doing this the route will now load the url ```/article/view/1``` instead of ```/my-cat-is-beatiful```.
|
||||
|
||||
The last thing we need to do, is to add our custom boot-manager to the ```routes.php``` file. You can create as many bootmanagers as you like and easily add them in your ```routes.php``` file.
|
||||
|
||||
**routes.php example:**
|
||||
|
||||
```php
|
||||
// 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 --
|
||||
|
||||
$route->setClass('Example\MyCustomClass');
|
||||
$route->setMethod('hello');
|
||||
```
|
||||
|
||||
## Documentation
|
||||
While I work on a better documentation, please refer to the Laravel 5 routing documentation here:
|
||||
|
||||
@@ -261,9 +340,12 @@ http://laravel.com/docs/5.1/routing
|
||||
## Easily extendable
|
||||
The router can be easily extended to customize your needs.
|
||||
|
||||
## Ideas and issues
|
||||
If you want a great new feature or experience any issues what-so-ever, please feel free to leave an issue and i'll look into it whenever possible.
|
||||
|
||||
## The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Simon Sessingø / simple-php-router
|
||||
Copyright (c) 2016 Simon Sessingø / simple-php-router
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -7,12 +7,6 @@ class CsrfToken {
|
||||
|
||||
protected $token;
|
||||
|
||||
public function __construct() {
|
||||
if($this->getToken() === null) {
|
||||
$this->setToken($this->generateToken());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate random identifier for CSRF token
|
||||
* @return string
|
||||
@@ -51,10 +45,18 @@ class CsrfToken {
|
||||
* @return string|null
|
||||
*/
|
||||
public function getToken(){
|
||||
if(isset($_COOKIE[self::CSRF_KEY])) {
|
||||
if($this->hasToken()) {
|
||||
return $_COOKIE[self::CSRF_KEY];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the csrf token has been defined
|
||||
* @return bool
|
||||
*/
|
||||
public function hasToken() {
|
||||
return isset($_COOKIE[self::CSRF_KEY]);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
namespace Pecee\Exception;
|
||||
class RouterException extends \Exception { }
|
||||
@@ -6,10 +6,6 @@ class Request {
|
||||
protected static $instance;
|
||||
|
||||
protected $data;
|
||||
protected $uri;
|
||||
protected $host;
|
||||
protected $method;
|
||||
protected $headers;
|
||||
|
||||
/**
|
||||
* Return new instance
|
||||
@@ -27,10 +23,23 @@ class Request {
|
||||
$this->host = $_SERVER['HTTP_HOST'];
|
||||
$this->uri = $_SERVER['REQUEST_URI'];
|
||||
$this->method = (isset($_POST['_method'])) ? strtolower($_POST['_method']) : strtolower($_SERVER['REQUEST_METHOD']);
|
||||
$this->headers = array_change_key_case(getallheaders(), CASE_LOWER);
|
||||
$this->headers = $this->getAllHeaders();
|
||||
}
|
||||
|
||||
protected function getAllHeaders() {
|
||||
$headers = array();
|
||||
foreach ($_SERVER as $name => $value) {
|
||||
if (substr($name, 0, 5) === 'HTTP_') {
|
||||
$headers[strtolower(str_replace('_', '-', substr($name, 5)))] = $value;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
|
||||
public function getIsSecure() {
|
||||
if(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https') {
|
||||
return true;
|
||||
}
|
||||
return isset($_SERVER['HTTPS']) ? true : (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] === 443);
|
||||
}
|
||||
|
||||
@@ -122,6 +131,17 @@ class Request {
|
||||
return (isset($_REQUEST[$name]) ? $_REQUEST[$name] : $defaultValue);
|
||||
}
|
||||
|
||||
public function isFormatAccepted($format) {
|
||||
return (isset($_SERVER['HTTP_ACCEPT']) && stripos($_SERVER['HTTP_ACCEPT'], $format) > -1);
|
||||
}
|
||||
|
||||
public function getAcceptFormats() {
|
||||
if(isset($_SERVER['HTTP_ACCEPT'])) {
|
||||
return explode(',', $_SERVER['HTTP_ACCEPT']);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
public function __set($name, $value = null) {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
@@ -130,4 +150,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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,14 +19,19 @@ class Response {
|
||||
* Redirect the response
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $httpCode
|
||||
*/
|
||||
public function redirect($url) {
|
||||
$this->header('Location: ' . $url);
|
||||
public function redirect($url, $httpCode = null) {
|
||||
if($httpCode !== null) {
|
||||
$this->httpCode($httpCode);
|
||||
}
|
||||
|
||||
$this->header('location: ' . $url);
|
||||
die();
|
||||
}
|
||||
|
||||
public function refresh() {
|
||||
$this->redirect(url());
|
||||
$this->redirect(Request::getInstance()->getUri());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
interface IRouteEntry {
|
||||
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\ArrayUtil;
|
||||
use Pecee\CsrfToken;
|
||||
use Pecee\Exception\RouterException;
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\Url;
|
||||
|
||||
class RouterBase {
|
||||
|
||||
@@ -15,38 +15,50 @@ class RouterBase {
|
||||
protected $routes;
|
||||
protected $processedRoutes;
|
||||
protected $controllerUrlMap;
|
||||
protected $backstack;
|
||||
protected $loadedRoute;
|
||||
protected $backStack;
|
||||
protected $defaultNamespace;
|
||||
protected $bootManagers;
|
||||
protected $baseCsrfVerifier;
|
||||
|
||||
// TODO: make interface for controller routers, so they can be easily detected
|
||||
// TODO: clean up - cut some of the methods down to smaller pieces
|
||||
|
||||
public function __construct() {
|
||||
$this->routes = array();
|
||||
$this->backstack = array();
|
||||
$this->backStack = array();
|
||||
$this->controllerUrlMap = array();
|
||||
$this->request = Request::getInstance();
|
||||
$this->baseCsrfVerifier = new BaseCsrfVerifier();
|
||||
$this->request = new Request();
|
||||
$this->bootManagers = array();
|
||||
|
||||
$csrf = new CsrfToken();
|
||||
$token = ($csrf->hasToken()) ? $csrf->getToken() : $csrf->generateToken();
|
||||
$csrf->setToken($token);
|
||||
}
|
||||
|
||||
public function addRoute(RouterEntry $route) {
|
||||
if($this->currentRoute !== null) {
|
||||
$this->backstack[] = $route;
|
||||
$this->backStack[] = $route;
|
||||
} else {
|
||||
$this->routes[] = $route;
|
||||
}
|
||||
}
|
||||
|
||||
protected function processRoutes(array $routes, array $settings = array(), array $prefixes = array(), $backstack = false, $group = null) {
|
||||
protected function processRoutes(array $routes, array $settings = array(), array $prefixes = array(), $backStack = false, $group = null) {
|
||||
// Loop through each route-request
|
||||
|
||||
$activeGroup = null;
|
||||
$routesCount = count($routes);
|
||||
$mergedSettings = array();
|
||||
|
||||
/* @var $route RouterEntry */
|
||||
foreach($routes as $route) {
|
||||
for($i = 0; $i < $routesCount; $i++) {
|
||||
|
||||
$route->setGroup($group);
|
||||
$route = $routes[$i];
|
||||
|
||||
$route->addSettings($settings);
|
||||
|
||||
if($backStack) {
|
||||
$route->setGroup($group);
|
||||
}
|
||||
|
||||
if($this->defaultNamespace && !$route->getNamespace()) {
|
||||
$namespace = null;
|
||||
@@ -60,40 +72,54 @@ class RouterBase {
|
||||
}
|
||||
|
||||
$newPrefixes = $prefixes;
|
||||
$mergedSettings = array_merge($settings, $route->getMergeableSettings());
|
||||
|
||||
if($route->getPrefix()) {
|
||||
array_push($newPrefixes, rtrim($route->getPrefix(), '/'));
|
||||
}
|
||||
$route->addSettings($mergedSettings);
|
||||
|
||||
if(!($route instanceof RouterGroup)) {
|
||||
if(is_array($newPrefixes) && count($newPrefixes) && $backstack) {
|
||||
if(is_array($newPrefixes) && count($newPrefixes) && $backStack) {
|
||||
$route->setUrl( join('/', $newPrefixes) . $route->getUrl() );
|
||||
}
|
||||
|
||||
$group = null;
|
||||
$this->controllerUrlMap[] = $route;
|
||||
}
|
||||
|
||||
$this->currentRoute = $route;
|
||||
if($route instanceof RouterGroup && is_callable($route->getCallback())) {
|
||||
|
||||
if($route instanceof RouterGroup && $route->matchRoute($this->request) && is_callable($route->getCallback())) {
|
||||
$group = $route;
|
||||
$route->renderRoute($this->request);
|
||||
$activeGroup = $route;
|
||||
$mergedSettings = array_merge($route->getMergeableSettings(), $settings);
|
||||
}
|
||||
|
||||
$this->currentRoute = null;
|
||||
|
||||
if(count($this->backstack)) {
|
||||
$backstack = $this->backstack;
|
||||
$this->backstack = array();
|
||||
if(count($this->backStack)) {
|
||||
$backStack = $this->backStack;
|
||||
$this->backStack = array();
|
||||
|
||||
// Route any routes added to the backstack
|
||||
$this->processRoutes($backstack, $mergedSettings, $newPrefixes, true, $activeGroup);
|
||||
$this->processRoutes($backStack, $mergedSettings, $newPrefixes, true, $group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function routeRequest() {
|
||||
|
||||
// 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) {
|
||||
/* @var $csrfVerifier BaseCsrfVerifier */
|
||||
@@ -107,11 +133,16 @@ class RouterBase {
|
||||
|
||||
$routeNotAllowed = false;
|
||||
|
||||
$max = count($this->controllerUrlMap);
|
||||
|
||||
/* @var $route RouterEntry */
|
||||
foreach($this->controllerUrlMap as $route) {
|
||||
for($i = 0; $i < $max; $i++) {
|
||||
|
||||
$route = $this->controllerUrlMap[$i];
|
||||
|
||||
$routeMatch = $route->matchRoute($this->request);
|
||||
|
||||
if($routeMatch && !($routeMatch instanceof RouterGroup)) {
|
||||
if($routeMatch) {
|
||||
|
||||
if(count($route->getRequestMethods()) && !in_array($this->request->getMethod(), $route->getRequestMethods())) {
|
||||
$routeNotAllowed = true;
|
||||
@@ -120,9 +151,10 @@ class RouterBase {
|
||||
|
||||
$routeNotAllowed = false;
|
||||
|
||||
$this->loadedRoute = $routeMatch;
|
||||
$routeMatch->loadMiddleware($this->request);
|
||||
$routeMatch->renderRoute($this->request);
|
||||
$this->request->loadedRoute = $route;
|
||||
$route->loadMiddleware($this->request);
|
||||
|
||||
$this->request->loadedRoute->renderRoute($this->request);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +163,7 @@ class RouterBase {
|
||||
throw new RouterException('Route or method not allowed', 403);
|
||||
}
|
||||
|
||||
if(!$this->loadedRoute) {
|
||||
if(!$this->request->loadedRoute) {
|
||||
throw new RouterException(sprintf('Route not found: %s', $this->request->getUri()), 404);
|
||||
}
|
||||
}
|
||||
@@ -150,12 +182,30 @@ class RouterBase {
|
||||
$this->defaultNamespace = $defaultNamespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getBootManagers() {
|
||||
return $this->bootManagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $bootManagers
|
||||
*/
|
||||
public function setBootManagers(array $bootManagers) {
|
||||
$this->bootManagers = $bootManagers;
|
||||
}
|
||||
|
||||
public function addBootManager(RouterBootManager $bootManager) {
|
||||
$this->bootManagers[] = $bootManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouterEntry
|
||||
*/
|
||||
public function getLoadedRoute() {
|
||||
if(!($this->loadedRoute instanceof RouterGroup)) {
|
||||
return $this->loadedRoute;
|
||||
if(!($this->request->loadedRoute instanceof RouterGroup)) {
|
||||
return $this->request->loadedRoute;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -164,7 +214,7 @@ class RouterBase {
|
||||
* @return array
|
||||
*/
|
||||
public function getBackstack() {
|
||||
return $this->backstack;
|
||||
return $this->backStack;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,9 +259,34 @@ class RouterBase {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function arrayToParams(array $getParams = null, $includeEmpty = true) {
|
||||
if (is_array($getParams) && count($getParams) > 0) {
|
||||
foreach ($getParams as $key => $val) {
|
||||
if (!empty($val) || empty($val) && $includeEmpty) {
|
||||
$getParams[$key] = $key . '=' . $val;
|
||||
}
|
||||
}
|
||||
return join('&', $getParams);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function processUrl($route, $method = null, $parameters = null, $getParams = null) {
|
||||
|
||||
$url = '/' . trim($route->getUrl(), '/');
|
||||
$domain = '';
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
$domain = '//' . $domain;
|
||||
}
|
||||
|
||||
$url = $domain . '/' . trim($route->getUrl(), '/');
|
||||
|
||||
if(($route instanceof RouterController || $route instanceof RouterResource) && $method !== null) {
|
||||
$url .= $method;
|
||||
@@ -223,26 +298,32 @@ class RouterBase {
|
||||
}
|
||||
} else {
|
||||
/* @var $route RouterEntry */
|
||||
$params = $route->getParameters();
|
||||
if(count($params)) {
|
||||
$i = 0;
|
||||
foreach($params as $param => $value) {
|
||||
$value = (isset($parameters[$param])) ? $parameters[$param] : $value;
|
||||
$url = str_ireplace(array('{' . $param. '}', '{' . $param. '?}'), $value, $url);
|
||||
$i++;
|
||||
}
|
||||
if(is_array($parameters)) {
|
||||
$params = array_merge($route->getParameters(), $parameters);
|
||||
} else {
|
||||
// If no parameters are specified in the route, assume that the provided parameters should be used.
|
||||
if(count($parameters)) {
|
||||
$url = rtrim($url, '/') . '/' . join('/', $parameters);
|
||||
}
|
||||
$params = $route->getParameters();
|
||||
}
|
||||
|
||||
$otherParams = [];
|
||||
|
||||
$i = 0;
|
||||
foreach($params as $param => $value) {
|
||||
$value = (isset($parameters[$param])) ? $parameters[$param] : $value;
|
||||
if(stripos($url, '{' . $param. '}') !== false || stripos($url, '{' . $param . '?}') !== false) {
|
||||
$url = str_ireplace(array('{' . $param . '}', '{' . $param . '?}'), $value, $url);
|
||||
} else {
|
||||
$otherParams[$param] = $value;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
$url = rtrim($url, '/') . '/' . join('/', $otherParams);
|
||||
}
|
||||
|
||||
$url = rtrim($url, '/') . '/';
|
||||
|
||||
if($getParams !== null && count($getParams)) {
|
||||
$url .= '?'.Url::arrayToParams($getParams);
|
||||
$url .= '?' . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
return $url;
|
||||
@@ -258,22 +339,40 @@ class RouterBase {
|
||||
throw new \InvalidArgumentException('Invalid type for getParams. Must be array or null');
|
||||
}
|
||||
|
||||
if($controller === null && $parameters === null && $this->loadedRoute !== null) {
|
||||
return $this->processUrl($this->loadedRoute, null, $getParams);
|
||||
// Return current route if no options has been specified
|
||||
if($controller === null && $parameters === null) {
|
||||
$getParams = (is_array($getParams)) ? array_merge($_GET, $getParams) : $_GET;
|
||||
|
||||
$url = parse_url(Request::getInstance()->getUri());
|
||||
$url = $url['path'];
|
||||
|
||||
if(count($getParams)) {
|
||||
$url .= '?' . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
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 */
|
||||
foreach($this->controllerUrlMap as $route) {
|
||||
for($i = 0; $i < $max; $i++) {
|
||||
|
||||
$route = $this->controllerUrlMap[$i];
|
||||
|
||||
// Check an alias exist, if the matches - use it
|
||||
if($route instanceof RouterRoute && strtolower($route->getAlias()) === strtolower($controller)) {
|
||||
return $this->processUrl($route, $route->getMethod(), $parameters, $getParams);
|
||||
}
|
||||
|
||||
if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) {
|
||||
if($route instanceof RouterRoute && stripos($route->getCallback(), '@') !== false) {
|
||||
$c = $route->getCallback();
|
||||
} else if($route instanceof RouterController || $route instanceof RouterResource) {
|
||||
$c = $route->getController();
|
||||
@@ -287,7 +386,10 @@ class RouterBase {
|
||||
$c = '';
|
||||
|
||||
// No match has yet been found, let's try to guess what url that should be returned
|
||||
foreach($this->controllerUrlMap as $route) {
|
||||
for($i = 0; $i < $max; $i++) {
|
||||
|
||||
$route = $this->controllerUrlMap[$i];
|
||||
|
||||
if($route instanceof RouterRoute && !is_callable($route->getCallback()) && stripos($route->getCallback(), '@') !== false) {
|
||||
$c = $route->getClass();
|
||||
} else if($route instanceof RouterController || $route instanceof RouterResource) {
|
||||
@@ -309,13 +411,16 @@ class RouterBase {
|
||||
$url = array($controller);
|
||||
|
||||
if(is_array($parameters)) {
|
||||
ArrayUtil::append($url, $parameters);
|
||||
foreach($parameters as $key => $value) {
|
||||
array_push($url,$value);
|
||||
}
|
||||
}
|
||||
|
||||
$url = '/' . trim(join('/', $url), '/') . '/';
|
||||
|
||||
if(is_array($getParams)) {
|
||||
$url .= '?' . Url::arrayToParams($getParams);
|
||||
|
||||
if($getParams !== null && count($getParams)) {
|
||||
$url .= '?' . $this->arrayToParams($getParams);
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
abstract class RouterBootManager {
|
||||
|
||||
abstract public function boot(Request $request);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Exception\RouterException;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterController extends RouterEntry {
|
||||
@@ -38,10 +39,12 @@ class RouterController extends RouterEntry {
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
$url = parse_url($request->getUri());
|
||||
$url = parse_url(urldecode($request->getUri()));
|
||||
$url = rtrim($url['path'], '/') . '/';
|
||||
|
||||
if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
|
||||
@@ -61,7 +64,7 @@ class RouterController extends RouterEntry {
|
||||
// Set callback
|
||||
$this->setCallback($this->controller . '@' . $this->method);
|
||||
|
||||
return $this;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Exception\RouterException;
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
@@ -23,13 +24,12 @@ abstract class RouterEntry {
|
||||
|
||||
protected $settings;
|
||||
protected $callback;
|
||||
protected $parameters;
|
||||
|
||||
public function __construct() {
|
||||
$this->settings = array();
|
||||
$this->settings['requestMethods'] = array();
|
||||
$this->settings['parametersRegex'] = array();
|
||||
$this->parameters = array();
|
||||
$this->settings['where'] = array();
|
||||
$this->settings['parameters'] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,6 +78,16 @@ abstract class RouterEntry {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function setMethod($method) {
|
||||
$this->callback = sprintf('%s@%s', $this->getClass(), $method);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setClass($class) {
|
||||
$this->callback = sprintf('%s@%s', $class, $this->getMethod());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefix
|
||||
* @return self
|
||||
@@ -137,7 +147,7 @@ abstract class RouterEntry {
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParameters(){
|
||||
return $this->parameters;
|
||||
return ($this->parameters === null) ? array() : $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +166,7 @@ abstract class RouterEntry {
|
||||
* @return self
|
||||
*/
|
||||
public function where(array $options) {
|
||||
$this->parametersRegex = array_merge($this->parametersRegex, $options);
|
||||
$this->where = array_merge($this->where, $options);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -179,10 +189,6 @@ abstract class RouterEntry {
|
||||
public function getMergeableSettings() {
|
||||
$settings = $this->settings;
|
||||
|
||||
/*if(isset($settings['middleware'])) {
|
||||
unset($settings['middleware']);
|
||||
}*/
|
||||
|
||||
if(isset($settings['prefix'])) {
|
||||
unset($settings['prefix']);
|
||||
}
|
||||
@@ -216,7 +222,7 @@ abstract class RouterEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamicially access settings value
|
||||
* Dynamically access settings value
|
||||
*
|
||||
* @param $name
|
||||
* @return mixed|null
|
||||
@@ -243,6 +249,92 @@ abstract class RouterEntry {
|
||||
return new $name();
|
||||
}
|
||||
|
||||
protected function parseParameters($route, $url, $parameterRegex = '[a-z0-9]+') {
|
||||
$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;
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function loadMiddleware(Request $request) {
|
||||
if($this->getMiddleware()) {
|
||||
if(is_array($this->getMiddleware())) {
|
||||
@@ -252,7 +344,7 @@ abstract class RouterEntry {
|
||||
throw new RouterException($middleware . ' must be instance of Middleware');
|
||||
}
|
||||
|
||||
/* @var $class Middleware */
|
||||
/* @var $class IMiddleware */
|
||||
$middleware->handle($request);
|
||||
}
|
||||
} else {
|
||||
@@ -261,7 +353,7 @@ abstract class RouterEntry {
|
||||
throw new RouterException($this->getMiddleware() . ' must be instance of Middleware');
|
||||
}
|
||||
|
||||
/* @var $class Middleware */
|
||||
/* @var $class IMiddleware */
|
||||
$middleware->handle($request);
|
||||
}
|
||||
}
|
||||
@@ -285,7 +377,11 @@ abstract class RouterEntry {
|
||||
throw new RouterException(sprintf('Method %s does not exist in class %s', $method, $className), 404);
|
||||
}
|
||||
|
||||
call_user_func_array(array($class, $method), $this->getParameters());
|
||||
$parameters = array_filter($this->getParameters(), function($var){
|
||||
return !is_null($var);
|
||||
});
|
||||
|
||||
call_user_func_array(array($class, $method), $parameters);
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Exception\RouterException;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterGroup extends RouterEntry {
|
||||
@@ -10,6 +11,40 @@ class RouterGroup extends RouterEntry {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function matchDomain(Request $request) {
|
||||
if($this->domain !== null) {
|
||||
|
||||
if(is_array($this->domain)) {
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function renderRoute(Request $request) {
|
||||
// Check if request method is allowed
|
||||
$hasAccess = (!$this->method);
|
||||
@@ -26,11 +61,18 @@ class RouterGroup extends RouterEntry {
|
||||
throw new RouterException('Method not allowed');
|
||||
}
|
||||
|
||||
$this->matchDomain($request);
|
||||
|
||||
return parent::renderRoute($request);
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
return null;
|
||||
// Skip if prefix doesn't match
|
||||
if($this->getPrefix() !== null && stripos($request->getUri(), $this->getPrefix()) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->matchDomain($request);
|
||||
}
|
||||
|
||||
public function setExceptionHandler($class) {
|
||||
@@ -42,4 +84,8 @@ class RouterGroup extends RouterEntry {
|
||||
return $this->exceptionHandler;
|
||||
}
|
||||
|
||||
public function getDomain() {
|
||||
return $this->domain;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
<?php
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\Exception\RouterException;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterResource extends RouterEntry {
|
||||
|
||||
const DEFAULT_METHOD = 'index';
|
||||
|
||||
protected $url;
|
||||
protected $controller;
|
||||
protected $method;
|
||||
protected $postMethod;
|
||||
|
||||
public function __construct($url, $controller) {
|
||||
@@ -45,62 +43,58 @@ class RouterResource extends RouterEntry {
|
||||
protected function call($method, $parameters) {
|
||||
$this->setCallback($this->controller . '@' . $method);
|
||||
$this->parameters = $parameters;
|
||||
return $this;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
$url = parse_url($request->getUri());
|
||||
$url = parse_url(urldecode($request->getUri()));
|
||||
$url = rtrim($url['path'], '/') . '/';
|
||||
|
||||
if(strtolower($url) == strtolower($this->url) || stripos($url, $this->url) === 0) {
|
||||
$url = rtrim($url, '/');
|
||||
$route = rtrim($this->url, '/') . '/{id?}/{action?}';
|
||||
|
||||
$strippedUrl = trim(substr($url, strlen($this->url)), '/');
|
||||
$path = explode('/', $strippedUrl);
|
||||
$parameters = $this->parseParameters($route, $url, '[0-9]+?');
|
||||
|
||||
$args = $path;
|
||||
$action = '';
|
||||
if($parameters !== null) {
|
||||
|
||||
if(count($args)) {
|
||||
$action = $args[0];
|
||||
array_shift($args);
|
||||
if(is_array($parameters)) {
|
||||
$parameters = array_merge($this->parameters, $parameters);
|
||||
}
|
||||
|
||||
if (count($path)) {
|
||||
$action = isset($parameters['action']) ? $parameters['action'] : null;
|
||||
unset($parameters['action']);
|
||||
|
||||
// Delete
|
||||
if($request->getMethod() === self::REQUEST_TYPE_DELETE && $this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('destroy', $args);
|
||||
}
|
||||
|
||||
// Update
|
||||
if(in_array($request->getMethod(), array('put', 'patch')) && $this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('update', array_merge(array($action), $args));
|
||||
}
|
||||
|
||||
// Edit
|
||||
if(isset($args[0]) && strtolower($args[0]) === 'edit' && $this->postMethod === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('edit', array_merge(array($action), array_slice($args, 1)));
|
||||
}
|
||||
|
||||
// Create
|
||||
if(strtolower($action) === 'create' && $request->getMethod() === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('create', $args);
|
||||
}
|
||||
|
||||
// Save
|
||||
if($this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('store', $args);
|
||||
}
|
||||
|
||||
// Show
|
||||
if($action && $this->postMethod === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('show', array_merge(array($action), $args));
|
||||
}
|
||||
|
||||
// Index
|
||||
return $this->call('index', $args);
|
||||
// Delete
|
||||
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(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' && $this->postMethod === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('edit', $parameters);
|
||||
}
|
||||
|
||||
// Create
|
||||
if(strtolower($action) === 'create' && $request->getMethod() === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('create', $parameters);
|
||||
}
|
||||
|
||||
// Save
|
||||
if($this->postMethod === self::REQUEST_TYPE_POST) {
|
||||
return $this->call('store', $parameters);
|
||||
}
|
||||
|
||||
// Show
|
||||
if(isset($parameters['id']) && $this->postMethod === self::REQUEST_TYPE_GET) {
|
||||
return $this->call('show', $parameters);
|
||||
}
|
||||
|
||||
// Index
|
||||
return $this->call('index', $parameters);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -135,18 +129,4 @@ class RouterResource extends RouterEntry {
|
||||
$this->controller = $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMethod() {
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
*/
|
||||
public function setMethod($method) {
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Pecee\ArrayUtil;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RouterRoute extends RouterEntry {
|
||||
@@ -20,98 +21,36 @@ class RouterRoute extends RouterEntry {
|
||||
|
||||
public function matchRoute(Request $request) {
|
||||
|
||||
$url = parse_url($request->getUri());
|
||||
$url = parse_url(urldecode($request->getUri()));
|
||||
$url = rtrim($url['path'], '/') . '/';
|
||||
|
||||
// Match on custom defined regular expression
|
||||
if($this->regexMatch) {
|
||||
$parameters = array();
|
||||
if(preg_match('/('.$this->regexMatch.')/is', $url, $parameters)) {
|
||||
if(preg_match('/('.$this->regexMatch.')/is', $request->getHost() . $url, $parameters)) {
|
||||
$this->parameters = (!is_array($parameters[0]) ? array($parameters[0]) : $parameters[0]);
|
||||
return $this;
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make regular expression based on route
|
||||
|
||||
$route = rtrim($this->url, '/') . '/';
|
||||
|
||||
$parameterNames = array();
|
||||
$regex = '';
|
||||
$lastCharacter = '';
|
||||
$isParameter = false;
|
||||
$parameter = '';
|
||||
$parameters = $this->parseParameters($route, $url);
|
||||
|
||||
for($i = 0; $i < strlen($route); $i++) {
|
||||
if($parameters !== null) {
|
||||
|
||||
$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
|
||||
if($lastCharacter === '?') {
|
||||
$parameter = substr($parameter, 0, strlen($parameter)-1);
|
||||
$regex .= '(?:(?:\/{0,1}(?P<'.$parameter.'>[a-z0-9]*?)){0,1}\\/)';
|
||||
$required = false;
|
||||
} else {
|
||||
// Use custom parameter regex if it exists
|
||||
$parameterRegex = '[a-z0-9]*?';
|
||||
|
||||
if(is_array($this->parametersRegex) && isset($this->parametersRegex[$parameter])) {
|
||||
$parameterRegex = $this->parametersRegex[$parameter];
|
||||
}
|
||||
|
||||
$regex .= '(?:\\/{0,1}(?P<' . $parameter . '>'. $parameterRegex .')\\/)';
|
||||
}
|
||||
$parameterNames[] = array('name' => $parameter, 'required' => $required);
|
||||
$parameter = '';
|
||||
$isParameter = false;
|
||||
|
||||
} elseif($isParameter) {
|
||||
$parameter .= $character;
|
||||
} elseif($character === '/') {
|
||||
$regex .= '\\' . $character;
|
||||
if(is_array($this->parameters)) {
|
||||
$this->parameters = array_merge($this->parameters, $parameters);
|
||||
} else {
|
||||
$regex .= $character;
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
$lastCharacter = $character;
|
||||
return true;
|
||||
}
|
||||
|
||||
$parameterValues = array();
|
||||
|
||||
if(preg_match('/^'.$regex.'$/is', $url, $parameterValues)) {
|
||||
|
||||
$parameters = array();
|
||||
|
||||
if(count($parameterNames)) {
|
||||
foreach($parameterNames as $name) {
|
||||
$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);
|
||||
}
|
||||
|
||||
$parameters[$name['name']] = $parameterValue;
|
||||
}
|
||||
}
|
||||
|
||||
$this->parameters = $parameters;
|
||||
return $this;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -128,7 +67,6 @@ class RouterRoute extends RouterEntry {
|
||||
* @return self
|
||||
*/
|
||||
public function setUrl($url) {
|
||||
|
||||
$parameters = array();
|
||||
$matches = array();
|
||||
|
||||
@@ -137,9 +75,11 @@ class RouterRoute extends RouterEntry {
|
||||
}
|
||||
|
||||
if(count($parameters)) {
|
||||
$tmp = array();
|
||||
foreach($parameters as $param) {
|
||||
$this->parameters[$param] = '';
|
||||
$tmp[$param] = null;
|
||||
}
|
||||
$this->parameters = $tmp;
|
||||
}
|
||||
|
||||
$this->url = $url;
|
||||
|
||||
@@ -19,7 +19,7 @@ class SimpleRouter {
|
||||
* @throws RouterException
|
||||
*/
|
||||
public static function start($defaultNamespace = null) {
|
||||
$router = RouterBase::GetInstance();
|
||||
$router = RouterBase::getInstance();
|
||||
$router->setDefaultNamespace($defaultNamespace);
|
||||
$router->routeRequest();
|
||||
}
|
||||
@@ -32,6 +32,10 @@ class SimpleRouter {
|
||||
RouterBase::getInstance()->setBaseCsrfVerifier($baseCsrfVerifier);
|
||||
}
|
||||
|
||||
public static function addBootManager(RouterBootManager $bootManager) {
|
||||
RouterBase::getInstance()->addBootManager($bootManager);
|
||||
}
|
||||
|
||||
public static function get($url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->addSettings($settings);
|
||||
@@ -90,6 +94,18 @@ class SimpleRouter {
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds get + post route
|
||||
*
|
||||
* @param string $url
|
||||
* @param function $callback
|
||||
* @param array|null $settings
|
||||
* @return RouterRoute
|
||||
*/
|
||||
public static function basic($url, $callback, array $settings = null) {
|
||||
return self::match(['get', 'post'], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
public static function match(array $requestMethods, $url, $callback, array $settings = null) {
|
||||
$route = new RouterRoute($url, $callback);
|
||||
$route->setRequestMethods($requestMethods);
|
||||
|
||||
Reference in New Issue
Block a user