diff --git a/composer.json b/composer.json index 27da3874..e1ae4c52 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "High performance QQ robot and web server development framework", "minimum-stability": "stable", "license": "Apache-2.0", - "version": "2.1.4", + "version": "2.1.5", "extra": { "exclude_annotate": [ "src/ZM" diff --git a/src/ZM/Annotation/AnnotationParser.php b/src/ZM/Annotation/AnnotationParser.php index a1b2361d..22e205e4 100644 --- a/src/ZM/Annotation/AnnotationParser.php +++ b/src/ZM/Annotation/AnnotationParser.php @@ -12,6 +12,7 @@ use ReflectionMethod; use ZM\Annotation\Http\{HandleAfter, HandleBefore, Controller, HandleException, Middleware, MiddlewareClass, RequestMapping}; use ZM\Annotation\Interfaces\Level; use ZM\Annotation\Module\Closed; +use ZM\Http\RouteManager; use ZM\Utils\DataProvider; class AnnotationParser @@ -113,7 +114,7 @@ class AnnotationParser $method_anno->class = $v; $method_anno->method = $method_name; if ($method_anno instanceof RequestMapping) { - $this->registerRequestMapping($method_anno, $method_name, $v, $methods_annotations); //TODO: 用symfony的routing重写 + RouteManager::importRouteByAnnotation($method_anno, $method_name, $v, $methods_annotations); } elseif ($method_anno instanceof Middleware) { $this->middleware_map[$method_anno->class][$method_anno->method][] = $method_anno->middleware; } @@ -121,11 +122,6 @@ class AnnotationParser } } } - - //预处理4:生成路由树(换成symfony后就不需要了) - $tree = $this->genTree($this->req_mapping); - $this->req_mapping = $tree[0]; - Console::debug("解析注解完毕!"); } @@ -175,109 +171,6 @@ class AnnotationParser //private function below - private function registerRequestMapping(RequestMapping $vss, $method, $class, $methods_annotations) { - $prefix = ''; - foreach ($methods_annotations as $annotation) { - if ($annotation instanceof Controller) { - $prefix = $annotation->prefix; - break; - } - } - $array = $this->req_mapping; - $uid = count($array); - $prefix_exp = explode("/", $prefix); - $route_exp = explode("/", $vss->route); - foreach ($prefix_exp as $k => $v) { - if ($v == "" || $v == ".." || $v == ".") { - unset($prefix_exp[$k]); - } - } - foreach ($route_exp as $k => $v) { - if ($v == "" || $v == ".." || $v == ".") { - unset($route_exp[$k]); - } - } - if ($prefix_exp == [] && $route_exp == []) { - $array[0]['method'] = $method; - $array[0]['class'] = $class; - $array[0]['request_method'] = $vss->request_method; - $array[0]['route'] = $vss->route; - $this->req_mapping = $array; - return; - } - $pid = 0; - while (($shift = array_shift($prefix_exp)) !== null) { - foreach ($array as $k => $v) { - if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) { - $pid = $v["id"]; - continue 2; - } - } - $array[$uid++] = [ - 'id' => $uid - 1, - 'pid' => $pid, - 'name' => $shift - ]; - $pid = $uid - 1; - } - while (($shift = array_shift($route_exp)) !== null) { - /*if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") { - $p->removeAllRoute(); - Console::info("移除本节点其他所有路由中"); - }*/ - foreach ($array as $k => $v) { - if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) { - $pid = $v["id"]; - continue 2; - } - } - if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") { - foreach ($array as $k => $v) { - if ($pid == $v["id"]) { - $array[$k]["param_route"] = $uid; - } - } - } - $array[$uid++] = [ - 'id' => $uid - 1, - 'pid' => $pid, - 'name' => $shift - ]; - $pid = $uid - 1; - } - $array[$uid - 1]['method'] = $method; - $array[$uid - 1]['class'] = $class; - $array[$uid - 1]['request_method'] = $vss->request_method; - $array[$uid - 1]['route'] = $vss->route; - $this->req_mapping = $array; - } - - /** @noinspection PhpIncludeInspection */ - private function loadAnnotationClasses() { - $class = getAllClasses(WORKING_DIR . "/src/ZM/Annotation/", "ZM\\Annotation"); - foreach ($class as $v) { - $s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php"; - //Console::debug("Requiring annotation " . $s); - require_once $s; - } - $class = getAllClasses(DataProvider::getWorkingDir() . "/src/Custom/Annotation/", "Custom\\Annotation"); - foreach ($class as $v) { - $s = DataProvider::getWorkingDir() . '/src/' . str_replace("\\", "/", $v) . ".php"; - Console::debug("Requiring custom annotation " . $s); - require_once $s; - } - } - - private function genTree($items) { - $tree = array(); - foreach ($items as $item) - if (isset($items[$item['pid']])) - $items[$item['pid']]['son'][] = &$items[$item['id']]; - else - $tree[] = &$items[$item['id']]; - return $tree; - } - private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class) { $result = [ "class" => "\\" . $reflection_class->getName(), diff --git a/src/ZM/Event/ServerEventHandler.php b/src/ZM/Event/ServerEventHandler.php index 2eb28cbd..98324a3c 100644 --- a/src/ZM/Event/ServerEventHandler.php +++ b/src/ZM/Event/ServerEventHandler.php @@ -301,7 +301,7 @@ class ServerEventHandler * @param $request * @param $response */ - public function onRequest($request, $response) { + public function onRequest(?Request $request, ?\Swoole\Http\Response $response) { $response = new Response($response); unset(Context::$context[Co::getCid()]); Console::debug("Calling Swoole \"request\" event from fd=" . $request->fd); diff --git a/src/ZM/Framework.php b/src/ZM/Framework.php index 57a0d755..5698eebf 100644 --- a/src/ZM/Framework.php +++ b/src/ZM/Framework.php @@ -280,8 +280,8 @@ class Framework } break; default: - Console::info("Calculating ".$x); - dump($y); + //Console::info("Calculating ".$x); + //dump($y); break; } } diff --git a/src/ZM/Http/RouteManager.php b/src/ZM/Http/RouteManager.php new file mode 100644 index 00000000..0aa842e7 --- /dev/null +++ b/src/ZM/Http/RouteManager.php @@ -0,0 +1,35 @@ +prefix; + break; + } + } + + $route_name = $prefix."/".$vss->route; + $route = new Route($route_name, ['_class' => $class, '_method' => $method]); + $route->setMethods($vss->request_method); + + self::$routes->add(md5($route_name), $route); + } +} \ No newline at end of file diff --git a/src/ZM/Utils/HttpUtil.php b/src/ZM/Utils/HttpUtil.php index 9e5ac510..85ba1abf 100644 --- a/src/ZM/Utils/HttpUtil.php +++ b/src/ZM/Utils/HttpUtil.php @@ -5,57 +5,47 @@ namespace ZM\Utils; use Co; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Routing\Matcher\UrlMatcher; +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RouteCollection; use ZM\Config\ZMConfig; use ZM\Console\Console; -use ZM\Event\EventManager; use ZM\Http\Response; +use ZM\Http\RouteManager; class HttpUtil { public static function parseUri($request, $response, $uri, &$node, &$params) { - $uri = explode("/", $uri); - $uri = array_diff($uri, ["..", "", "."]); - $node = EventManager::$req_mapping; - $params = []; - while (true) { - $r = array_shift($uri); - if ($r === null) break; - if (($cnt = count($node["son"] ?? [])) == 1) { - if (isset($node["param_route"])) { - foreach ($node["son"] as $k => $v) { - if ($v["id"] == $node["param_route"]) { - $node = $v; - $params[mb_substr($v["name"], 1, -1)] = $r; - continue 2; - } - } - } elseif ($node["son"][0]["name"] == $r) { - $node = $node["son"][0]; - continue; - } - } elseif ($cnt >= 1) { - if (isset($node["param_route"])) { - foreach ($node["son"] as $k => $v) { - if ($v["id"] == $node["param_route"]) { - $node = $v; - $params[mb_substr($v["name"], 1, -1)] = $r; - continue 2; - } - } - } - foreach ($node["son"] as $k => $v) { - if ($v["name"] == $r) { - $node = $v; - continue 2; - } - } - } + $context = new RequestContext(); + $context->setMethod($request->server['request_method']); + + try { + $matcher = new UrlMatcher(RouteManager::$routes ?? new RouteCollection(), $context); + $matched = $matcher->match($uri); + } catch (ResourceNotFoundException $e) { if (ZMConfig::get("global", "static_file_server")["status"]) { HttpUtil::handleStaticPage($request->server["request_uri"], $response); return null; } + $matched = null; + } catch (MethodNotAllowedException $e) { + $matched = null; + } + if ($matched !== null) { + $node = [ + "route" => RouteManager::$routes->get($matched["_route"])->getPath(), + "class" => $matched["_class"], + "method" => $matched["_method"], + "request_method" => $request->server['request_method'] + ]; + unset($matched["_class"], $matched["_method"]); + $params = $matched; + return true; + } else { + return false; } - return !isset($node["route"]) ? false : true; } public static function getHttpCodePage(int $http_code) { @@ -83,9 +73,9 @@ class HttpUtil return true; } if (is_dir($path)) { - if(mb_substr($uri, -1, 1) != "/") { + if (mb_substr($uri, -1, 1) != "/") { Console::info("[302] " . $uri); - $response->redirect($uri."/", 302); + $response->redirect($uri . "/", 302); return true; } foreach ($base_index as $vp) { diff --git a/test/test.php b/test/test.php index 13ae52ed..13ce93ce 100644 --- a/test/test.php +++ b/test/test.php @@ -2,13 +2,17 @@ require __DIR__ . "/../vendor/autoload.php"; +use Symfony\Component\Routing\Exception\MethodNotAllowedException; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; - +$root = new RouteCollection(); $route = new Route('/foo', array('controller' => 'MyController')); $routes = new RouteCollection(); + + $routes->add('route_name', $route); @@ -35,30 +39,37 @@ $routes->add('date', new Route( array() // methods )); + + $route = new Route('/archive/test'); $routes->add('qwerty', $route); -$route = new Route('/'); +$route = new Route('/{aas}/{test}', ['_class' => stdClass::class, '_method' => 'foo'],[],["class" => stdClass::class]); $routes->add('root', $route); $context = new RequestContext(); -$matcher = new UrlMatcher($routes, $context); +//$root->addCollection($routes); +$matcher = new UrlMatcher($root, $context); +$root->addCollection($routes); +dump($root->all()); //$parameters = $matcher->match('/test/foo');var_dump($parameters); - -$parameters = $matcher->match('/archive/2012-01'); -var_dump($parameters); // array( // 'controller' => 'showArchive', // 'month' => '2012-01', // 'subdomain' => 'www', // '_route' => ... // ) +try { + $parameters = $matcher->match('/fooss/%20'); + var_dump($parameters); +} catch (ResourceNotFoundException $e) { + echo $e->getMessage().PHP_EOL; +} catch (MethodNotAllowedException $e) { +} -$parameters = $matcher->match('/'); -var_dump($parameters); $sub = new RouteCollection();