Support setting multiple annotations by inheriting AbstractMultipleAnnotation, such as @Middleware. (#3791)

Co-authored-by: assert <zhangchengming@kkguan.com>
Co-authored-by: 李铭昕 <715557344@qq.com>
This commit is contained in:
张城铭 2021-07-09 17:48:39 +08:00 committed by GitHub
parent aa269a9d72
commit 29fca4319b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 178 additions and 28 deletions

View File

@ -65,6 +65,7 @@
- [#3743](https://github.com/hyperf/hyperf/pull/3743) Support custom register for service governance.
- [#3753](https://github.com/hyperf/hyperf/pull/3753) Support long pulling mode for Apollo Client.
- [#3759](https://github.com/hyperf/hyperf/pull/3759) Added `rpc-multiplex` component.
- [#3791](https://github.com/hyperf/hyperf/pull/3791) Support setting multiple annotations by inheriting `AbstractMultipleAnnotation`, such as `@Middleware`.
## Optimized

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Di\Annotation;
abstract class AbstractMultipleAnnotation extends AbstractAnnotation
{
public function collectClass(string $className): void
{
$annotation = AnnotationCollector::getClassAnnotation($className, static::class);
AnnotationCollector::collectClass($className, static::class, $this->formatAnnotation($annotation));
}
public function collectMethod(string $className, ?string $target): void
{
$annotation = AnnotationCollector::getClassMethodAnnotation($className, $target)[static::class] ?? null;
AnnotationCollector::collectMethod($className, $target, static::class, $this->formatAnnotation($annotation));
}
public function collectProperty(string $className, ?string $target): void
{
$annotation = AnnotationCollector::getClassPropertyAnnotation($className, $target)[static::class] ?? null;
AnnotationCollector::collectProperty($className, $target, static::class, $this->formatAnnotation($annotation));
}
protected function formatAnnotation(?MultipleAnnotation $annotation): MultipleAnnotation
{
if ($annotation instanceof MultipleAnnotation) {
return $annotation->insert($this);
}
return new MultipleAnnotation($this);
}
}

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Di\Annotation;
use Hyperf\Di\Exception\AnnotationException;
class MultipleAnnotation implements MultipleAnnotationInterface
{
/**
* @var AnnotationInterface[]
*/
protected $annotations = [];
/**
* @var string
*/
protected $className;
public function __construct(AnnotationInterface $annotation)
{
$this->annotations = [$annotation];
$this->className = get_class($annotation);
}
public function __get(string $name)
{
if (count($this->annotations) > 1) {
throw new AnnotationException('MultipleAnnotation[' . $this->className() . '] has more than one annotations.');
}
return $this->annotations[0]->{$name};
}
public function className(): string
{
return $this->className;
}
public function insert(AnnotationInterface $annotation)
{
if (! $annotation instanceof $this->className) {
throw new AnnotationException(get_class($annotation) . ' must instanceof ' . $this->className);
}
$this->annotations[] = $annotation;
return $this;
}
public function toAnnotations(): array
{
return $this->annotations;
}
public function collectClass(string $className): void
{
throw new AnnotationException('MultipleAnnotation[' . $this->className() . '] does not support collectClass()');
}
public function collectMethod(string $className, ?string $target): void
{
throw new AnnotationException('MultipleAnnotation[' . $this->className() . '] does not support collectMethod()');
}
public function collectProperty(string $className, ?string $target): void
{
throw new AnnotationException('MultipleAnnotation[' . $this->className() . '] does not support collectProperty()');
}
}

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Di\Annotation;
use Hyperf\Di\Exception\AnnotationException;
interface MultipleAnnotationInterface extends AnnotationInterface
{
public function className(): string;
/**
* @throws AnnotationException
*/
public function insert(AnnotationInterface $annotation);
/**
* @return AnnotationInterface[]
*/
public function toAnnotations(): array;
}

View File

@ -181,9 +181,9 @@ class ProxyManager
$defined = [];
$annotations = AnnotationCollector::get($annotationCollectorKey, []);
foreach ($annotations as $k => $annotation) {
foreach ($annotations as $name => $annotation) {
if (is_object($annotation)) {
$defined[] = $k;
$defined[] = $name;
} else {
$defined = array_merge($defined, array_keys($annotation));
}

View File

@ -12,14 +12,14 @@ declare(strict_types=1);
namespace Hyperf\HttpServer\Annotation;
use Attribute;
use Hyperf\Di\Annotation\AbstractAnnotation;
use Hyperf\Di\Annotation\AbstractMultipleAnnotation;
/**
* @Annotation
* @Target({"ALL"})
*/
#[Attribute]
class Middleware extends AbstractAnnotation
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Middleware extends AbstractMultipleAnnotation
{
/**
* @var string

View File

@ -22,7 +22,7 @@ use Hyperf\Di\Annotation\AbstractAnnotation;
class Middlewares extends AbstractAnnotation
{
/**
* @var array
* @var Middleware[]
*/
public $middlewares = [];
@ -30,10 +30,10 @@ class Middlewares extends AbstractAnnotation
{
if (is_string($value[0])) {
$middlewares = [];
foreach ($value as $key => $middlewareName) {
$middlewares['value'][] = new Middleware($middlewareName);
foreach ($value as $middlewareName) {
$middlewares[] = new Middleware($middlewareName);
}
$value = $middlewares;
$value = ['value' => $middlewares];
}
$this->bindMainProperty('middlewares', $value);
}

View File

@ -16,6 +16,7 @@ use FastRoute\Dispatcher;
use FastRoute\Dispatcher\GroupCountBased;
use FastRoute\RouteParser\Std;
use Hyperf\Di\Annotation\AnnotationCollector;
use Hyperf\Di\Annotation\MultipleAnnotationInterface;
use Hyperf\Di\Exception\ConflictAnnotationException;
use Hyperf\Di\ReflectionManager;
use Hyperf\HttpServer\Annotation\AutoController;
@ -220,27 +221,23 @@ class DispatcherFactory
protected function handleMiddleware(array $metadata): array
{
$hasMiddlewares = isset($metadata[Middlewares::class]);
$hasMiddleware = isset($metadata[Middleware::class]);
if (! $hasMiddlewares && ! $hasMiddleware) {
/** @var null|Middlewares $middlewares */
$middlewares = $metadata[Middlewares::class] ?? null;
/** @var null|MultipleAnnotationInterface $middleware */
$middleware = $metadata[Middleware::class] ?? null;
if ($middleware instanceof MultipleAnnotationInterface) {
$middleware = $middleware->toAnnotations();
}
if (! $middlewares && ! $middleware) {
return [];
}
if ($hasMiddlewares && $hasMiddleware) {
if ($middlewares && $middleware) {
throw new ConflictAnnotationException('Could not use @Middlewares and @Middleware annotation at the same times at same level.');
}
if ($hasMiddlewares) {
// @Middlewares
/** @var Middlewares $middlewares */
$middlewares = $metadata[Middlewares::class];
$result = [];
foreach ($middlewares->middlewares as $middleware) {
$result[] = $middleware->middleware;
}
return $result;
}
// @Middleware
/** @var Middleware $middleware */
$middleware = $metadata[Middleware::class];
return [$middleware->middleware];
return array_map(function (Middleware $middleware) {
return $middleware->middleware;
}, $middlewares ? $middlewares->middlewares : $middleware);
}
}

View File

@ -11,6 +11,7 @@ declare(strict_types=1);
*/
namespace HyperfTest\HttpServer\Router;
use Hyperf\Di\Annotation\MultipleAnnotation;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
@ -88,7 +89,7 @@ class DispatcherFactoryTest extends TestCase
['index' => [
GetMapping::class => new GetMapping(['path' => '/index', 'options' => ['name' => 'index.get', 'id' => 1]]),
PostMapping::class => new PostMapping(['path' => '/index', 'options' => ['name' => 'index.post']]),
Middleware::class => new Middleware(['middleware' => FooMiddleware::class]),
Middleware::class => new MultipleAnnotation(new Middleware(['middleware' => FooMiddleware::class])),
]],
[SetHeaderMiddleware::class]
);