zhamao-framework/src/ZM/Annotation/AnnotationParser.php

311 lines
11 KiB
PHP
Raw Normal View History

2020-03-02 16:14:20 +08:00
<?php
namespace ZM\Annotation;
2020-08-31 10:11:06 +08:00
use Doctrine\Common\Annotations\AnnotationReader;
2020-09-29 15:07:43 +08:00
use ZM\Annotation\Interfaces\ErgodicAnnotation;
2020-08-31 10:11:06 +08:00
use ZM\Console\Console;
2020-03-02 16:14:20 +08:00
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
2020-09-29 15:07:43 +08:00
use ZM\Annotation\Http\{After, Before, Controller, HandleException, Middleware, MiddlewareClass, RequestMapping};
2020-03-02 16:14:20 +08:00
use ZM\Annotation\Interfaces\Level;
2020-08-31 10:11:06 +08:00
use ZM\Annotation\Module\Closed;
use ZM\Utils\DataProvider;
2020-03-02 16:14:20 +08:00
class AnnotationParser
{
2020-08-31 10:11:06 +08:00
private $path_list = [];
private $start_time;
private $annotation_map = [];
2020-09-29 15:07:43 +08:00
private $middleware_map = [];
private $middlewares = [];
2020-08-31 10:11:06 +08:00
2020-09-29 15:07:43 +08:00
/** @var null|AnnotationReader */
private $reader = null;
private $req_mapping = [];
/**
* AnnotationParser constructor.
*/
2020-08-31 10:11:06 +08:00
public function __construct() {
$this->start_time = microtime(true);
$this->loadAnnotationClasses();
2020-09-29 15:07:43 +08:00
$this->req_mapping[0] = [
'id' => 0,
'pid' => -1,
'name' => '/'
];
2020-08-31 10:11:06 +08:00
}
/**
* 注册各个模块类的注解和模块level的排序
* @throws ReflectionException
*/
public function registerMods() {
2020-09-29 15:07:43 +08:00
foreach ($this->path_list as $path) {
Console::debug("parsing annotation in ".$path[0]);
2020-08-31 10:11:06 +08:00
$all_class = getAllClasses($path[0], $path[1]);
2020-09-29 15:07:43 +08:00
$this->reader = new AnnotationReader();
2020-08-31 10:11:06 +08:00
foreach ($all_class as $v) {
Console::debug("正在检索 " . $v);
$reflection_class = new ReflectionClass($v);
$methods = $reflection_class->getMethods(ReflectionMethod::IS_PUBLIC);
2020-09-29 15:07:43 +08:00
$class_annotations = $this->reader->getClassAnnotations($reflection_class);
2020-08-31 10:11:06 +08:00
2020-09-29 15:07:43 +08:00
// 这段为新加的:start
2020-08-31 10:11:06 +08:00
//这里将每个类里面所有的类注解、方法注解通通加到一颗大树上,后期解析
/*
$annotation_map: {
Module\Example\Hello: {
class_annotations: [
注解对象1, 注解对象2, ...
],
methods: [
ReflectionMethod, ReflectionMethod, ...
],
methods_annotations: {
foo: [ 注解对象1, 注解对象2, ... ],
bar: [ 注解对象1, 注解对象2, ... ],
}
2020-08-31 10:11:06 +08:00
}
}
*/
2020-09-29 15:07:43 +08:00
// 生成主树
2020-08-31 10:11:06 +08:00
$this->annotation_map[$v]["class_annotations"] = $class_annotations;
$this->annotation_map[$v]["methods"] = $methods;
foreach ($methods as $method) {
2020-09-29 15:07:43 +08:00
$this->annotation_map[$v]["methods_annotations"][$method->getName()] = $this->reader->getMethodAnnotations($method);
2020-08-31 10:11:06 +08:00
}
2020-09-29 15:07:43 +08:00
foreach ($this->annotation_map[$v]["class_annotations"] as $ks => $vs) {
$vs->class = $v;
//预处理1将适用于每一个函数的注解到类注解重新注解到每个函数下面
if ($vs instanceof ErgodicAnnotation) {
foreach ($this->annotation_map[$v]["methods"] as $method) {
$copy = clone $vs;
$copy->method = $method->getName();
$this->annotation_map[$v]["methods_annotations"][$method->getName()][] = $copy;
}
}
//预处理2处理 class 下面的注解
2020-08-31 10:11:06 +08:00
if ($vs instanceof Closed) {
2020-09-29 15:07:43 +08:00
unset($this->annotation_map[$v]);
2020-08-31 10:11:06 +08:00
continue 2;
} elseif ($vs instanceof MiddlewareClass) {
Console::verbose("正在注册中间件 " . $reflection_class->getName());
2020-09-29 15:07:43 +08:00
$rs = $this->registerMiddleware($vs, $reflection_class);
$this->middlewares[$rs["name"]] = $rs;
2020-03-25 18:35:16 +08:00
}
2020-03-02 16:14:20 +08:00
}
2020-09-29 15:07:43 +08:00
//预处理3处理每个函数上面的特殊注解就是需要操作一些东西的
foreach ($this->annotation_map[$v]["methods_annotations"] as $method_name => $methods_annotations) {
foreach ($methods_annotations as $method_anno) {
/** @var AnnotationBase $method_anno */
$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重写
} elseif ($method_anno instanceof Middleware) {
$this->middleware_map[$method_anno->class][$method_anno->method][] = $method_anno->middleware;
}
2020-08-31 10:11:06 +08:00
}
2020-09-29 15:07:43 +08:00
}
2020-03-02 16:14:20 +08:00
}
}
2020-08-31 10:11:06 +08:00
2020-09-29 15:07:43 +08:00
//预处理4生成路由树换成symfony后就不需要了
$tree = $this->genTree($this->req_mapping);
$this->req_mapping = $tree[0];
2020-08-31 10:11:06 +08:00
Console::debug("解析注解完毕!");
}
2020-09-29 15:07:43 +08:00
/**
* @return array
*/
public function generateAnnotationEvents() {
$o = [];
foreach ($this->annotation_map as $module => $obj) {
foreach ($obj["class_annotations"] as $class_annotation) {
if ($class_annotation instanceof ErgodicAnnotation) continue;
else $o[get_class($class_annotation)][] = $class_annotation;
}
foreach ($obj["methods_annotations"] as $method_name => $methods_annotations) {
foreach ($methods_annotations as $annotation) {
$o[get_class($annotation)][] = $annotation;
2020-03-02 16:14:20 +08:00
}
}
2020-09-29 15:07:43 +08:00
}
foreach ($o as $k => $v) {
$this->sortByLevel($o, $k);
2020-03-02 16:14:20 +08:00
}
2020-09-29 15:07:43 +08:00
return $o;
2020-03-02 16:14:20 +08:00
}
2020-09-29 15:07:43 +08:00
/**
* @return array
*/
public function getMiddlewares() { return $this->middlewares; }
2020-03-02 16:14:20 +08:00
2020-09-29 15:07:43 +08:00
/**
* @return array
*/
public function getMiddlewareMap() { return $this->middleware_map; }
2020-03-02 16:14:20 +08:00
2020-09-29 15:07:43 +08:00
/**
* @return array
*/
public function getReqMapping() { return $this->req_mapping; }
2020-03-02 16:14:20 +08:00
2020-09-29 15:07:43 +08:00
/**
* @param $path
* @param $indoor_name
*/
public function addRegisterPath($path, $indoor_name) { $this->path_list[] = [$path, $indoor_name]; }
//private function below
2020-03-02 16:14:20 +08:00
2020-09-29 15:07:43 +08:00
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);
2020-03-02 16:14:20 +08:00
$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 == []) {
2020-09-29 15:07:43 +08:00
$array[0]['method'] = $method;
$array[0]['class'] = $class;
$array[0]['request_method'] = $vss->request_method;
2020-11-03 21:02:24 +08:00
$array[0]['route'] = $vss->route;
2020-09-29 15:07:43 +08:00
$this->req_mapping = $array;
2020-03-02 16:14:20 +08:00
return;
}
$pid = 0;
2020-03-02 16:14:20 +08:00
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;
2020-03-02 16:14:20 +08:00
}
while (($shift = array_shift($route_exp)) !== null) {
/*if (mb_substr($shift, 0, 1) == "{" && mb_substr($shift, -1, 1) == "}") {
2020-03-02 16:14:20 +08:00
$p->removeAllRoute();
Console::info("移除本节点其他所有路由中");
}*/
foreach ($array as $k => $v) {
if ($v["name"] == $shift && $pid == ($v["pid"] ?? -1)) {
$pid = $v["id"];
continue 2;
}
2020-03-02 16:14:20 +08:00
}
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;
2020-03-02 16:14:20 +08:00
}
2020-09-29 15:07:43 +08:00
$array[$uid - 1]['method'] = $method;
$array[$uid - 1]['class'] = $class;
$array[$uid - 1]['request_method'] = $vss->request_method;
2020-09-29 15:07:43 +08:00
$array[$uid - 1]['route'] = $vss->route;
$this->req_mapping = $array;
2020-03-02 16:14:20 +08:00
}
2020-09-29 15:07:43 +08:00
/** @noinspection PhpIncludeInspection */
2020-08-31 10:11:06 +08:00
private function loadAnnotationClasses() {
2020-03-02 16:14:20 +08:00
$class = getAllClasses(WORKING_DIR . "/src/ZM/Annotation/", "ZM\\Annotation");
foreach ($class as $v) {
$s = WORKING_DIR . '/src/' . str_replace("\\", "/", $v) . ".php";
2020-09-29 15:07:43 +08:00
//Console::debug("Requiring annotation " . $s);
2020-03-02 16:14:20 +08:00
require_once $s;
}
2020-05-02 23:27:26 +08:00
$class = getAllClasses(DataProvider::getWorkingDir() . "/src/Custom/Annotation/", "Custom\\Annotation");
2020-03-02 16:14:20 +08:00
foreach ($class as $v) {
2020-05-02 23:27:26 +08:00
$s = DataProvider::getWorkingDir() . '/src/' . str_replace("\\", "/", $v) . ".php";
Console::debug("Requiring custom annotation " . $s);
2020-03-02 16:14:20 +08:00
require_once $s;
}
}
2020-09-29 15:07:43 +08:00
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;
}
2020-09-29 15:07:43 +08:00
private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class) {
$result = [
"class" => "\\" . $reflection_class->getName(),
"name" => $vs->name
];
foreach ($reflection_class->getMethods() as $vss) {
$method_annotations = $this->reader->getMethodAnnotations($vss);
foreach ($method_annotations as $vsss) {
if ($vsss instanceof Before) $result["before"] = $vss->getName();
if ($vsss instanceof After) $result["after"] = $vss->getName();
if ($vsss instanceof HandleException) {
$result["exceptions"][$vsss->class_name] = $vss->getName();
}
2020-05-10 18:25:51 +08:00
}
2020-09-29 15:07:43 +08:00
}
return $result;
}
2020-08-31 10:11:06 +08:00
2020-09-29 15:07:43 +08:00
private function sortByLevel(&$events, string $class_name, $prefix = "") {
if (is_a($class_name, Level::class, true)) {
$class_name .= $prefix;
usort($events[$class_name], function ($a, $b) {
$left = $a->level;
$right = $b->level;
return $left > $right ? -1 : ($left == $right ? 0 : 1);
});
}
2020-08-31 10:11:06 +08:00
}
}