Bläddra i källkod

升级匹配规则
升级转发规则

Zhu Jinhui 6 år sedan
förälder
incheckning
d7b7990137
2 ändrade filer med 117 tillägg och 76 borttagningar
  1. 5 1
      src/Base/Dispatcher.php
  2. 112 75
      src/Router/Parse/Normal.php

+ 5 - 1
src/Base/Dispatcher.php

@@ -38,7 +38,11 @@ class Dispatcher
         $controller = $controller != '' ? $controller : $this->request->getControllerName();
         $action = $action != '' ? $action : $this->request->getActionName();
 
-        $controllerName = Register::get(Consts::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
+        $controllerName = $controller;
+        //如果controller以\开头,就不添加默认前缀 Update at 2018-05-29 13:50
+        if(substr($controller,0, 1) != '\\') {
+            $controllerName = Register::get(Consts::APP_DEFAULT_CONTROLLER_PREFIX) . '_' . $controller;
+        }
         $funcArgs = array();
         if (count($args) > 2) {
             $funcArgs = array_slice($args, 2);

+ 112 - 75
src/Router/Parse/Normal.php

@@ -1,5 +1,4 @@
 <?php
-
 namespace Qii\Router\Parse;
 
 /**
@@ -37,19 +36,38 @@ class Normal
      * @param String $action
      * @return Array ($controller, $action);
      *
-     * *:* => *:yyy 所有controller和action都转发到 *->yyy
-     * *:* => yy:* 所有转发到xxx->*, 这里的*,前边对应的是什么,后边就对应转发到什么,比如: *:xxx => yy:yyy
-     * xx:* => yy:* xx中对应的方法转发到yy对应的方法
-     * xx:* => yy:yyy xxx Controller转发到 yy->yyy
-     * *:xxx => yy:yyy 所有Controller转发到 yy->yyy
-     * xxx:*(yy):第三个参数 => {1}:* 转发xxx:yy => yy:第三个参数
+     * $rules = [
+     * 'api:*' => 'api\client\*:*',
+     * 'api:client:admin:*' => 'api\client\{2}:*',
+     * 'api:admin:*' => 'api\admin\{2}:*',
+     * 'admin:*' => 'admin\{1}:*',
+     * 'udp:*' => 'udp\{1}:*',
+     * 's:*' => 's:index',
+     * 'index:*' => 'ip:*',
+     * 'shortURL:*:*' => '\shortURL\*:*'
+     * ];
+     *
+     * $urls = [
+     * '/api/client/admin' => ['controller' => 'api\client\client', 'action' => 'index'],
+     * '/api/client/admin/remove' => ['controller' => 'api\client', 'action' => 'remove'],
+     * '/api/url/add' => ['controller' => 'api\url', 'action' => 'add'],
+     * '/api/admin/free/add' => ['controller' => 'api\admin\free', 'action' => 'add'],
+     * '/admin/index' => ['controller' => 'admin\index', 'action' => 'index'],
+     * '/admin/dir/add' => ['controller' => 'admin\dir', 'action' => 'add'],
+     * '/udp/index' => ['controller' => 'udp', 'action' => 'index'],
+     * '/udp/add' => ['controller' => 'udp', 'action' => 'index'],
+     * '/s/for' => ['controller' => 's', 'action' =>'index'],
+     * '/index/for' => ['controller' => 'ip', 'action' =>'for'],
+     * '/usr/login/check' => ['controller' => 'usr\login', 'action' => 'check'],
+     * '/shortURL/free/sss' => ['controller' => '\shortURL\free', 'action' => 'sss'],
+     * ];
      */
     public function parse($url, $controller, $action)
     {
         if (!$this->config) {
             return array('controller' => $controller, 'action' => $action);
         }
-        if ($url == '' || $url == '/') $url = 'index/index.html';
+        if($url == '' || $url == '/') $url = 'index/index.html';
         $url = ltrim($url, '/');
         $dirName = pathinfo($url, PATHINFO_DIRNAME);
         $dirInfo = explode('/', $dirName);
@@ -59,91 +77,110 @@ class Normal
         }
         $dirInfo[] = $fileName;
         //补全路径
-        if (count($dirInfo) == 1) {
+        if(count($dirInfo) == 1)
+        {
             $dirInfo[] = 'index';
         }
 
         $dir = [];
-        $match = ['key' => '', 'val' => '', 'url' => $url];
-        if (isset($this->config['*:*'])) {
+        $match = ['url' => $url, 'controller' => $controller, 'action' => $action];
+        if(isset($this->config['*:*'])) {
             list($controller, $action) = explode(':', $this->config['*:*']);
             $match['match'] = '*:*';
             $match['controller'] = $controller ? $controller : 'index';
             $match['action'] = $action ? $action : 'index';
             return $match;
         }
-        foreach ($dirInfo AS $path) {
+        $match['dirInfo'] = $dirInfo;
+
+        $lastFound = [];
+        //将内容和规则做匹配
+        foreach ($dirInfo AS $key => $path) {
             $dir[] = $path;
-            $notAll = join($dir, ':');
-            if (isset($this->config[$notAll])) {
-                $config = $this->config[$notAll];
-                //匹配最长的规则
-                if (strlen($config) > strlen($match['val'])) {
-                    $match = array_merge($match, ['key' => $notAll, 'val' => $config]);
-                }
-            }
-            $joinPath = join($dir, ':') . ":*";
-            if (isset($this->config[$joinPath])) {
-                $config = $this->config[$joinPath];
-                //匹配最长的规则
-                if (strlen($config) > strlen($match['val'])) {
-                    $match = array_merge($match, ['key' => $joinPath, 'val' => $config]);
+            $register = [];
+            $matchLen = 0;
+            foreach($this->config as $config => $val) {
+                //匹配规则
+                $configArr = explode(':', $config);
+                $interSet = array_intersect_assoc($configArr, $dir);
+                if($interSet) {
+                    $countInterSet = count($interSet);
+                    if($configArr[$countInterSet] == '*' || $configArr[$countInterSet] == $dirInfo[$dirInfo[$key]]) {
+                        if($matchLen < $countInterSet) {
+                            $register = ['rule' => $config, 'val' => $val, 'interSet' => $interSet];
+                        }else{
+                            $matchLen = $countInterSet;
+                        }
+                    }
                 }
-            } else if (isset($this->config[$joinPath . ':*'])) {
-                $match = array_merge($match, ['key' => $joinPath, 'val' => $this->config[$joinPath . ':*']]);
-            } else if (isset($this->config[$joinPath . ':*:*'])) {
-                $match = array_merge($match, ['key' => $joinPath, 'val' => $this->config[$joinPath . ':*:*']]);
             }
         }
-        $match['dirInfo'] = $dirInfo;
-        //如果match到就解析match的内容
-        if ($match['val']) {
-            $real = $match['val'];
-            $matches = explode(':', $match['val']);
-            $match['matches'] = $matches;
-            $maxIndex = 0;
-            foreach ($match['matches'] as $val) {
-                preg_match_all("/[\d]/", $val, $index);
-                if ($index && $index[0]) {
-                    foreach ($index[0] as $i) {
-                        if($maxIndex < $i) $maxIndex = $i;
-                        if (isset($dirInfo[$i])) $real = str_replace('{' . $i . '}', $dir[$i], $real);
-                    }
-                }
+        if(!empty($register)){
+            $lastFound = $register;
+        }
+        $match['match'] = $lastFound;
+        //没有匹配到就直接使用/url做匹配
+        if(!$match['match']) {
+            $info = $this->getInfoFromDirInfo($dirInfo);
+            $match['controller'] = $info['controller'];
+            $match['action'] = $info['action'];
+            return $match;
+        }
+        //解析规则
+        $rulesVal = $match['match']['val'];
+        preg_match_all("/\{[\d]{1,}\}|[\*]{1}/", $rulesVal, $rules);
+
+        if(empty($rules) || empty($rules[0])) {
+            $info = $this->getInfoFromDirInfo($dirInfo);
+            $match['controller'] = $info['controller'];
+            $match['action'] = $info['action'];
+        }
+        $maxIndex = 0;
+        //获取*位置最大值索引值
+        if(preg_match("/[\*]{1}/", $rulesVal)) {
+            foreach($rules[0] as $val) {
+                $val = intval(str_replace(array('{', '}'), '', $val));
+                if($val > $maxIndex) $maxIndex = $val;
             }
             $maxIndex++;
-            $match['real'] = $real;
-            $matches = explode(':', $real);
-            $action = array_pop($matches);
-            $controller = join('\\', $matches);
-            $match['controller'] = $controller;
-            //如果 action == * 那就取路径中的配置 或默认为index
-            $match['action'] = $action == '*' && isset($dirInfo[$maxIndex])? $dirInfo[$maxIndex] : 'index';
-        } else {
-            $controller = 'index';
-            $action = 'index';
-            if (count($dirInfo) > 1) {
-                $action = array_pop($dirInfo);
-                $controller = join('\\', $dirInfo);
-            } else if (count($dirInfo) == 1 && !empty($dirInfo[0])) {
-                $controller = $dirInfo[0];
-            }
-            $match['controller'] = $controller;
-            $match['action'] = $action;
-            //匹配配置文件中以 * 开头的规则
-            foreach ($this->config as $key => $config) {
-                if (substr($key, 0, 2) == '*:') {
-                    list($sourceController, $sourceAction) = explode(':', $key);
-                    list($destController, $destAction) = explode(":", $config);
-                    $match['controller'] = $destController;
-                    if ($sourceAction == '*') {
-                        $map['action'] = $destAction;
-                    } else if ($map['action'] == $sourceAction) {
-                        $map['action'] = $destAction;
-                    }
-                }
+        }
+        $replacements = $rules[0];
+        foreach($rules[0] as $key => $val)
+        {
+            if(preg_match("/\{[\d]{1,}\}/", $val)) {
+                $index = str_replace(array('{', '}'), '', $val);
+                $replacements[$key] = $dirInfo[$index] ?? 'index';
+                $rulesVal = preg_replace("/\{[\d]{1,}\}/", $replacements[$key], $rulesVal, 1);
+            }else if($val == '*'){
+                $replacements[$key] = $dirInfo[$maxIndex] ?? 'index';
+                //一次只替换一个,用于匹配多次
+                $rulesVal = preg_replace("/[\*]{1}/", $replacements[$key], $rulesVal, 1);
+                $maxIndex++;
             }
         }
+        list($controller, $action) = explode(":", $rulesVal);
+        $match['controller'] = $controller;
+        $match['action'] = $action ?? 'index';
+        $match['replacements'] = $replacements;
+        $match['rulesVal'] = $rulesVal;
         return $match;
     }
+
+    /**
+     * 从路径中获取controller和action
+     *
+     * @param array $dirInfo 目录路径
+     * @return array
+     */
+    protected function getInfoFromDirInfo($dirInfo)
+    {
+        if(count($dirInfo) >= 2) {
+            $action = array_pop($dirInfo);
+            $controller = join("\\", $dirInfo);
+        }else{
+            $controller = join("\\", $dirInfo);
+            $action = 'index';
+        }
+        return ['controller' => $controller, 'action' => $action];
+    }
 }