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

293 lines
11 KiB
PHP
Raw Normal View History

2020-03-02 16:14:20 +08:00
<?php
declare(strict_types=1);
2020-03-02 16:14:20 +08:00
namespace ZM\Annotation;
2020-08-31 10:11:06 +08:00
use Doctrine\Common\Annotations\AnnotationReader;
use Koriym\Attributes\AttributeReader;
use Koriym\Attributes\DualReader;
2020-03-02 16:14:20 +08:00
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use Symfony\Component\Routing\RouteCollection;
use ZM\Annotation\Http\Controller;
use ZM\Annotation\Http\Route;
use ZM\Annotation\Interfaces\ErgodicAnnotation;
2020-03-02 16:14:20 +08:00
use ZM\Annotation\Interfaces\Level;
use ZM\Annotation\Middleware\HandleAfter;
use ZM\Annotation\Middleware\HandleBefore;
use ZM\Annotation\Middleware\HandleException;
use ZM\Annotation\Middleware\Middleware;
use ZM\Annotation\Middleware\MiddlewareClass;
use ZM\Config\ZMConfig;
use ZM\Exception\ConfigException;
use ZM\Store\FileSystem;
use ZM\Store\InternalGlobals;
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 = [];
2020-09-29 15:07:43 +08:00
private $middlewares = [];
2020-08-31 10:11:06 +08:00
2022-04-03 01:47:38 +08:00
/** @var null|AnnotationReader|DualReader */
private $reader;
2020-09-29 15:07:43 +08:00
private $req_mapping = [];
/**
* AnnotationParser constructor.
*/
public function __construct()
{
2020-08-31 10:11:06 +08:00
$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
* @throws ConfigException
2020-08-31 10:11:06 +08:00
*/
public function parseAll()
{
2020-09-29 15:07:43 +08:00
foreach ($this->path_list as $path) {
2022-06-08 23:11:17 +08:00
logger()->debug('parsing annotation in ' . $path[0] . ':' . $path[1]);
$all_class = FileSystem::getClassesPsr4($path[0], $path[1]);
$conf = ZMConfig::get('global.runtime.annotation_reader_ignore');
if (isset($conf['name']) && is_array($conf['name'])) {
foreach ($conf['name'] as $v) {
AnnotationReader::addGlobalIgnoredName($v);
}
}
if (isset($conf['namespace']) && is_array($conf['namespace'])) {
foreach ($conf['namespace'] as $v) {
AnnotationReader::addGlobalIgnoredNamespace($v);
}
}
AnnotationReader::addGlobalIgnoredName('mixin');
$this->reader = new DualReader(new AnnotationReader(), new AttributeReader());
2020-08-31 10:11:06 +08:00
foreach ($all_class as $v) {
2022-06-08 23:11:17 +08:00
logger()->debug('正在检索 ' . $v);
2022-03-29 00:46:17 +08:00
2020-08-31 10:11:06 +08:00
$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);
// 这段为新加的: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
// 生成主树
$this->annotation_map[$v]['class_annotations'] = $class_annotations;
$this->annotation_map[$v]['methods'] = $methods;
2020-08-31 10:11:06 +08:00
foreach ($methods as $method) {
$this->annotation_map[$v]['methods_annotations'][$method->getName()] = $this->reader->getMethodAnnotations($method);
2020-08-31 10:11:06 +08:00
}
foreach ($this->annotation_map[$v]['class_annotations'] as $vs) {
2020-09-29 15:07:43 +08:00
$vs->class = $v;
// 预处理1将适用于每一个函数的注解到类注解重新注解到每个函数下面
2022-04-02 23:37:22 +08:00
if (($vs instanceof ErgodicAnnotation) && ($vs instanceof AnnotationBase)) {
foreach (($this->annotation_map[$v]['methods'] ?? []) as $method) {
2020-09-29 15:07:43 +08:00
$copy = clone $vs;
$copy->method = $method->getName();
$this->annotation_map[$v]['methods_annotations'][$method->getName()][] = $copy;
2020-09-29 15:07:43 +08:00
}
}
// 预处理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;
}
if ($vs instanceof MiddlewareClass) {
// 注册中间件本身的类,标记到 middlewares 属性中
2022-06-08 23:11:17 +08:00
logger()->debug('正在注册中间件 ' . $reflection_class->getName());
2020-09-29 15:07:43 +08:00
$rs = $this->registerMiddleware($vs, $reflection_class);
$this->middlewares[$rs['name']] = $rs;
}
2020-05-08 16:37:38 +08:00
}
2020-09-29 15:07:43 +08:00
2021-11-16 15:41:01 +08:00
$inserted = [];
// 预处理3处理每个函数上面的特殊注解就是需要操作一些东西的
foreach (($this->annotation_map[$v]['methods_annotations'] ?? []) as $method_name => $methods_annotations) {
2020-09-29 15:07:43 +08:00
foreach ($methods_annotations as $method_anno) {
/* @var AnnotationBase $method_anno */
2020-09-29 15:07:43 +08:00
$method_anno->class = $v;
$method_anno->method = $method_name;
if (!($method_anno instanceof Middleware) && ($middlewares = ZMConfig::get('global.global_middleware_binding')[get_class($method_anno)] ?? []) !== []) {
2021-11-16 15:41:01 +08:00
if (!isset($inserted[$v][$method_name])) {
// 在这里在其他中间件前插入插入全局的中间件
foreach ($middlewares as $middleware) {
$mid_class = new Middleware($middleware);
2021-11-16 15:41:01 +08:00
$mid_class->class = $v;
$mid_class->method = $method_name;
$this->middleware_map[$v][$method_name][] = $mid_class;
}
$inserted[$v][$method_name] = true;
}
} elseif ($method_anno instanceof Route) {
$this->addRouteAnnotation($method_anno, $method_name, $v, $methods_annotations);
2020-09-29 15:07:43 +08:00
} elseif ($method_anno instanceof Middleware) {
2021-07-04 15:45:30 +08:00
$this->middleware_map[$method_anno->class][$method_anno->method][] = $method_anno;
} else {
AnnotationMap::$_map[$method_anno->class][$method_anno->method][] = $method_anno;
2020-08-31 10:11:06 +08:00
}
}
2020-09-29 15:07:43 +08:00
}
2020-03-02 16:14:20 +08:00
}
}
2022-06-08 23:11:17 +08:00
logger()->debug('解析注解完毕!');
2020-08-31 10:11:06 +08:00
}
public function generateAnnotationEvents(): array
{
2020-09-29 15:07:43 +08:00
$o = [];
2021-06-16 00:17:30 +08:00
foreach ($this->annotation_map as $obj) {
2021-11-16 15:41:01 +08:00
// 这里的ErgodicAnnotation是为了解决类上的注解可穿透到方法上的问题
foreach (($obj['class_annotations'] ?? []) as $class_annotation) {
if ($class_annotation instanceof ErgodicAnnotation) {
continue;
}
$o[get_class($class_annotation)][] = $class_annotation;
2020-09-29 15:07:43 +08:00
}
foreach (($obj['methods_annotations'] ?? []) as $methods_annotations) {
2020-09-29 15:07:43 +08:00
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);
}
return $o;
2020-03-02 16:14:20 +08:00
}
public function getMiddlewares(): array
{
return $this->middlewares;
}
2020-03-02 16:14:20 +08:00
public function getMiddlewareMap(): array
{
return $this->middleware_map;
}
2020-09-29 15:07:43 +08:00
public function getReqMapping(): array
{
return $this->req_mapping;
}
2020-09-29 15:07:43 +08:00
/**
2022-04-02 23:37:22 +08:00
* @param string $path 注册解析注解的路径
* @param string $indoor_name 起始命名空间的名称
2020-09-29 15:07:43 +08:00
*/
2022-04-02 23:37:22 +08:00
public function addRegisterPath(string $path, string $indoor_name)
{
logger()->debug('Add register path: ' . $path . ' => ' . $indoor_name);
$this->path_list[] = [$path, $indoor_name];
}
2020-08-31 10:11:06 +08:00
2021-09-01 14:14:00 +08:00
/**
2022-04-02 23:37:22 +08:00
* @param array $events 需要排序的
* @param string $class_name 排序的类名
* @param string $prefix 前缀
* @internal 用于 level 排序
2021-09-01 14:14:00 +08:00
*/
2022-04-02 23:37:22 +08:00
public function sortByLevel(array &$events, string $class_name, string $prefix = '')
{
2020-09-29 15:07:43 +08:00
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
}
2021-09-01 14:14:00 +08:00
public function getUsedTime()
{
return microtime(true) - $this->start_time;
}
// private function below
private function registerMiddleware(MiddlewareClass $vs, ReflectionClass $reflection_class): array
{
$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 HandleBefore) {
$result['before'] = $vss->getName();
}
if ($vsss instanceof HandleAfter) {
$result['after'] = $vss->getName();
}
if ($vsss instanceof HandleException) {
$result['exceptions'][$vsss->class_name] = $vss->getName();
}
}
}
return $result;
}
private function addRouteAnnotation(Route $vss, $method, $class, $methods_annotations)
{
if (InternalGlobals::$routes === null) {
InternalGlobals::$routes = new RouteCollection();
}
// 拿到所属方法的类上面有没有控制器的注解
$prefix = '';
foreach ($methods_annotations as $annotation) {
if ($annotation instanceof Controller) {
$prefix = $annotation->prefix;
break;
}
}
$tail = trim($vss->route, '/');
$route_name = $prefix . ($tail === '' ? '' : '/') . $tail;
logger()->debug('添加路由:' . $route_name);
$route = new \Symfony\Component\Routing\Route($route_name, ['_class' => $class, '_method' => $method]);
$route->setMethods($vss->request_method);
InternalGlobals::$routes->add(md5($route_name), $route);
}
}