123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- <?php
- namespace Qii\Base;
- use Qii\Config\Consts;
- use Qii\Config\Register;
- use Qii\Request\Http;
- /**
- * Route
- */
- class Route
- {
- /**
- * group 路由前缀
- * @var string
- */
- public $prefix = '';
- /**
- * 路由 middleware
- * @var array
- */
- public $middleware = [];
- /**
- * 路由
- * @var array
- */
- private $route = [];
- /**
- * 存储转换后的路由和middleware
- *
- * @var array $stored
- */
- private $stored = [];
- /**
- * 是否启用正则匹配
- *
- * @var bool $enableExpress 默认为启用
- */
- private $enableExpress = true;
- public function __construct() {
- $this->clean();
- }
- /**
- * 清理middleware和路由规则
- *
- * @return void
- */
- public function clean() {
- $this->prefix = '';
- $this->middleware = [];
- $this->route = [
- 'GET' => [],
- 'POST' => [],
- 'DELETE' => [],
- 'PUT' => [],
- 'HEAD' => [],
- 'ANY' => []
- ];
- }
- /**
- * 实例化Route
- * @return mixed|object|string|null
- */
- public static function getInstance() {
- return \Qii::getInstance("Qii\Base\Route");
- }
- /**
- * 设置路由规则
- *
- * @param array $route
- * @return void
- */
- public function setRoute($route){
- if (!is_array($route) && !in_array($route, $this->route)) {
- $this->route[] = $route;
- }
- $this->route = array_merge($this->route, $route);
- }
- /**
- * 设置URL前缀
- *
- * @param string $name
- * @return mixed|object|string|null
- */
- public static function prefix($name) {
- $route = self::getInstance();
- $route->clean();
- $route->prefix = $name;
- return $route;
- }
- /**
- * 设置中间件
- * @param array|string $middleware
- * @return $this
- */
- public function setMiddleware($middleware) {
- if(!is_array($middleware)) {
- $this->middleware[] = $middleware;
- }else{
- $this->middleware = array_merge($this->middleware, $middleware);
- }
- return $this;
- }
- public function gatherMiddleware(){
- return array_unique($this->middleware);
- }
- public function group($callable) {
- $route = \Qii::getInstance("Qii\Base\Route");
- call_user_func($callable, $route);
- $this->stored[] = [$route->middleware, $route->route];
- return $this;
- }
- public function get($uri, $callable){
- $uri = $this->appendPrefix($this->prefix, $uri);
- $this->route['GET'][] = [$uri, $callable];
- return $this;
- }
- public function post($uri, $callable) {
- $uri = $this->appendPrefix($this->prefix, $uri);
- $this->route['POST'][] = [$uri, $callable];
- return $this;
- }
- /**
- * 补充前缀
- * @param string $prefix 前缀
- * @param string $uri uri
- * @return mixed|string
- */
- protected function appendPrefix($prefix, $uri){
- if(!$prefix) {
- return $uri;
- }
- return $prefix . '/'. ltrim($uri, '/');;
- }
- public function put($uri, $callable) {
- $uri = $this->appendPrefix($this->prefix, $uri);
- $this->route['PUT'][] = [$uri, $callable];
- return $this;
- }
- public function delete($uri, $callable) {
- $uri = $this->appendPrefix($this->prefix, $uri);
- $this->route['DELETE'][] = [$uri, $callable];
- return $this;
- }
- public function any($uri, $callable) {
- $uri = $this->appendPrefix($this->prefix, $uri);
- $this->route['ANY'][] = [$uri, $callable];
- return $this;
- }
- /**
- * 匹配路由并执行
- *
- * @param $request
- * @return bool
- */
- public function match(Http $request, $next) {
- $route = $this->getStoredRoute();
- $method = strtoupper($request->getMethod());
- $uri = $request->getRequestUri();
- $middleware = [];
- $callable = '';
- foreach ($route as $item) {
- $middleware = $item[0];
- $subRoute = $item[1];
- if(!isset($subRoute[$method]) && !isset($subRoute['ANY'])) {
- continue;
- }
- $subRoute['ANY'] = isset($subRoute['ANY']) ? (array) $subRoute['ANY'] : array();
- $subRoute[$method] = isset($subRoute[$method]) ? (array) $subRoute[$method] : array();
- $routes = array_merge($subRoute[$method], $subRoute['ANY']);
- $callable = '';
- $args = null;
- foreach ($routes as $routeUri) {
- //启用正则匹配
- if($this->enableExpress) {
- list($route, $args) = $this->parse($uri, $routeUri);
- if($route) {
- if(is_array($args)) {
- //将$args的值设置到get参数里
- foreach ($args as $key => $value) {
- $request->set($key, $value);
- }
- }
- $callable = $route[1];
- break;
- }
- }
- if ($uri == $routeUri[0]) {
- $callable = $routeUri[1];
- break;
- }
- }
- if ($callable) {
- break;
- }
- }
- if (!$callable || count($middleware) == 0) {
- return $next($request);
- }
- //命中后,执行相应程序后就不往下执行
- $middleware = array_reverse(array_unique($middleware));
- $result = array_reduce($middleware, function ($carry, $item){
- return function () use ($carry, $item){
- return _loadClass($item)->handle(\Qii::getInstance()->request, $carry);
- };
- }, function(){
- return true;
- })();
- if (!$result) return false;
- if (!$this->make($callable, $request, $args)){
- return $next($request);
- }
- return false;
- }
- /**
- * 匹配规则
- * /user/get/{uid:num}/{name:string}/{sex:string}
- *
- * @param string $uri 请求uri
- * @param array $route 路由规则
- * @return null[]
- */
- public function parse($uri, $route) {
- if(preg_match("/\{.*?\}/i", $route[0])) {
- $uriArray = explode("/", $uri);
- $routeArray = explode("/", $route[0]);
- //如果uri的长度比route的端,那就直接不匹配
- if(count($uriArray) < count($routeArray)) {
- return [null, null];
- }
- $args = array();
- $firstMatch = -1;
- foreach ($routeArray as $index => $val) {
- if(preg_match("/\{.*?\}/i", $val)) {
- if($firstMatch == -1) {
- $firstMatch = $index;
- }
- $key = str_replace(array("{", "}"), "", $val);
- $args[$key] = $uriArray[$index];
- }
- }
- //首次变量的位置之前的内容不匹配,页直接返回不匹配
- $uriMatch = join("/", array_slice($uriArray, 0, 4));
- $routeMatch = join("/", array_slice($routeArray, 0, 4));
- if($uriMatch != $routeMatch) {
- return [null, null];
- }
- return [$route, $args];
- }
- return [null, null];
- }
- /**
- * 执行 $callable
- * @param mix $callable 执行方法
- * @param HTTP $request request
- * @param array | null $args 正则匹配后拿到的参数及值
- * @return bool
- */
- public function make($callable, $request, $args = null) {
- if($args === null) {
- $args = array($request);
- }
- if(is_array($args)) {
- array_unshift($args, $request);
- }
- switch ($callable) {
- case ($callable instanceof \Closure):
- $res = call_user_func_array($callable, $args);
- if($res instanceof \Qii\Base\Response) {
- return $res->response();
- }
- echo $res;
- break;
- case is_array($callable):
- echo Register::get("APP_DEFAULT_ACTION");
- $action = (isset($callable[1]) ? $callable[1] : "index"). Register::get(Consts::APP_DEFAULT_ACTION_SUFFIX);
- $res = call_user_func_array(array(_loadClass($callable[0]), $action), $args);
- if($res instanceof \Qii\Base\Response) {
- return $res->response();
- }
- break;
- case gettype($callable) == 'string':
- $res = call_user_func_array(
- array(_loadClass($callable),
- Register::get("APP_DEFAULT_ACTION"). Register::get(Consts::APP_DEFAULT_ACTION_SUFFIX)), $args);
- if($res instanceof \Qii\Base\Response) {
- return $res->response();
- }
- break;
- }
- if ($callable) {
- return true;
- }
- return false;
- }
- /**
- * 获取所有设置的路由
- *
- * @return mixed
- */
- public function getStoredRoute(){
- return self::getInstance()->stored;
- }
- }
|