mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-11-29 18:27:44 +08:00
Added annotation ExceptionHandler
. (#1245)
Co-authored-by: ccb <ccb412727@qq.com> Co-authored-by: 李铭昕 <715557344@qq.com>
This commit is contained in:
parent
a6073bf151
commit
bf859acbad
@ -39,6 +39,8 @@
|
||||
|
||||
## Added
|
||||
|
||||
- [#1245](https://github.com/hyperf/hyperf/pull/1245) Added Annotation `ExceptionHandler`.
|
||||
- [#1245](https://github.com/hyperf/hyperf/pull/1245) Exception handler's config and annotation support priority.
|
||||
- [#1819](https://github.com/hyperf/hyperf/pull/1819) Added `hyperf/signal` component.
|
||||
- [#1844](https://github.com/hyperf/hyperf/pull/1844) Support type `\DateInterval` for `ttl` in `model-cache`.
|
||||
- [#1855](https://github.com/hyperf/hyperf/pull/1855) Added `ConstantFrequency` to flush one connection, when it is idle connection for the interval of time.
|
||||
|
31
src/exception-handler/src/Annotation/ExceptionHandler.php
Normal file
31
src/exception-handler/src/Annotation/ExceptionHandler.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\ExceptionHandler\Annotation;
|
||||
|
||||
use Hyperf\Di\Annotation\AbstractAnnotation;
|
||||
|
||||
/**
|
||||
* @Annotation
|
||||
* @Target({"CLASS"})
|
||||
*/
|
||||
class ExceptionHandler extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $server = 'http';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $priority = 0;
|
||||
}
|
@ -13,6 +13,7 @@ namespace Hyperf\ExceptionHandler;
|
||||
|
||||
use Hyperf\ExceptionHandler\Formatter\DefaultFormatter;
|
||||
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
|
||||
use Hyperf\ExceptionHandler\Listener\ExceptionHandlerListener;
|
||||
|
||||
class ConfigProvider
|
||||
{
|
||||
@ -22,6 +23,9 @@ class ConfigProvider
|
||||
'dependencies' => [
|
||||
FormatterInterface::class => DefaultFormatter::class,
|
||||
],
|
||||
'listeners' => [
|
||||
ExceptionHandlerListener::class,
|
||||
],
|
||||
'annotations' => [
|
||||
'scan' => [
|
||||
'paths' => [
|
||||
|
@ -37,6 +37,7 @@ class ExceptionHandlerDispatcher extends AbstractDispatcher
|
||||
*/
|
||||
[$throwable, $handlers] = $params;
|
||||
$response = Context::get(ResponseInterface::class);
|
||||
|
||||
foreach ($handlers as $handler) {
|
||||
if (! $this->container->has($handler)) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid exception handler %s.', $handler));
|
||||
|
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\ExceptionHandler\Listener;
|
||||
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Di\Annotation\AnnotationCollector;
|
||||
use Hyperf\Event\Contract\ListenerInterface;
|
||||
use Hyperf\ExceptionHandler\Annotation\ExceptionHandler;
|
||||
use Hyperf\Framework\Event\BootApplication;
|
||||
use SplPriorityQueue;
|
||||
|
||||
class ExceptionHandlerListener implements ListenerInterface
|
||||
{
|
||||
const HANDLER_KEY = 'exceptions.handler';
|
||||
|
||||
/**
|
||||
* @var ConfigInterface
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $serial = PHP_INT_MAX;
|
||||
|
||||
public function __construct(ConfigInterface $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function listen(): array
|
||||
{
|
||||
return [
|
||||
BootApplication::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function process(object $event)
|
||||
{
|
||||
$queue = new SplPriorityQueue();
|
||||
$handlers = $this->config->get(self::HANDLER_KEY, []);
|
||||
foreach ($handlers as $server => $items) {
|
||||
foreach ($items as $handler => $priority) {
|
||||
if (! is_numeric($priority)) {
|
||||
$handler = $priority;
|
||||
$priority = 0;
|
||||
}
|
||||
$queue->insert([$server, $handler], [$priority, $this->serial--]);
|
||||
}
|
||||
}
|
||||
|
||||
$annotations = AnnotationCollector::getClassesByAnnotation(ExceptionHandler::class);
|
||||
/**
|
||||
* @var string $handler
|
||||
* @var ExceptionHandler $annotation
|
||||
*/
|
||||
foreach ($annotations as $handler => $annotation) {
|
||||
$queue->insert([$annotation->server, $handler], [$annotation->priority, $this->serial--]);
|
||||
}
|
||||
|
||||
$this->config->set(self::HANDLER_KEY, $this->formatExceptionHandlers($queue));
|
||||
}
|
||||
|
||||
protected function formatExceptionHandlers(SplPriorityQueue $queue): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($queue as $item) {
|
||||
[$server, $handler] = $item;
|
||||
$result[$server][] = $handler;
|
||||
$result[$server] = array_values(array_unique($result[$server]));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
116
src/exception-handler/tests/ExceptionHandlerListenerTest.php
Normal file
116
src/exception-handler/tests/ExceptionHandlerListenerTest.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://doc.hyperf.io
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace HyperfTest\ExceptionHandler;
|
||||
|
||||
use Hyperf\Config\Config;
|
||||
use Hyperf\Di\Annotation\AnnotationCollector;
|
||||
use Hyperf\ExceptionHandler\Annotation\ExceptionHandler;
|
||||
use Hyperf\ExceptionHandler\Listener\ExceptionHandlerListener;
|
||||
use Mockery;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class ExceptionHandlerListenerTest extends TestCase
|
||||
{
|
||||
protected function tearDown()
|
||||
{
|
||||
Mockery::close();
|
||||
AnnotationCollector::clear();
|
||||
}
|
||||
|
||||
public function testConfig()
|
||||
{
|
||||
$config = new Config([
|
||||
'exceptions' => [
|
||||
'handler' => [
|
||||
'http' => $http = [
|
||||
'Foo', 'Bar',
|
||||
],
|
||||
'ws' => $ws = [
|
||||
'Foo', 'Tar', 'Bar',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
$listener = new ExceptionHandlerListener($config);
|
||||
$listener->process(new \stdClass());
|
||||
$this->assertSame($http, $config->get('exceptions.handler', [])['http']);
|
||||
$this->assertSame($ws, $config->get('exceptions.handler', [])['ws']);
|
||||
}
|
||||
|
||||
public function testAnnotation()
|
||||
{
|
||||
$config = new Config([
|
||||
'exceptions' => [
|
||||
'handler' => [
|
||||
'http' => [
|
||||
'Foo', 'Bar',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
AnnotationCollector::collectClass('Bar1', ExceptionHandler::class, new ExceptionHandler(['server' => 'http', 'priority' => 1]));
|
||||
$listener = new ExceptionHandlerListener($config);
|
||||
$listener->process(new \stdClass());
|
||||
$this->assertSame([
|
||||
'http' => [
|
||||
'Bar1', 'Foo', 'Bar',
|
||||
],
|
||||
], $config->get('exceptions.handler', []));
|
||||
}
|
||||
|
||||
public function testAnnotationWithSamePriotity()
|
||||
{
|
||||
$config = new Config([
|
||||
'exceptions' => [
|
||||
'handler' => [
|
||||
'http' => [
|
||||
'Foo', 'Bar',
|
||||
],
|
||||
'ws' => [
|
||||
'Foo',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
AnnotationCollector::collectClass('Bar1', ExceptionHandler::class, new ExceptionHandler(['server' => 'http', 'priority' => 0]));
|
||||
AnnotationCollector::collectClass('Bar', ExceptionHandler::class, new ExceptionHandler(['server' => 'ws', 'priority' => 1]));
|
||||
$listener = new ExceptionHandlerListener($config);
|
||||
$listener->process(new \stdClass());
|
||||
$this->assertEquals(['Foo', 'Bar', 'Bar1'], $config->get('exceptions.handler', [])['http']);
|
||||
$this->assertEquals(['Bar', 'Foo'], $config->get('exceptions.handler', [])['ws']);
|
||||
}
|
||||
|
||||
public function testTheSameHandler()
|
||||
{
|
||||
$config = new Config([
|
||||
'exceptions' => [
|
||||
'handler' => [
|
||||
'http' => [
|
||||
'Foo', 'Bar', 'Bar', 'Tar',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
AnnotationCollector::collectClass('Tar', ExceptionHandler::class, new ExceptionHandler(['server' => 'http', 'priority' => 1]));
|
||||
$listener = new ExceptionHandlerListener($config);
|
||||
$listener->process(new \stdClass());
|
||||
$this->assertSame([
|
||||
'http' => [
|
||||
'Tar', 'Foo', 'Bar',
|
||||
],
|
||||
], $config->get('exceptions.handler', []));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user