v.0.1
This commit is contained in:
232
vendor/craft-group/phroute/src/Phroute/Dispatcher.php
vendored
Normal file
232
vendor/craft-group/phroute/src/Phroute/Dispatcher.php
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
use Phroute\Phroute\Exception\HttpMethodNotAllowedException;
|
||||
use Phroute\Phroute\Exception\HttpRouteNotFoundException;
|
||||
|
||||
class Dispatcher {
|
||||
|
||||
private $staticRouteMap;
|
||||
private $variableRouteData;
|
||||
private $filters;
|
||||
private $handlerResolver;
|
||||
public $matchedRoute;
|
||||
|
||||
/**
|
||||
* Create a new route dispatcher.
|
||||
*
|
||||
* @param RouteDataInterface $data
|
||||
* @param HandlerResolverInterface $resolver
|
||||
*/
|
||||
public function __construct(RouteDataInterface $data, HandlerResolverInterface $resolver = null)
|
||||
{
|
||||
$this->staticRouteMap = $data->getStaticRoutes();
|
||||
|
||||
$this->variableRouteData = $data->getVariableRoutes();
|
||||
|
||||
$this->filters = $data->getFilters();
|
||||
|
||||
if ($resolver === null)
|
||||
{
|
||||
$this->handlerResolver = new HandlerResolver();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->handlerResolver = $resolver;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a route for the given HTTP Method / URI.
|
||||
*
|
||||
* @param $httpMethod
|
||||
* @param $uri
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function dispatch($httpMethod, $uri)
|
||||
{
|
||||
list($handler, $filters, $vars) = $this->dispatchRoute($httpMethod, trim($uri, '/'));
|
||||
|
||||
list($beforeFilter, $afterFilter) = $this->parseFilters($filters);
|
||||
|
||||
if(($response = $this->dispatchFilters($beforeFilter)) !== null)
|
||||
{
|
||||
return $response;
|
||||
}
|
||||
|
||||
$resolvedHandler = $this->handlerResolver->resolve($handler);
|
||||
|
||||
$response = call_user_func_array($resolvedHandler, $vars);
|
||||
|
||||
return $this->dispatchFilters($afterFilter, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a route filter.
|
||||
*
|
||||
* @param $filters
|
||||
* @param null $response
|
||||
* @return mixed|null
|
||||
*/
|
||||
private function dispatchFilters($filters, $response = null)
|
||||
{
|
||||
while($filter = array_shift($filters))
|
||||
{
|
||||
$handler = $this->handlerResolver->resolve($filter['closure']);
|
||||
|
||||
$params = array_merge([$response], $filter['params']);
|
||||
|
||||
if(($filteredResponse = call_user_func_array($handler, $params)) !== null)
|
||||
{
|
||||
return $filteredResponse;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the array filters attached to the route and merge with any global filters.
|
||||
*
|
||||
* @param $filters
|
||||
* @return array
|
||||
*/
|
||||
private function parseFilters($filters)
|
||||
{
|
||||
$beforeFilter = array();
|
||||
$afterFilter = array();
|
||||
|
||||
if(isset($filters[Route::BEFORE]))
|
||||
{
|
||||
foreach ($filters[Route::BEFORE] as $filter){
|
||||
if(array_key_exists($filter['name'], $this->filters)){
|
||||
$beforeFilter[] = array_merge($filter, ['closure' => $this->filters[$filter['name']]]);
|
||||
}
|
||||
}
|
||||
//$beforeFilter = array_intersect_key($this->filters, array_flip((array) $filters[Route::BEFORE]));
|
||||
}
|
||||
|
||||
if(isset($filters[Route::AFTER]))
|
||||
{
|
||||
foreach ($filters[Route::AFTER] as $filter){
|
||||
if(array_key_exists($filter['name'], $this->filters)){
|
||||
$afterFilter[] = array_merge($filter, ['closure' => $this->filters[$filter['name']]]);
|
||||
}
|
||||
}
|
||||
//$afterFilter = array_intersect_key($this->filters, array_flip((array) $filters[Route::AFTER]));
|
||||
}
|
||||
|
||||
return array($beforeFilter, $afterFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the route dispatching. Check static routes first followed by variable routes.
|
||||
*
|
||||
* @param $httpMethod
|
||||
* @param $uri
|
||||
* @throws Exception\HttpRouteNotFoundException
|
||||
*/
|
||||
private function dispatchRoute($httpMethod, $uri)
|
||||
{
|
||||
if (isset($this->staticRouteMap[$uri]))
|
||||
{
|
||||
return $this->dispatchStaticRoute($httpMethod, $uri);
|
||||
}
|
||||
|
||||
return $this->dispatchVariableRoute($httpMethod, $uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the dispatching of static routes.
|
||||
*
|
||||
* @param $httpMethod
|
||||
* @param $uri
|
||||
* @return mixed
|
||||
* @throws Exception\HttpMethodNotAllowedException
|
||||
*/
|
||||
private function dispatchStaticRoute($httpMethod, $uri)
|
||||
{
|
||||
$routes = $this->staticRouteMap[$uri];
|
||||
|
||||
if (!isset($routes[$httpMethod]))
|
||||
{
|
||||
$httpMethod = $this->checkFallbacks($routes, $httpMethod);
|
||||
}
|
||||
|
||||
return $routes[$httpMethod];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check fallback routes: HEAD for GET requests followed by the ANY attachment.
|
||||
*
|
||||
* @param $routes
|
||||
* @param $httpMethod
|
||||
* @throws Exception\HttpMethodNotAllowedException
|
||||
*/
|
||||
private function checkFallbacks($routes, $httpMethod)
|
||||
{
|
||||
$additional = array(Route::ANY);
|
||||
|
||||
if($httpMethod === Route::HEAD)
|
||||
{
|
||||
$additional[] = Route::GET;
|
||||
}
|
||||
|
||||
foreach($additional as $method)
|
||||
{
|
||||
if(isset($routes[$method]))
|
||||
{
|
||||
return $method;
|
||||
}
|
||||
}
|
||||
|
||||
$this->matchedRoute = $routes;
|
||||
|
||||
throw new HttpMethodNotAllowedException('Allow: ' . implode(', ', array_keys($routes)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the dispatching of variable routes.
|
||||
*
|
||||
* @param $httpMethod
|
||||
* @param $uri
|
||||
* @throws Exception\HttpMethodNotAllowedException
|
||||
* @throws Exception\HttpRouteNotFoundException
|
||||
*/
|
||||
private function dispatchVariableRoute($httpMethod, $uri)
|
||||
{
|
||||
foreach ($this->variableRouteData as $data)
|
||||
{
|
||||
if (!preg_match($data['regex'], $uri, $matches))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$count = count($matches);
|
||||
|
||||
while(!isset($data['routeMap'][$count++]));
|
||||
|
||||
$routes = $data['routeMap'][$count - 1];
|
||||
|
||||
if (!isset($routes[$httpMethod]))
|
||||
{
|
||||
$httpMethod = $this->checkFallbacks($routes, $httpMethod);
|
||||
}
|
||||
|
||||
foreach (array_values($routes[$httpMethod][2]) as $i => $varName)
|
||||
{
|
||||
if(!isset($matches[$i + 1]) || $matches[$i + 1] === '')
|
||||
{
|
||||
unset($routes[$httpMethod][2][$varName]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$routes[$httpMethod][2][$varName] = $matches[$i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
return $routes[$httpMethod];
|
||||
}
|
||||
|
||||
throw new HttpRouteNotFoundException('Route ' . $uri . ' does not exist');
|
||||
}
|
||||
}
|
4
vendor/craft-group/phroute/src/Phroute/Exception/BadRouteException.php
vendored
Normal file
4
vendor/craft-group/phroute/src/Phroute/Exception/BadRouteException.php
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<?php namespace Phroute\Phroute\Exception;
|
||||
|
||||
class BadRouteException extends \LogicException {
|
||||
}
|
3
vendor/craft-group/phroute/src/Phroute/Exception/HttpException.php
vendored
Normal file
3
vendor/craft-group/phroute/src/Phroute/Exception/HttpException.php
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<?php namespace Phroute\Phroute\Exception;
|
||||
|
||||
class HttpException extends \Exception {}
|
3
vendor/craft-group/phroute/src/Phroute/Exception/HttpMethodNotAllowedException.php
vendored
Normal file
3
vendor/craft-group/phroute/src/Phroute/Exception/HttpMethodNotAllowedException.php
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<?php namespace Phroute\Phroute\Exception;
|
||||
|
||||
class HttpMethodNotAllowedException extends HttpException {}
|
4
vendor/craft-group/phroute/src/Phroute/Exception/HttpRouteNotFoundException.php
vendored
Normal file
4
vendor/craft-group/phroute/src/Phroute/Exception/HttpRouteNotFoundException.php
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
<?php namespace Phroute\Phroute\Exception;
|
||||
|
||||
class HttpRouteNotFoundException extends HttpException {}
|
||||
|
21
vendor/craft-group/phroute/src/Phroute/HandlerResolver.php
vendored
Normal file
21
vendor/craft-group/phroute/src/Phroute/HandlerResolver.php
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
class HandlerResolver implements HandlerResolverInterface {
|
||||
|
||||
/**
|
||||
* Create an instance of the given handler.
|
||||
*
|
||||
* @param $handler
|
||||
* @return array
|
||||
*/
|
||||
|
||||
public function resolve ($handler)
|
||||
{
|
||||
if(is_array($handler) && is_string($handler[0]))
|
||||
{
|
||||
$handler[0] = new $handler[0];
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
}
|
13
vendor/craft-group/phroute/src/Phroute/HandlerResolverInterface.php
vendored
Normal file
13
vendor/craft-group/phroute/src/Phroute/HandlerResolverInterface.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
interface HandlerResolverInterface {
|
||||
|
||||
/**
|
||||
* Create an instance of the given handler.
|
||||
*
|
||||
* @param $handler
|
||||
* @return array
|
||||
*/
|
||||
|
||||
public function resolve($handler);
|
||||
}
|
33
vendor/craft-group/phroute/src/Phroute/Route.php
vendored
Normal file
33
vendor/craft-group/phroute/src/Phroute/Route.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
class Route {
|
||||
|
||||
/**
|
||||
* Constants for before and after filters
|
||||
*/
|
||||
const BEFORE = 'before';
|
||||
|
||||
const AFTER = 'after';
|
||||
|
||||
const PREFIX = 'prefix';
|
||||
|
||||
/**
|
||||
* Constants for common HTTP methods
|
||||
*/
|
||||
const ANY = 'ANY';
|
||||
|
||||
const GET = 'GET';
|
||||
|
||||
const HEAD = 'HEAD';
|
||||
|
||||
const POST = 'POST';
|
||||
|
||||
const PUT = 'PUT';
|
||||
|
||||
const PATCH = 'PATCH';
|
||||
|
||||
const DELETE = 'DELETE';
|
||||
|
||||
const OPTIONS = 'OPTIONS';
|
||||
}
|
||||
|
472
vendor/craft-group/phroute/src/Phroute/RouteCollector.php
vendored
Normal file
472
vendor/craft-group/phroute/src/Phroute/RouteCollector.php
vendored
Normal file
@ -0,0 +1,472 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
|
||||
use Phroute\Phroute\Exception\BadRouteException;
|
||||
|
||||
/**
|
||||
* Class RouteCollector
|
||||
* @package Phroute\Phroute
|
||||
*/
|
||||
class RouteCollector implements RouteDataProviderInterface {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const DEFAULT_CONTROLLER_ROUTE = 'index';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const APPROX_CHUNK_SIZE = 10;
|
||||
|
||||
/**
|
||||
* @var RouteParser
|
||||
*/
|
||||
private $routeParser;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $filters = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $staticRoutes = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $regexToRoutesMap = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $reverse = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $globalFilters = [];
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $globalRoutePrefix;
|
||||
|
||||
/**
|
||||
* @param RouteParser $routeParser
|
||||
*/
|
||||
public function __construct(RouteParser $routeParser = null) {
|
||||
$this->routeParser = $routeParser ?: new RouteParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasRoute($name) {
|
||||
return isset($this->reverse[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param array $args
|
||||
* @return string
|
||||
*/
|
||||
public function route($name, array $args = null)
|
||||
{
|
||||
$url = [];
|
||||
|
||||
$replacements = is_null($args) ? [] : array_values($args);
|
||||
|
||||
$variable = 0;
|
||||
|
||||
foreach($this->reverse[$name] as $part)
|
||||
{
|
||||
if(!$part['variable'])
|
||||
{
|
||||
$url[] = $part['value'];
|
||||
}
|
||||
elseif(isset($replacements[$variable]))
|
||||
{
|
||||
if($part['optional'])
|
||||
{
|
||||
$url[] = '/';
|
||||
}
|
||||
|
||||
$url[] = $replacements[$variable++];
|
||||
}
|
||||
elseif(!$part['optional'])
|
||||
{
|
||||
throw new BadRouteException("Expecting route variable '{$part['name']}'");
|
||||
}
|
||||
}
|
||||
|
||||
return implode('', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $httpMethod
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return $this
|
||||
*/
|
||||
public function addRoute($httpMethod, $route, $handler, array $filters = []) {
|
||||
|
||||
if(is_array($route))
|
||||
{
|
||||
list($route, $name) = $route;
|
||||
}
|
||||
|
||||
$route = $this->addPrefix($this->trim($route));
|
||||
|
||||
list($routeData, $reverseData) = $this->routeParser->parse($route);
|
||||
|
||||
if(isset($name))
|
||||
{
|
||||
$this->reverse[$name] = $reverseData;
|
||||
}
|
||||
|
||||
if(array_key_exists(Route::BEFORE, $filters)){
|
||||
$filters = [Route::BEFORE => [['name' => $filters[Route::BEFORE], 'params' => $filters['params']]]];
|
||||
}
|
||||
if(array_key_exists(Route::AFTER, $filters)){
|
||||
$filters = [Route::AFTER => [['name' => $filters[Route::AFTER], 'params' => $filters['params']]]];
|
||||
}
|
||||
|
||||
$filters = array_merge_recursive($this->globalFilters, $filters);
|
||||
|
||||
isset($routeData[1]) ?
|
||||
$this->addVariableRoute($httpMethod, $routeData, $handler, $filters) :
|
||||
$this->addStaticRoute($httpMethod, $routeData, $handler, $filters);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $httpMethod
|
||||
* @param $routeData
|
||||
* @param $handler
|
||||
* @param $filters
|
||||
*/
|
||||
private function addStaticRoute($httpMethod, $routeData, $handler, $filters)
|
||||
{
|
||||
$routeStr = $routeData[0];
|
||||
|
||||
if (isset($this->staticRoutes[$routeStr][$httpMethod]))
|
||||
{
|
||||
throw new BadRouteException("Cannot register two routes matching '$routeStr' for method '$httpMethod'");
|
||||
}
|
||||
|
||||
foreach ($this->regexToRoutesMap as $regex => $routes) {
|
||||
if (isset($routes[$httpMethod]) && preg_match('~^' . $regex . '$~', $routeStr))
|
||||
{
|
||||
throw new BadRouteException("Static route '$routeStr' is shadowed by previously defined variable route '$regex' for method '$httpMethod'");
|
||||
}
|
||||
}
|
||||
|
||||
$this->staticRoutes[$routeStr][$httpMethod] = array($handler, $filters, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $httpMethod
|
||||
* @param $routeData
|
||||
* @param $handler
|
||||
* @param $filters
|
||||
*/
|
||||
private function addVariableRoute($httpMethod, $routeData, $handler, $filters)
|
||||
{
|
||||
list($regex, $variables) = $routeData;
|
||||
|
||||
if (isset($this->regexToRoutesMap[$regex][$httpMethod]))
|
||||
{
|
||||
throw new BadRouteException("Cannot register two routes matching '$regex' for method '$httpMethod'");
|
||||
}
|
||||
|
||||
$this->regexToRoutesMap[$regex][$httpMethod] = [$handler, $filters, $variables];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filters
|
||||
* @param \Closure $callback
|
||||
*/
|
||||
public function group(array $filters, \Closure $callback)
|
||||
{
|
||||
if(array_key_exists(Route::BEFORE, $filters)){
|
||||
$filters = [Route::BEFORE => [['name' => $filters[Route::BEFORE], 'params' => isset($filters['params']) ? $filters['params'] : []]]];
|
||||
}
|
||||
if(array_key_exists(Route::AFTER, $filters)){
|
||||
$filters = [Route::AFTER => [['name' => $filters[Route::AFTER], 'params' => isset($filters['params']) ? $filters['params'] : []]]];
|
||||
}
|
||||
$oldGlobalFilters = $this->globalFilters;
|
||||
|
||||
$oldGlobalPrefix = $this->globalRoutePrefix;
|
||||
|
||||
$this->globalFilters = array_merge_recursive($this->globalFilters, array_intersect_key($filters, [Route::AFTER => 1, Route::BEFORE => 1]));
|
||||
|
||||
$newPrefix = isset($filters[Route::PREFIX]) ? $this->trim($filters[Route::PREFIX]) : null;
|
||||
|
||||
$this->globalRoutePrefix = $this->addPrefix($newPrefix);
|
||||
|
||||
$callback($this);
|
||||
|
||||
$this->globalFilters = $oldGlobalFilters;
|
||||
|
||||
$this->globalRoutePrefix = $oldGlobalPrefix;
|
||||
}
|
||||
|
||||
private function addPrefix($route)
|
||||
{
|
||||
return $this->trim($this->trim($this->globalRoutePrefix) . '/' . $route);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @param $handler
|
||||
*/
|
||||
public function filter($name, $handler)
|
||||
{
|
||||
$this->filters[$name] = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function get($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::GET, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function head($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::HEAD, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function post($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::POST, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function put($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::PUT, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function patch($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::PATCH, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function delete($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::DELETE, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function options($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::OPTIONS, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $handler
|
||||
* @param array $filters
|
||||
* @return RouteCollector
|
||||
*/
|
||||
public function any($route, $handler, array $filters = [])
|
||||
{
|
||||
return $this->addRoute(Route::ANY, $route, $handler, $filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $classname
|
||||
* @param array $filters
|
||||
* @return $this
|
||||
*/
|
||||
public function controller($route, $classname, array $filters = [])
|
||||
{
|
||||
$reflection = new ReflectionClass($classname);
|
||||
|
||||
$validMethods = $this->getValidMethods();
|
||||
|
||||
$sep = $route === '/' ? '' : '/';
|
||||
|
||||
foreach($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method)
|
||||
{
|
||||
foreach($validMethods as $valid)
|
||||
{
|
||||
if(stripos($method->name, $valid) === 0)
|
||||
{
|
||||
$methodName = $this->camelCaseToDashed(substr($method->name, strlen($valid)));
|
||||
|
||||
$params = $this->buildControllerParameters($method);
|
||||
|
||||
if($methodName === self::DEFAULT_CONTROLLER_ROUTE)
|
||||
{
|
||||
$this->addRoute($valid, $route . $params, [$classname, $method->name], $filters);
|
||||
}
|
||||
|
||||
$this->addRoute($valid, $route . $sep . $methodName . $params, [$classname, $method->name], $filters);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionMethod $method
|
||||
* @return string
|
||||
*/
|
||||
private function buildControllerParameters(ReflectionMethod $method)
|
||||
{
|
||||
$params = '';
|
||||
|
||||
foreach($method->getParameters() as $param)
|
||||
{
|
||||
$params .= "/{" . $param->getName() . "}" . ($param->isOptional() ? '?' : '');
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $string
|
||||
* @return string
|
||||
*/
|
||||
private function camelCaseToDashed($string)
|
||||
{
|
||||
return strtolower(preg_replace('/([A-Z])/', '-$1', lcfirst($string)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getValidMethods()
|
||||
{
|
||||
return [
|
||||
Route::ANY,
|
||||
Route::GET,
|
||||
Route::POST,
|
||||
Route::PUT,
|
||||
Route::PATCH,
|
||||
Route::DELETE,
|
||||
Route::HEAD,
|
||||
Route::OPTIONS,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouteDataArray
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
if (empty($this->regexToRoutesMap))
|
||||
{
|
||||
return new RouteDataArray($this->staticRoutes, [], $this->filters);
|
||||
}
|
||||
|
||||
return new RouteDataArray($this->staticRoutes, $this->generateVariableRouteData(), $this->filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @return string
|
||||
*/
|
||||
private function trim($route)
|
||||
{
|
||||
if(is_null($route)) {
|
||||
return null;
|
||||
}
|
||||
return trim($route, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function generateVariableRouteData()
|
||||
{
|
||||
$chunkSize = $this->computeChunkSize(count($this->regexToRoutesMap));
|
||||
$chunks = array_chunk($this->regexToRoutesMap, $chunkSize, true);
|
||||
return array_map([$this, 'processChunk'], $chunks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $count
|
||||
* @return float
|
||||
*/
|
||||
private function computeChunkSize($count)
|
||||
{
|
||||
$numParts = max(1, round($count / self::APPROX_CHUNK_SIZE));
|
||||
return ceil($count / $numParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $regexToRoutesMap
|
||||
* @return array
|
||||
*/
|
||||
private function processChunk($regexToRoutesMap)
|
||||
{
|
||||
$routeMap = [];
|
||||
$regexes = [];
|
||||
$numGroups = 0;
|
||||
foreach ($regexToRoutesMap as $regex => $routes) {
|
||||
$firstRoute = reset($routes);
|
||||
$numVariables = count($firstRoute[2]);
|
||||
$numGroups = max($numGroups, $numVariables);
|
||||
|
||||
$regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);
|
||||
|
||||
foreach ($routes as $httpMethod => $route) {
|
||||
$routeMap[$numGroups + 1][$httpMethod] = $route;
|
||||
}
|
||||
|
||||
$numGroups++;
|
||||
}
|
||||
|
||||
$regex = '~^(?|' . implode('|', $regexes) . ')$~';
|
||||
return ['regex' => $regex, 'routeMap' => $routeMap];
|
||||
}
|
||||
}
|
57
vendor/craft-group/phroute/src/Phroute/RouteDataArray.php
vendored
Normal file
57
vendor/craft-group/phroute/src/Phroute/RouteDataArray.php
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
class RouteDataArray implements RouteDataInterface {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $variableRoutes;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $staticRoutes;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $filters;
|
||||
|
||||
/**
|
||||
* @param array $staticRoutes
|
||||
* @param array $variableRoutes
|
||||
* @param array $filters
|
||||
*/
|
||||
public function __construct(array $staticRoutes, array $variableRoutes, array $filters)
|
||||
{
|
||||
$this->staticRoutes = $staticRoutes;
|
||||
|
||||
$this->variableRoutes = $variableRoutes;
|
||||
|
||||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getStaticRoutes()
|
||||
{
|
||||
return $this->staticRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getVariableRoutes()
|
||||
{
|
||||
return $this->variableRoutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
}
|
24
vendor/craft-group/phroute/src/Phroute/RouteDataInterface.php
vendored
Normal file
24
vendor/craft-group/phroute/src/Phroute/RouteDataInterface.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
|
||||
/**
|
||||
* Interface RouteDataInterface
|
||||
* @package Phroute\Phroute
|
||||
*/
|
||||
interface RouteDataInterface {
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getStaticRoutes();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getVariableRoutes();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters();
|
||||
}
|
14
vendor/craft-group/phroute/src/Phroute/RouteDataProviderInterface.php
vendored
Normal file
14
vendor/craft-group/phroute/src/Phroute/RouteDataProviderInterface.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
|
||||
/**
|
||||
* Interface RouteDataProviderInterface
|
||||
* @package Phroute\Phroute
|
||||
*/
|
||||
interface RouteDataProviderInterface {
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getData();
|
||||
}
|
207
vendor/craft-group/phroute/src/Phroute/RouteParser.php
vendored
Normal file
207
vendor/craft-group/phroute/src/Phroute/RouteParser.php
vendored
Normal file
@ -0,0 +1,207 @@
|
||||
<?php namespace Phroute\Phroute;
|
||||
|
||||
use Phroute\Phroute\Exception\BadRouteException;
|
||||
/**
|
||||
* Parses routes of the following form:
|
||||
*
|
||||
* "/user/{name}/{id:[0-9]+}?"
|
||||
*/
|
||||
class RouteParser {
|
||||
|
||||
/**
|
||||
* Search through the given route looking for dynamic portions.
|
||||
*
|
||||
* Using ~ as the regex delimiter.
|
||||
*
|
||||
* We start by looking for a literal '{' character followed by any amount of whitespace.
|
||||
* The next portion inside the parentheses looks for a parameter name containing alphanumeric characters or underscore.
|
||||
*
|
||||
* After this we look for the ':\d+' and ':[0-9]+' style portion ending with a closing '}' character.
|
||||
*
|
||||
* Finally we look for an optional '?' which is used to signify an optional route.
|
||||
*/
|
||||
const VARIABLE_REGEX =
|
||||
"~\{
|
||||
\s* ([a-zA-Z0-9_]*) \s*
|
||||
(?:
|
||||
: \s* ([^{]+(?:\{.*?\})?)
|
||||
)?
|
||||
\}\??~x";
|
||||
|
||||
/**
|
||||
* The default parameter character restriction (One or more characters that is not a '/').
|
||||
*/
|
||||
const DEFAULT_DISPATCH_REGEX = '[^/]+';
|
||||
|
||||
private $parts;
|
||||
|
||||
private $reverseParts;
|
||||
|
||||
private $partsCounter;
|
||||
|
||||
private $variables;
|
||||
|
||||
private $regexOffset;
|
||||
|
||||
/**
|
||||
* Handy parameter type restrictions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $regexShortcuts = array(
|
||||
':i}' => ':[0-9]+}',
|
||||
':a}' => ':[0-9A-Za-z]+}',
|
||||
':h}' => ':[0-9A-Fa-f]+}',
|
||||
':c}' => ':[a-zA-Z0-9+_\-\.]+}'
|
||||
);
|
||||
|
||||
/**
|
||||
* Parse a route returning the correct data format to pass to the dispatch engine.
|
||||
*
|
||||
* @param $route
|
||||
* @return array
|
||||
*/
|
||||
public function parse($route)
|
||||
{
|
||||
$this->reset();
|
||||
|
||||
$route = strtr($route, $this->regexShortcuts);
|
||||
|
||||
if (!$matches = $this->extractVariableRouteParts($route))
|
||||
{
|
||||
$reverse = array(
|
||||
'variable' => false,
|
||||
'value' => $route
|
||||
);
|
||||
|
||||
return [[$route], array($reverse)];
|
||||
}
|
||||
|
||||
foreach ($matches as $set) {
|
||||
|
||||
$this->staticParts($route, $set[0][1]);
|
||||
|
||||
$this->validateVariable($set[1][0]);
|
||||
|
||||
$regexPart = (isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX);
|
||||
|
||||
$this->regexOffset = $set[0][1] + strlen($set[0][0]);
|
||||
|
||||
$match = '(' . $regexPart . ')';
|
||||
|
||||
$isOptional = substr($set[0][0], -1) === '?';
|
||||
|
||||
if($isOptional)
|
||||
{
|
||||
$match = $this->makeOptional($match);
|
||||
}
|
||||
|
||||
$this->reverseParts[$this->partsCounter] = array(
|
||||
'variable' => true,
|
||||
'optional' => $isOptional,
|
||||
'name' => $set[1][0]
|
||||
);
|
||||
|
||||
$this->parts[$this->partsCounter++] = $match;
|
||||
}
|
||||
|
||||
$this->staticParts($route, strlen($route));
|
||||
|
||||
return [[implode('', $this->parts), $this->variables], array_values($this->reverseParts)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the parser ready for the next route.
|
||||
*/
|
||||
private function reset()
|
||||
{
|
||||
$this->parts = array();
|
||||
|
||||
$this->reverseParts = array();
|
||||
|
||||
$this->partsCounter = 0;
|
||||
|
||||
$this->variables = array();
|
||||
|
||||
$this->regexOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any variable route portions from the given route.
|
||||
*
|
||||
* @param $route
|
||||
* @return mixed
|
||||
*/
|
||||
private function extractVariableRouteParts($route)
|
||||
{
|
||||
if(preg_match_all(self::VARIABLE_REGEX, $route, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER))
|
||||
{
|
||||
return $matches;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $route
|
||||
* @param $nextOffset
|
||||
*/
|
||||
private function staticParts($route, $nextOffset)
|
||||
{
|
||||
$static = preg_split('~(/)~u', substr($route, $this->regexOffset, $nextOffset - $this->regexOffset), 0, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
foreach($static as $staticPart)
|
||||
{
|
||||
if($staticPart)
|
||||
{
|
||||
$quotedPart = $this->quote($staticPart);
|
||||
|
||||
$this->parts[$this->partsCounter] = $quotedPart;
|
||||
|
||||
$this->reverseParts[$this->partsCounter] = array(
|
||||
'variable' => false,
|
||||
'value' => $staticPart
|
||||
);
|
||||
|
||||
$this->partsCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $varName
|
||||
*/
|
||||
private function validateVariable($varName)
|
||||
{
|
||||
if (isset($this->variables[$varName]))
|
||||
{
|
||||
throw new BadRouteException("Cannot use the same placeholder '$varName' twice");
|
||||
}
|
||||
|
||||
$this->variables[$varName] = $varName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $match
|
||||
* @return string
|
||||
*/
|
||||
private function makeOptional($match)
|
||||
{
|
||||
$previous = $this->partsCounter - 1;
|
||||
|
||||
if(isset($this->parts[$previous]) && $this->parts[$previous] === '/')
|
||||
{
|
||||
$this->partsCounter--;
|
||||
$match = '(?:/' . $match . ')';
|
||||
}
|
||||
|
||||
return $match . '?';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $part
|
||||
* @return string
|
||||
*/
|
||||
private function quote($part)
|
||||
{
|
||||
return preg_quote($part, '~');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user