From cb07e0e85f843da5099177a634a0fc910271dc8d Mon Sep 17 00:00:00 2001 From: Yurun Date: Tue, 14 Nov 2023 19:57:22 +0800 Subject: [PATCH] =?UTF-8?q?[3.0]=20=E9=87=8D=E6=9E=84=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=8E=9F=E7=94=9F=E6=9E=9A=E4=B8=BE?= =?UTF-8?q?=20(#648)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 重构 AMQP 枚举 * 重构 pgsql 枚举 * 重构 CronTaskType * 重构 Imi\Cron\Consts\UniqueLevel 枚举 * 重构 Imi\Db\Mysql\Consts\LogicalOperator * 重构 Imi\Db\Mysql\Query\FullText\SearchModifier * 修复 * 重构 Imi\Model\IdGenerator\UUIDGeneratorType * 更新文档 * 修复 * 重构 Imi\Server\WebSocket\Enum::NonControlFrameType 枚举 * PHP 原生枚举深度支持 (#646) * beans 配置注入支持枚举 * InEnum 验证器支持原生枚举 * 修复 * 修复 * 修复一个类有多个Bean名称时,beans 注入的属性值不正确 * 完善测试 * 修复 * 修复 # Conflicts: # phpstan.neon # src/Bean/BeanProxy.php # src/Validate/ValidatorHelper.php * 修复 * 修复 * 调整命名 --- doc/base/config.md | 4 +- doc/base/version/2.1-3.0.md | 14 ++ doc/components/orm/RDModel/definition.md | 8 +- doc/components/struct/enum.md | 4 +- doc/components/task/cron.md | 6 +- doc/container/workerman.md | 4 +- doc/container/workerman/serverConfig.md | 4 +- doc/core/long-connection-distributed.md | 4 +- doc/core/subServer.md | 4 +- src/Bean/BeanFactory.php | 42 ++++-- src/Bean/BeanProxy.php | 120 +++++++++++++----- src/Bean/Container.php | 2 +- .../amqp/example/AMQP/Test/TestConsumer.php | 4 +- src/Components/amqp/src/Base/BaseConsumer.php | 16 +-- .../amqp/src/Enum/ConsumerResult.php | 34 +++-- .../amqp/src/Queue/AMQPQueueDriver.php | 3 +- .../amqp/src/Queue/AMQPQueueDriverHandler.php | 27 ++-- .../amqp/src/Queue/QueueConsumer.php | 5 +- .../amqp/src/Queue/SwooleQueueConsumer.php | 5 +- .../kafka/src/Queue/KafkaQueueDriver.php | 3 +- .../pgsql/src/Db/Query/FullText/TsQuery.php | 11 +- .../pgsql/src/Db/Query/FullText/TsRank.php | 11 +- .../src/Annotation/QueueTypeStructType.php | 20 --- .../queue/src/Driver/IQueueDriver.php | 5 +- .../queue/src/Driver/RedisQueueDriver.php | 65 +++++----- .../src/Driver/RedisStreamQueueDriver.php | 3 +- src/Components/queue/src/Enum/IQueueType.php | 13 ++ src/Components/queue/src/Enum/QueueType.php | 70 +++++----- .../swoole/src/Cron/Consts/CronTaskType.php | 9 +- .../swoole/src/Cron/CronManager.php | 3 +- .../Server/Util/Amqp/AmqpServerConsumer.php | 8 +- .../swoole/src/Server/Util/AmqpServerUtil.php | 4 +- .../src/Server/Util/LocalServerUtil.php | 6 +- .../swoole/src/Server/WebSocket/Server.php | 6 +- .../unit/WebSocketServer/config/config.php | 2 +- .../Server/Gateway/GatewayServer.php | 8 +- .../tests/unit/AppServer/config/config.php | 2 +- .../workerman/src/Server/WebSocket/Server.php | 8 +- .../tests/unit/AppServer/config/config.php | 2 +- src/Cron/Annotation/Cron.php | 3 +- src/Cron/Consts/CronTaskType.php | 6 +- src/Cron/Consts/UniqueLevel.php | 19 ++- src/Cron/Contract/ICronManager.php | 3 +- src/Cron/CronLock.php | 4 +- src/Cron/CronManager.php | 3 +- src/Cron/CronTask.php | 11 +- src/Db/Mysql/Consts/LogicalOperator.php | 23 ++-- .../Mysql/Query/FullText/SearchModifier.php | 23 ++-- src/Db/Query/Traits/TWhereCollector.php | 12 +- src/Model/IdGenerator/UUIDGenerator.php | 13 +- src/Model/IdGenerator/UUIDGeneratorType.php | 14 +- .../WebSocket/Contract/IWebSocketServer.php | 3 +- src/Server/WebSocket/Dispatcher.php | 2 +- .../WebSocket/Enum/NonControlFrameType.php | 19 ++- src/Util/EnumUtil.php | 48 +++++++ src/Validate/ValidatorHelper.php | 17 ++- tests/unit/Component/Bean/EnumBean.php | 38 ++++++ tests/unit/Component/Enum/TestEnumBean.php | 11 ++ .../Component/Enum/TestEnumBeanBacked.php | 11 ++ tests/unit/Component/Model/ArticleId.php | 3 +- tests/unit/Component/Tests/BeanTest.php | 29 +++++ tests/unit/Component/Tests/Util/EnumTest.php | 37 ++++++ .../Component/Tests/ValidatorHelperTest.php | 14 ++ tests/unit/Component/config/config.php | 10 ++ 64 files changed, 610 insertions(+), 335 deletions(-) delete mode 100644 src/Components/queue/src/Annotation/QueueTypeStructType.php create mode 100644 src/Components/queue/src/Enum/IQueueType.php create mode 100644 src/Util/EnumUtil.php create mode 100644 tests/unit/Component/Bean/EnumBean.php create mode 100644 tests/unit/Component/Enum/TestEnumBean.php create mode 100644 tests/unit/Component/Enum/TestEnumBeanBacked.php create mode 100644 tests/unit/Component/Tests/Util/EnumTest.php diff --git a/doc/base/config.md b/doc/base/config.md index 420cfc6617..006cbd3d66 100644 --- a/doc/base/config.md +++ b/doc/base/config.md @@ -147,8 +147,8 @@ return [ // 参考: http://wiki.swoole.com/#/server/setting // 参考: http://wiki.swoole.com/#/websocket_server?id=%e9%80%89%e9%a1%b9 // 参考: http://wiki.swoole.com/#/http_server?id=%e9%85%8d%e7%bd%ae%e9%80%89%e9%a1%b9 - 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::TEXT, // 配置 WebSocket 纯文本通信协议 - // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::BINARY, // 配置 WebSocket 二进制通信协议 + 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Text, // 配置 WebSocket 纯文本通信协议 + // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Binary, // 配置 WebSocket 二进制通信协议 'configs' => [ 'reactor_num' => 8, 'worker_num' => 8, diff --git a/doc/base/version/2.1-3.0.md b/doc/base/version/2.1-3.0.md index fb29d84c6a..5b629b5fbe 100644 --- a/doc/base/version/2.1-3.0.md +++ b/doc/base/version/2.1-3.0.md @@ -69,6 +69,16 @@ return [ * 重构注解类写法 +* 定时任务 `Imi\Cron\Annotation\Cron` 注解的 `unique` 值类型更改为 `\Imi\Cron\Consts\UniqueLevel` 枚举,大小写有所变化 + +### 模型 + +* UUID 发号器的 `type` 类型改为枚举,大小写有所变化 + +### WebSocket + +* 重构 `Imi\Server\WebSocket\Enum::NonControlFrameType` 为枚举 + ### imi-access-control 废弃并移出主仓库,代码仓库: @@ -81,6 +91,10 @@ return [ * 废弃 `Imi\AMQP\Swoole\AMQPSwooleConnection` 客户端类 +* 消费者类 `Imi\AMQP\Base\BaseConsumer::consume()` 方法返回值类型应设置为 `\Imi\AMQP\Enum\ConsumerResult`,且必须返回枚举值 + +* `Imi\Queue\Enum\QueueType` 改为原生注解,如需自定义请编写枚举并实现 `Imi\Queue\Enum\QueueType\IQueueType` 接口 + ### imi-macro 废弃并移出主仓库,代码仓库: diff --git a/doc/components/orm/RDModel/definition.md b/doc/components/orm/RDModel/definition.md index ab6acbf053..3a52aa32f9 100644 --- a/doc/components/orm/RDModel/definition.md +++ b/doc/components/orm/RDModel/definition.md @@ -550,19 +550,19 @@ ID 生成器指定参数: `#[Id(generator: \Imi\Model\IdGenerator\UUIDGenerator::class)]` -`#[Id(generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::TIME])]` +`#[Id(generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::Time])]` -**随机算法:**`#[Id(generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::RANDOM])]` +**随机算法:**`#[Id(generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::Random])]` **MD5、Sha1:** 使用方法基本一样,差别就是 `generatorOptions.type` 值不同。 -`#[Id(index: false, generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::MD5, "ns" => "99e4edaf-8363-466e-bddf-7254db57675c", "nameField" => "名称字段名,该字段值必须唯一,否则会重复"])]` +`#[Id(index: false, generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::Md5, "ns" => "99e4edaf-8363-466e-bddf-7254db57675c", "nameField" => "名称字段名,该字段值必须唯一,否则会重复"])]` > `ns` 必须是一个合法的 UUID -`#[Id(index: false, generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::SHA1, "nsField" => "命名空间字段名", "name" => "直接指定名称"])]` +`#[Id(index: false, generator: \Imi\Model\IdGenerator\UUIDGenerator::class, generatorOptions: ["type" => \Imi\Model\IdGenerator\UUIDGeneratorType::Sha1, "nsField" => "命名空间字段名", "name" => "直接指定名称"])]` > 注意:`ns`、`name` 的值如果一样,生成的 UUID 也会一样!!! diff --git a/doc/components/struct/enum.md b/doc/components/struct/enum.md index 810e0b05b1..de211b7b35 100644 --- a/doc/components/struct/enum.md +++ b/doc/components/struct/enum.md @@ -2,7 +2,9 @@ [toc] -由于 PHP 本身不支持枚举类型,imi 特别基于注解实现了枚举类。 +由于 PHP < 8.1 本身不支持枚举类型,imi 特别基于注解实现了枚举类。 + +> 此功能在 3.0 不会被内置,需要手动安装 `imi-old-enum` 组件。强烈建议使用 PHP 原生枚举! ## 枚举类定义 diff --git a/doc/components/task/cron.md b/doc/components/task/cron.md index 82fa9d2d41..9d41fe5178 100644 --- a/doc/components/task/cron.md +++ b/doc/components/task/cron.md @@ -339,9 +339,9 @@ class TaskProcess implements IProcess **unique:** 定时任务唯一性设置 -当前实例唯一: current -所有实例唯一: all -不唯一: null +当前实例唯一: `\Imi\Cron\Consts\UniqueLevel::Current` +所有实例唯一: `\Imi\Cron\Consts\UniqueLevel::All` +不唯一: `null` **redisPool:** diff --git a/doc/container/workerman.md b/doc/container/workerman.md index b99d8aa025..575f1edd5a 100644 --- a/doc/container/workerman.md +++ b/doc/container/workerman.md @@ -46,8 +46,8 @@ imi v2.0 版本开始,支持运行在 Workerman 环境中。 'namespace' => 'Imi\WorkermanGateway\Test\AppServer\Gateway', 'type' => Imi\WorkermanGateway\Workerman\Server\Type::GATEWAY, 'socketName' => 'websocket://0.0.0.0:8081', // 网关监听的地址 - 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::TEXT, // 配置 WebSocket 纯文本通信协议 - // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::BINARY, // 配置 WebSocket 二进制通信协议 + 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Text, // 配置 WebSocket 纯文本通信协议 + // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Binary, // 配置 WebSocket 二进制通信协议 'configs' => [ 'lanIp' => '127.0.0.1', 'startPort' => 12900, diff --git a/doc/container/workerman/serverConfig.md b/doc/container/workerman/serverConfig.md index e9855e36d1..98ed77e026 100644 --- a/doc/container/workerman/serverConfig.md +++ b/doc/container/workerman/serverConfig.md @@ -47,8 +47,8 @@ return [ 'host' => '0.0.0.0', 'port' => 13002, 'shareWorker' => 'http', // 与名字叫 http 的服务,共享 worker 进程 - 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::TEXT, // 配置 WebSocket 纯文本通信协议 - // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::BINARY, // 配置 WebSocket 二进制通信协议 + 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Text, // 配置 WebSocket 纯文本通信协议 + // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Binary, // 配置 WebSocket 二进制通信协议 'configs' => [ ], ], diff --git a/doc/core/long-connection-distributed.md b/doc/core/long-connection-distributed.md index 853b16caf3..0d2dffc183 100644 --- a/doc/core/long-connection-distributed.md +++ b/doc/core/long-connection-distributed.md @@ -242,8 +242,8 @@ Workerman Gateway 是一个成熟的实现方案,可以实现分布式消息 'namespace' => 'Imi\WorkermanGateway\Test\AppServer\Gateway', 'type' => Imi\WorkermanGateway\Workerman\Server\Type::GATEWAY, 'socketName' => 'websocket://0.0.0.0:13002', - 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::TEXT, // 配置 WebSocket 纯文本通信协议 - // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::BINARY, // 配置 WebSocket 二进制通信协议 + 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Text, // 配置 WebSocket 纯文本通信协议 + // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Binary, // 配置 WebSocket 二进制通信协议 'configs' => [ 'lanIp' => '127.0.0.1', 'startPort' => 12900, diff --git a/doc/core/subServer.md b/doc/core/subServer.md index d9fbe91988..5f2210adb3 100644 --- a/doc/core/subServer.md +++ b/doc/core/subServer.md @@ -32,8 +32,8 @@ http 和 WebSocket 同时做在一个项目中,代码之间没有隔阂,可 'sockType' => SWOOLE_SOCK_TCP, // 同步连接,当连接事件执行完后,才执行 receive 事件。仅 TCP、WebSocket 且 SWOOLE_BASE 模式有效 'syncConnect' => true, - 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::TEXT, // 配置 WebSocket 纯文本通信协议 - // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::BINARY, // 配置 WebSocket 二进制通信协议 + 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Text, // 配置 WebSocket 纯文本通信协议 + // 'nonControlFrameType' => \Imi\Server\WebSocket\Enum\NonControlFrameType::Binary, // 配置 WebSocket 二进制通信协议 // 服务器配置,参数用法同\Swoole\Server->set($configs) 'configs' => [ ], diff --git a/src/Bean/BeanFactory.php b/src/Bean/BeanFactory.php index 06bf103cba..229a2f686e 100644 --- a/src/Bean/BeanFactory.php +++ b/src/Bean/BeanFactory.php @@ -37,8 +37,20 @@ class BeanFactory */ public static function newInstance(string $class, mixed ...$args): mixed { - $object = self::newInstanceNoInit($class, ...$args); - static::initInstance($object, $args); + return static::newBeanInstance($class, null, ...$args); + } + + /** + * 实例化. + * + * @template T + * + * @param class-string $class + */ + public static function newBeanInstance(string $class, ?string $beanName = null, mixed ...$args): mixed + { + $object = static::newInstanceNoInit($class, ...$args); + static::initInstance($object, $args, $beanName); return $object; } @@ -61,7 +73,7 @@ public static function newInstanceNoInit(string $class, mixed ...$args): mixed } else { - if (self::$enableFileCache) + if (static::$enableFileCache) { static::parseEvalName($class, $fileName, $className); if (is_file($fileName)) @@ -100,8 +112,20 @@ public static function newInstanceNoInit(string $class, mixed ...$args): mixed */ public static function newInstanceEx(string $class, array $args = []): mixed { - $object = self::newInstanceExNoInit($class, $args, $resultArgs); - static::initInstance($object, $resultArgs); + return static::newBeanInstanceEx($class, null, $args); + } + + /** + * 增强实例化. + * + * @template T + * + * @param class-string $class + */ + public static function newBeanInstanceEx(string $class, ?string $beanName = null, array $args = []): mixed + { + $object = static::newInstanceExNoInit($class, $args, $resultArgs); + static::initInstance($object, $resultArgs, $beanName); return $object; } @@ -135,16 +159,16 @@ public static function newInstanceExNoInit(string $class, array $args, ?array &$ } } - return self::newInstanceNoInit($class, ...$resultArgs); + return static::newInstanceNoInit($class, ...$resultArgs); } /** * 初始化Bean对象 */ - public static function initInstance(object $object, array $args = []): void + public static function initInstance(object $object, array $args = [], ?string $beanName = null): void { - $class = self::getObjectClass($object); - BeanProxy::injectProps($object, $class); + $class = static::getObjectClass($object); + BeanProxy::injectProps($object, $class, false, $beanName); $ref = ReflectionContainer::getClassReflection($class); if ($ref->hasMethod('__init')) { diff --git a/src/Bean/BeanProxy.php b/src/Bean/BeanProxy.php index d0856bb6e8..affd0baa66 100644 --- a/src/Bean/BeanProxy.php +++ b/src/Bean/BeanProxy.php @@ -17,6 +17,7 @@ use Imi\Aop\JoinPoint; use Imi\Aop\Model\AopItem; use Imi\Config; +use Imi\Util\EnumUtil; use Imi\Util\Imi; class BeanProxy @@ -135,9 +136,9 @@ public static function &call(object $object, string $className, string $method, /** * 注入属性. */ - public static function injectProps(object $object, string $className, bool $reInit = false): void + public static function injectProps(object $object, string $className, bool $reInit = false, ?string $beanName = null): void { - [$injects, $configs] = static::getInjects($className); + [$injects, $configs] = static::getInjects($className, $beanName); if (!$injects && !$configs) { return; @@ -169,6 +170,44 @@ public static function injectProps(object $object, string $className, bool $reIn { $propRef = $refClass->getProperty($name); $propRef->setAccessible(true); + if ($propRef->hasType()) + { + $type = $propRef->getType(); + foreach ((static function () use ($type) { + if ($type instanceof \ReflectionNamedType) + { + if (is_subclass_of($typeName = $type->getName(), \UnitEnum::class)) + { + yield $typeName; + } + } + elseif ($type instanceof \ReflectionUnionType) + { + foreach ($type->getTypes() as $type) + { + if (is_subclass_of($typeName = $type->getName(), \UnitEnum::class)) + { + yield $typeName; + } + } + } + })() as $enumType) + { + if (is_subclass_of($enumType, \BackedEnum::class)) + { + $case = $enumType::tryFrom($value); + } + else + { + $case = EnumUtil::tryFromName($enumType, $value); + } + if ($case) + { + $value = $case; + break; + } + } + } $propRef->setValue($object, $value); } } @@ -177,37 +216,54 @@ public static function injectProps(object $object, string $className, bool $reIn /** * 获取注入属性的配置们. */ - public static function getConfigInjects(string $className): array + public static function getConfigInjects(string $className, ?string $beanName = null): array { - // 配置文件注入 - $beanData = BeanManager::get($className); - if ($beanData) - { - $beanName = $beanData['beanName']; - } - else - { - $beanName = $className; - } - $beans = Config::get('@currentServer.beans'); - if (isset($beans[$beanName])) + $originBeanName = $beanName; + $count = 2; + while ($count--) { - return $beans[$beanName]; - } - elseif ($beanName !== $className && isset($beans[$className])) - { - return $beans[$className]; - } - else - { - $beans = Config::get('@app.beans'); - if (isset($beans[$beanName])) + // 配置文件注入 + if (null === $beanName) + { + $beanData = BeanManager::get($className); + if ($beanData) + { + $beanName = $beanData['beanName']; + } + else + { + $beanName = $className; + } + } + $serverBeans ??= Config::get('@currentServer.beans'); + if (isset($serverBeans[$beanName])) { - return $beans[$beanName]; + return $serverBeans[$beanName]; } - elseif ($beanName !== $className && isset($beans[$className])) + elseif ($beanName !== $className && isset($serverBeans[$className])) + { + return $serverBeans[$className]; + } + else + { + $appBeans ??= Config::get('@app.beans'); + if (isset($appBeans[$beanName])) + { + return $appBeans[$beanName]; + } + elseif ($beanName !== $className && isset($appBeans[$className])) + { + return $appBeans[$className]; + } + } + if (null === $originBeanName) + { + break; + } + else { - return $beans[$className]; + // 下次循环会根据类名尝试获取注入配置 + $beanName = null; } } @@ -219,9 +275,9 @@ public static function getConfigInjects(string $className): array * * 返回:[$annotations, $configs] */ - public static function getInjects(string $className): array + public static function getInjects(string $className, ?string $beanName = null): array { - $configs = static::getConfigInjects($className); + $configs = static::getConfigInjects($className, $beanName); $injects = BeanManager::getPropertyInjects($className); if ($configs && $injects) { @@ -301,9 +357,9 @@ private static function doAspect(string $className, string $method, string $poin /** * 获取注入类属性的值 */ - public static function getInjectValue(string $className, string $propertyName): mixed + public static function getInjectValue(string $className, string $propertyName, ?string $beanName = null): mixed { - [$annotations, $configs] = static::getInjects($className); + [$annotations, $configs] = static::getInjects($className, $beanName); if (isset($configs[$propertyName])) { return $configs[$propertyName]; diff --git a/src/Bean/Container.php b/src/Bean/Container.php index 1d65e01fe2..9bc4601030 100644 --- a/src/Bean/Container.php +++ b/src/Bean/Container.php @@ -163,7 +163,7 @@ private function __newInstance(string $id, array $params, bool $allowStore): mix if ($data['recursion'] ?? true) { // @phpstan-ignore-next-line - BeanFactory::initInstance($object, $params); + BeanFactory::initInstance($object, $params, $originId); if ($stored && $object !== $beanObjects[$originId]) { // 防止类 __init() 方法有协程上下文切换,导致单例被覆盖 diff --git a/src/Components/amqp/example/AMQP/Test/TestConsumer.php b/src/Components/amqp/example/AMQP/Test/TestConsumer.php index f54684388a..bdd7e5730c 100644 --- a/src/Components/amqp/example/AMQP/Test/TestConsumer.php +++ b/src/Components/amqp/example/AMQP/Test/TestConsumer.php @@ -23,11 +23,11 @@ class TestConsumer extends BaseConsumer * * @param \AMQPApp\AMQP\Test\TestMessage $message */ - protected function consume(IMessage $message): mixed + protected function consume(IMessage $message): ConsumerResult { var_dump(__CLASS__, $message->getBody(), $message::class); Redis::set('imi-amqp:consume:1:' . $message->getMemberId(), $message->getBody()); - return ConsumerResult::ACK; + return ConsumerResult::Ack; } } diff --git a/src/Components/amqp/src/Base/BaseConsumer.php b/src/Components/amqp/src/Base/BaseConsumer.php index bd71148b86..9290f2ee09 100644 --- a/src/Components/amqp/src/Base/BaseConsumer.php +++ b/src/Components/amqp/src/Base/BaseConsumer.php @@ -100,7 +100,7 @@ protected function bindConsumer(): void return; } ++$this->messageCount; - $result = ConsumerResult::NACK; + $result = ConsumerResult::Nack; try { /** @var \Imi\AMQP\Message $messageInstance */ @@ -117,7 +117,7 @@ protected function bindConsumer(): void { Log::error($th); - return ConsumerResult::NACK; + return ConsumerResult::Nack; } }); } @@ -134,19 +134,19 @@ protected function bindConsumer(): void { switch ($result) { - case ConsumerResult::ACK: + case ConsumerResult::Ack: $this->channel->basic_ack($message->getDeliveryTag()); break; - case ConsumerResult::NACK: + case ConsumerResult::Nack: $this->channel->basic_nack($message->getDeliveryTag()); break; - case ConsumerResult::NACK_REQUEUE: + case ConsumerResult::NackRequeue: $this->channel->basic_nack($message->getDeliveryTag(), false, true); break; - case ConsumerResult::REJECT: + case ConsumerResult::Reject: $this->channel->basic_reject($message->getDeliveryTag(), false); break; - case ConsumerResult::REJECT_REQUEUE: + case ConsumerResult::RejectRequeue: $this->channel->basic_reject($message->getDeliveryTag(), true); break; } @@ -159,5 +159,5 @@ protected function bindConsumer(): void /** * 消费任务 */ - abstract protected function consume(IMessage $message): mixed; + abstract protected function consume(IMessage $message): ConsumerResult; } diff --git a/src/Components/amqp/src/Enum/ConsumerResult.php b/src/Components/amqp/src/Enum/ConsumerResult.php index 30013739ec..aa9e08023b 100644 --- a/src/Components/amqp/src/Enum/ConsumerResult.php +++ b/src/Components/amqp/src/Enum/ConsumerResult.php @@ -4,37 +4,33 @@ namespace Imi\AMQP\Enum; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - /** * 消费者执行结果. */ -class ConsumerResult extends BaseEnum +enum ConsumerResult: int { - use \Imi\Util\Traits\TStaticClass; - /** - * 用于消息消费成功 + * 确认消息. */ - #[EnumItem(text: '确认消息')] - public const ACK = 1; + case Ack = 1; /** - * 用于消息消费失败. + * 否定消息. */ - #[EnumItem(text: '否定消息')] - public const NACK = 2; + case Nack = 2; /** - * 用于消息消费失败,并重回队列. + * 否定消息,并重回队列. */ - #[EnumItem(text: '否定消息,并重回队列')] - public const NACK_REQUEUE = 3; + case NackRequeue = 3; - #[EnumItem(text: '拒绝消息')] - public const REJECT = 4; + /** + * 拒绝消息. + */ + case Reject = 4; - #[EnumItem(text: '拒绝消息,并重回队列')] - public const REJECT_REQUEUE = 5; + /** + * 拒绝消息,并重回队列. + */ + case RejectRequeue = 5; } diff --git a/src/Components/amqp/src/Queue/AMQPQueueDriver.php b/src/Components/amqp/src/Queue/AMQPQueueDriver.php index 42f06521c9..501bc606ab 100644 --- a/src/Components/amqp/src/Queue/AMQPQueueDriver.php +++ b/src/Components/amqp/src/Queue/AMQPQueueDriver.php @@ -8,6 +8,7 @@ use Imi\Bean\BeanFactory; use Imi\Queue\Contract\IMessage; use Imi\Queue\Driver\IQueueDriver; +use Imi\Queue\Enum\IQueueType; use Imi\Queue\Model\QueueStatus; use Imi\RequestContext; use Imi\Util\Traits\TDataToProperty; @@ -153,7 +154,7 @@ public function delete(IMessage $message): bool /** * {@inheritDoc} */ - public function clear($queueType = null): void + public function clear(?IQueueType $queueType = null): void { $this->getHandler()->clear($queueType); } diff --git a/src/Components/amqp/src/Queue/AMQPQueueDriverHandler.php b/src/Components/amqp/src/Queue/AMQPQueueDriverHandler.php index 6bb7093157..ff15466581 100644 --- a/src/Components/amqp/src/Queue/AMQPQueueDriverHandler.php +++ b/src/Components/amqp/src/Queue/AMQPQueueDriverHandler.php @@ -8,6 +8,7 @@ use Imi\Bean\BeanFactory; use Imi\Queue\Contract\IMessage; use Imi\Queue\Driver\IQueueDriver; +use Imi\Queue\Enum\IQueueType; use Imi\Queue\Enum\QueueType; use Imi\Queue\Exception\QueueException; use Imi\Queue\Model\QueueStatus; @@ -333,7 +334,7 @@ public function pop(float $timeout = 0): ?IMessage } Redis::use(function (\Imi\Redis\RedisHandler $redis) use ($score, $message): void { - $redis->zAdd($this->getRedisQueueKey(QueueType::WORKING), $score, json_encode($message->toArray(), \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); + $redis->zAdd($this->getRedisQueueKey(QueueType::Working), $score, json_encode($message->toArray(), \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); }, $this->redisPoolName, true); return $message; @@ -359,12 +360,12 @@ public function delete(IMessage $message): bool /** * {@inheritDoc} */ - public function clear($queueType = null): void + public function clear(?IQueueType $queueType = null): void { Redis::use(function (\Imi\Redis\RedisHandler $redis) use ($queueType): void { if (null === $queueType) { - $queueTypes = QueueType::getValues(); + $queueTypes = QueueType::cases(); } else { @@ -376,7 +377,7 @@ public function clear($queueType = null): void { switch ($queueType) { - case QueueType::READY: + case QueueType::Ready: // 清空所有 while ($message = $this->pop()) { @@ -387,18 +388,18 @@ public function clear($queueType = null): void $this->consumer->reopen(); $redis->del($this->getRedisQueueKey('deleted')); break; - case QueueType::WORKING: - $redis->del($this->getRedisQueueKey(QueueType::WORKING)); + case QueueType::Working: + $redis->del($this->getRedisQueueKey(QueueType::Working)); break; - case QueueType::FAIL: + case QueueType::Fail: $this->failConsumer->getAMQPChannel()->queue_purge($this->failQueueName); $this->failConsumer->reopen(); break; - case QueueType::TIMEOUT: + case QueueType::Timeout: $this->timeoutConsumer->getAMQPChannel()->queue_purge($this->timeoutQueueName); $this->timeoutConsumer->reopen(); break; - case QueueType::DELAY: + case QueueType::Delay: $this->delayPublisher->getAMQPChannel()->queue_purge($this->delayQueueName); break; } @@ -475,7 +476,7 @@ public function status(): QueueStatus $status['ready'] = $ready; // working - $status['working'] = $redis->zCard($this->getRedisQueueKey(QueueType::WORKING)); + $status['working'] = $redis->zCard($this->getRedisQueueKey(QueueType::Working)); // fail $fail = 0; @@ -590,9 +591,9 @@ public function getRedisMessageIdKey(): string /** * 获取队列的键. */ - public function getRedisQueueKey(int|string $queueType): string + public function getRedisQueueKey(string|IQueueType $queueType): string { - return $this->redisPrefix . $this->name . ':' . strtolower(QueueType::getName($queueType) ?? $queueType); + return $this->redisPrefix . $this->name . ':' . strtolower($queueType->name ?? $queueType); } /** @@ -614,7 +615,7 @@ protected function parseTimeoutMessages(int $count = 100): void redis.call('zrem', KEYS[1], unpack(messages)) return messages LUA, [ - $this->getRedisQueueKey(QueueType::WORKING), + $this->getRedisQueueKey(QueueType::Working), microtime(true), $count, ], 1); diff --git a/src/Components/amqp/src/Queue/QueueConsumer.php b/src/Components/amqp/src/Queue/QueueConsumer.php index e3f0cc084b..9a619d4fa2 100644 --- a/src/Components/amqp/src/Queue/QueueConsumer.php +++ b/src/Components/amqp/src/Queue/QueueConsumer.php @@ -10,6 +10,7 @@ use Imi\AMQP\Base\BaseConsumer; use Imi\AMQP\Contract\IMessage; use Imi\AMQP\Contract\IQueueConsumer; +use Imi\AMQP\Enum\ConsumerResult; use Imi\AMQP\Message; class QueueConsumer extends BaseConsumer implements IQueueConsumer @@ -127,10 +128,10 @@ protected function bindConsumer(): void /** * {@inheritDoc} */ - protected function consume(IMessage $message): mixed + protected function consume(IMessage $message): ConsumerResult { $this->queue->push($message); - return null; + return ConsumerResult::Ack; } } diff --git a/src/Components/amqp/src/Queue/SwooleQueueConsumer.php b/src/Components/amqp/src/Queue/SwooleQueueConsumer.php index 3520c3c210..578f3dae59 100644 --- a/src/Components/amqp/src/Queue/SwooleQueueConsumer.php +++ b/src/Components/amqp/src/Queue/SwooleQueueConsumer.php @@ -10,6 +10,7 @@ use Imi\AMQP\Base\BaseConsumer; use Imi\AMQP\Contract\IMessage; use Imi\AMQP\Contract\IQueueConsumer; +use Imi\AMQP\Enum\ConsumerResult; use Imi\AMQP\Message; use Swoole\Coroutine\Channel; @@ -131,11 +132,11 @@ protected function bindConsumer(): void /** * {@inheritDoc} */ - protected function consume(IMessage $message): mixed + protected function consume(IMessage $message): ConsumerResult { $this->resultChannel->push($message); - return null; + return ConsumerResult::Ack; } } } diff --git a/src/Components/kafka/src/Queue/KafkaQueueDriver.php b/src/Components/kafka/src/Queue/KafkaQueueDriver.php index 88c5c3f5ad..847c33b65e 100644 --- a/src/Components/kafka/src/Queue/KafkaQueueDriver.php +++ b/src/Components/kafka/src/Queue/KafkaQueueDriver.php @@ -11,6 +11,7 @@ use Imi\Kafka\Queue\Model\KafkaPopMessage; use Imi\Queue\Contract\IMessage; use Imi\Queue\Driver\IQueueDriver; +use Imi\Queue\Enum\IQueueType; use Imi\Queue\Model\QueueStatus; use Imi\Util\Traits\TDataToProperty; use longlang\phpkafka\Consumer\Consumer; @@ -107,7 +108,7 @@ public function delete(IMessage $message): bool /** * {@inheritDoc} */ - public function clear($queueType = null): void + public function clear(?IQueueType $queueType = null): void { throw new \RuntimeException('Unsupport clear queue in KafkaQueueDriver'); } diff --git a/src/Components/pgsql/src/Db/Query/FullText/TsQuery.php b/src/Components/pgsql/src/Db/Query/FullText/TsQuery.php index 9eea83b9f5..a50dcf753d 100644 --- a/src/Components/pgsql/src/Db/Query/FullText/TsQuery.php +++ b/src/Components/pgsql/src/Db/Query/FullText/TsQuery.php @@ -4,23 +4,20 @@ namespace Imi\Pgsql\Db\Query\FullText; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; +use Imi\Util\Traits\TStaticClass; /** * PostgreSQL tsquery 函数. */ -class TsQuery extends BaseEnum +class TsQuery { - #[EnumItem(text: 'to_tsquery')] + use TStaticClass; + public const TO_TSQUERY = 'to_tsquery'; - #[EnumItem(text: 'plainto_tsquery')] public const PLAINTO_TSQUERY = 'plainto_tsquery'; - #[EnumItem(text: 'phraseto_tsquery')] public const PHRASETO_TSQUERY = 'phraseto_tsquery'; - #[EnumItem(text: 'websearch_to_tsquery')] public const WEBSEARCH_TO_TSQUERY = 'websearch_to_tsquery'; } diff --git a/src/Components/pgsql/src/Db/Query/FullText/TsRank.php b/src/Components/pgsql/src/Db/Query/FullText/TsRank.php index 4262d34635..d6e11b159c 100644 --- a/src/Components/pgsql/src/Db/Query/FullText/TsRank.php +++ b/src/Components/pgsql/src/Db/Query/FullText/TsRank.php @@ -4,17 +4,16 @@ namespace Imi\Pgsql\Db\Query\FullText; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - /** * PostgreSQL ts_rank 函数. */ -class TsRank extends BaseEnum +use Imi\Util\Traits\TStaticClass; + +class TsRank { - #[EnumItem(text: 'ts_rank')] + use TStaticClass; + public const TS_RANK = 'ts_rank'; - #[EnumItem(text: 'ts_rank_cd')] public const TS_RANK_CD = 'ts_rank_cd'; } diff --git a/src/Components/queue/src/Annotation/QueueTypeStructType.php b/src/Components/queue/src/Annotation/QueueTypeStructType.php deleted file mode 100644 index db3b75c070..0000000000 --- a/src/Components/queue/src/Annotation/QueueTypeStructType.php +++ /dev/null @@ -1,20 +0,0 @@ - 0) { $args = [ - $this->getQueueKey(QueueType::DELAY), + $this->getQueueKey(QueueType::Delay), $this->getMessageKeyPrefix(), $this->getMessageIdKey(), microtime(true) + $delay, @@ -121,7 +120,7 @@ public function push(IMessage $message, float $delay = 0, array $options = []): else { $args = [ - $this->getQueueKey(QueueType::READY), + $this->getQueueKey(QueueType::Ready), $this->getMessageKeyPrefix(), $this->getMessageIdKey(), date('Ymd'), @@ -217,8 +216,8 @@ public function pop(float $timeout = 0): ?IMessage redis.call('zadd', KEYS[2], ARGV[1] + score, messageId) return hashResult LUA, [ - $this->getQueueKey(QueueType::READY), - $this->getQueueKey(QueueType::WORKING), + $this->getQueueKey(QueueType::Ready), + $this->getQueueKey(QueueType::Working), $this->getMessageKeyPrefix(), microtime(true), ], 3); @@ -277,8 +276,8 @@ public function delete(IMessage $message): bool end return true LUA, [ - $this->getQueueKey(QueueType::READY), - $this->getQueueKey(QueueType::DELAY), + $this->getQueueKey(QueueType::Ready), + $this->getQueueKey(QueueType::Delay), $this->getMessageKeyPrefix(), $message->getMessageId(), ], 3); @@ -302,11 +301,11 @@ public function delete(IMessage $message): bool /** * {@inheritDoc} */ - public function clear($queueType = null): void + public function clear(?IQueueType $queueType = null): void { if (null === $queueType) { - $queueType = QueueType::getValues(); + $queueType = QueueType::cases(); } else { @@ -338,9 +337,9 @@ public function success(IMessage $message): int redis.call('del', KEYS[2] .. ARGV[1]) return true LUA, [ - $this->getQueueKey(QueueType::WORKING), + $this->getQueueKey(QueueType::Working), $this->getMessageKeyPrefix(), - $this->getQueueKey(QueueType::TIMEOUT), + $this->getQueueKey(QueueType::Timeout), $message->getMessageId(), ], 3); @@ -372,8 +371,8 @@ public function fail(IMessage $message, bool $requeue = false): int redis.call('rpush', KEYS[2], ARGV[1]) return true LUA, [ - $this->getQueueKey(QueueType::WORKING), - $requeue ? $this->getQueueKey(QueueType::READY) : $this->getQueueKey(QueueType::FAIL), + $this->getQueueKey(QueueType::Working), + $requeue ? $this->getQueueKey(QueueType::Ready) : $this->getQueueKey(QueueType::Fail), $message->getMessageId(), ], 2); @@ -400,21 +399,15 @@ public function status(): QueueStatus { return Redis::use(function (\Imi\Redis\RedisHandler $redis) { $status = []; - foreach (QueueType::getMap() as $key => $value) + foreach (QueueType::cases() as $case) { - /** @var QueueTypeStructType|null $queueTypeStructTypeAnnotation */ - $queueTypeStructTypeAnnotation = AnnotationManager::getConstantAnnotations(QueueType::class, $key, QueueTypeStructType::class, onlyFirst: true); - if (!$queueTypeStructTypeAnnotation) + $count = match ($case->structType()) { - throw new \RuntimeException(sprintf('Unknown QueueTypeStructType of %s::%s', QueueType::class, $key)); - } - $count = match ($queueTypeStructTypeAnnotation->type) - { - 'list' => $redis->lLen($this->getQueueKey($value)), - 'zset' => $redis->zCard($this->getQueueKey($value)), - default => throw new QueueException('Invalid type ' . $queueTypeStructTypeAnnotation->type), + 'list' => $redis->lLen($this->getQueueKey($case)), + 'zset' => $redis->zCard($this->getQueueKey($case)), + default => throw new QueueException('Invalid type ' . $case->structType()), }; - $status[strtolower(QueueType::getName($value))] = $count; + $status[strtolower($case->name)] = $count; } return new QueueStatus($status); @@ -435,8 +428,8 @@ public function restoreFailMessages(): int end return result LUA, [ - $this->getQueueKey(QueueType::READY), - $this->getQueueKey(QueueType::FAIL), + $this->getQueueKey(QueueType::Ready), + $this->getQueueKey(QueueType::Fail), ], 2); if (false === $result) @@ -469,8 +462,8 @@ public function restoreTimeoutMessages(): int end return result LUA, [ - $this->getQueueKey(QueueType::READY), - $this->getQueueKey(QueueType::TIMEOUT), + $this->getQueueKey(QueueType::Ready), + $this->getQueueKey(QueueType::Timeout), ], 2); if (false === $result) @@ -509,8 +502,8 @@ protected function parseDelayMessages(\Imi\Redis\RedisHandler $redis, int $count redis.call('zrem', KEYS[2], unpack(messageIds)) return messageIdCount LUA, [ - $this->getQueueKey(QueueType::READY), - $this->getQueueKey(QueueType::DELAY), + $this->getQueueKey(QueueType::Ready), + $this->getQueueKey(QueueType::Delay), microtime(true), $count, ], 2); @@ -550,8 +543,8 @@ protected function parseTimeoutMessages(\Imi\Redis\RedisHandler $redis, int $cou redis.call('zrem', KEYS[1], unpack(messageIds)) return messageIdCount LUA, [ - $this->getQueueKey(QueueType::WORKING), - $this->getQueueKey(QueueType::TIMEOUT), + $this->getQueueKey(QueueType::Working), + $this->getQueueKey(QueueType::Timeout), microtime(true), $count, ], 2); @@ -590,8 +583,8 @@ public function getMessageIdKey(): string /** * 获取队列的键. */ - public function getQueueKey(int $queueType): string + public function getQueueKey(int|string|QueueType $queueType): string { - return $this->prefix . $this->keyName . ':' . strtolower(QueueType::getName($queueType)); + return $this->prefix . $this->keyName . ':' . strtolower($queueType instanceof QueueType ? $queueType->name : (string) $queueType); } } diff --git a/src/Components/queue/src/Driver/RedisStreamQueueDriver.php b/src/Components/queue/src/Driver/RedisStreamQueueDriver.php index dd91c8edd8..873b40f7c2 100644 --- a/src/Components/queue/src/Driver/RedisStreamQueueDriver.php +++ b/src/Components/queue/src/Driver/RedisStreamQueueDriver.php @@ -7,6 +7,7 @@ use Imi\Bean\Annotation\Bean; use Imi\Queue\Contract\IMessage; use Imi\Queue\Contract\IRedisStreamMessage; +use Imi\Queue\Enum\IQueueType; use Imi\Queue\Exception\QueueException; use Imi\Queue\Model\QueueStatus; use Imi\Queue\Model\RedisStreamMessage; @@ -205,7 +206,7 @@ public function delete(IMessage $message): bool /** * {@inheritDoc} */ - public function clear($queueType = null): void + public function clear(?IQueueType $queueType = null): void { Redis::use(function (\Imi\Redis\RedisHandler $redis): void { $redis->del($this->getQueueKey()); diff --git a/src/Components/queue/src/Enum/IQueueType.php b/src/Components/queue/src/Enum/IQueueType.php new file mode 100644 index 0000000000..ca0cc90ea7 --- /dev/null +++ b/src/Components/queue/src/Enum/IQueueType.php @@ -0,0 +1,13 @@ + 'list', + self::Working, self::Delay => 'zset', + }; + } } diff --git a/src/Components/swoole/src/Cron/Consts/CronTaskType.php b/src/Components/swoole/src/Cron/Consts/CronTaskType.php index c7e0b945be..f091995c06 100644 --- a/src/Components/swoole/src/Cron/Consts/CronTaskType.php +++ b/src/Components/swoole/src/Cron/Consts/CronTaskType.php @@ -4,27 +4,20 @@ namespace Imi\Swoole\Cron\Consts; -use Imi\Enum\Annotation\EnumItem; - /** * 定时任务类型. */ -class CronTaskType extends \Imi\Cron\Consts\CronTaskType +class CronTaskType { use \Imi\Util\Traits\TStaticClass; - #[EnumItem(text: '随机工作进程任务')] public const RANDOM_WORKER = 'random_worker'; - #[EnumItem(text: '所有工作进程执行的任务')] public const ALL_WORKER = 'all_worker'; - #[EnumItem(text: '后台任务')] public const TASK = 'task'; - #[EnumItem(text: '进程')] public const PROCESS = 'process'; - #[EnumItem(text: '定时任务进程')] public const CRON_PROCESS = 'cron_process'; } diff --git a/src/Components/swoole/src/Cron/CronManager.php b/src/Components/swoole/src/Cron/CronManager.php index 9871180d6e..a8bdd6fdbe 100644 --- a/src/Components/swoole/src/Cron/CronManager.php +++ b/src/Components/swoole/src/Cron/CronManager.php @@ -9,6 +9,7 @@ use Imi\Bean\Annotation\Bean; use Imi\Cli\ImiCommand; use Imi\Cron\Annotation\Cron; +use Imi\Cron\Consts\UniqueLevel; use Imi\Cron\Contract\ICronManager; use Imi\Cron\Contract\ICronTask; use Imi\Cron\CronTask; @@ -104,7 +105,7 @@ public function addCronByAnnotation(Cron $cron, string $pointClass): void /** * {@inheritDoc} */ - public function addCron(string $id, ?string $type, callable|string $task, array $cronRules, mixed $data, float $lockExpire = 3, ?string $unique = null, ?string $redisPool = null, float $lockWaitTimeout = 3, bool $force = false, bool $successLog = true): void + public function addCron(string $id, ?string $type, callable|string $task, array $cronRules, mixed $data, float $lockExpire = 3, ?UniqueLevel $unique = null, ?string $redisPool = null, float $lockWaitTimeout = 3, bool $force = false, bool $successLog = true): void { if (isset($this->tasks[$id])) { diff --git a/src/Components/swoole/src/Server/Util/Amqp/AmqpServerConsumer.php b/src/Components/swoole/src/Server/Util/Amqp/AmqpServerConsumer.php index 515f578bc4..ef75b4d0c5 100644 --- a/src/Components/swoole/src/Server/Util/Amqp/AmqpServerConsumer.php +++ b/src/Components/swoole/src/Server/Util/Amqp/AmqpServerConsumer.php @@ -68,7 +68,7 @@ public function unbindRoutingKey(string $routingKey): void /** * {@inheritDoc} */ - protected function consume(IMessage $message): mixed + protected function consume(IMessage $message): ConsumerResult { try { @@ -80,16 +80,16 @@ protected function consume(IMessage $message): mixed 'closeByFlag' => Server::closeByFlag($data['flag'], $serverName, false), 'sendRawToGroup' => Server::sendRawToGroup($data['group'], $data['data'], $serverName, false), 'sendRawToAll' => Server::sendRawToAll($data['data'], $serverName, false), - default => ConsumerResult::ACK, + default => ConsumerResult::Ack, }; - return ConsumerResult::ACK; + return ConsumerResult::Ack; } catch (\Throwable $th) { Log::error($th); - return ConsumerResult::NACK; + return ConsumerResult::Nack; } } } diff --git a/src/Components/swoole/src/Server/Util/AmqpServerUtil.php b/src/Components/swoole/src/Server/Util/AmqpServerUtil.php index 5c4483b966..63a1bb112b 100644 --- a/src/Components/swoole/src/Server/Util/AmqpServerUtil.php +++ b/src/Components/swoole/src/Server/Util/AmqpServerUtil.php @@ -158,7 +158,7 @@ public function sendRawToAll(string $data, ?string $serverName = null, bool $toA if ($server instanceof \Imi\Swoole\Server\WebSocket\Server) { $method = 'push'; - $pushParams = (array) $server->getNonControlFrameType(); + $pushParams = (array) $server->getNonControlFrameType()->value; } else { @@ -206,7 +206,7 @@ public function sendRawToGroup(string|array $groupName, string $data, ?string $s if ($server instanceof \Imi\Swoole\Server\WebSocket\Server) { $method = 'push'; - $pushParams = (array) $server->getNonControlFrameType(); + $pushParams = (array) $server->getNonControlFrameType()->value; } else { diff --git a/src/Components/swoole/src/Server/Util/LocalServerUtil.php b/src/Components/swoole/src/Server/Util/LocalServerUtil.php index a6d238477d..e40dc9003f 100644 --- a/src/Components/swoole/src/Server/Util/LocalServerUtil.php +++ b/src/Components/swoole/src/Server/Util/LocalServerUtil.php @@ -147,7 +147,7 @@ public function sendRaw(string $data, int|string|array|null $clientId = null, ?s if ($server instanceof \Imi\Swoole\Server\WebSocket\Server) { $method = 'push'; - $pushParams = (array) $server->getNonControlFrameType(); + $pushParams = (array) $server->getNonControlFrameType()->value; } else { @@ -268,7 +268,7 @@ public function sendRawToAll(string $data, ?string $serverName = null, bool $toA if ($server instanceof \Imi\Swoole\Server\WebSocket\Server) { $method = 'push'; - $pushParams = (array) $server->getNonControlFrameType(); + $pushParams = (array) $server->getNonControlFrameType()->value; } else { @@ -354,7 +354,7 @@ public function sendRawToGroup(string|array $groupName, string $data, ?string $s if ($server instanceof \Imi\Swoole\Server\WebSocket\Server) { $method = 'push'; - $pushParams = (array) $server->getNonControlFrameType(); + $pushParams = (array) $server->getNonControlFrameType()->value; } else { diff --git a/src/Components/swoole/src/Server/WebSocket/Server.php b/src/Components/swoole/src/Server/WebSocket/Server.php index 891ed6f521..f08ded3f25 100644 --- a/src/Components/swoole/src/Server/WebSocket/Server.php +++ b/src/Components/swoole/src/Server/WebSocket/Server.php @@ -56,7 +56,7 @@ class Server extends Base implements ISwooleWebSocketServer /** * 非控制帧类型. */ - private int $nonControlFrameType = NonControlFrameType::TEXT; + private NonControlFrameType $nonControlFrameType = NonControlFrameType::Text; /** * {@inheritDoc} @@ -65,7 +65,7 @@ public function __construct(string $name, array $config, bool $isSubServer = fal { parent::__construct($name, $config, $isSubServer); $this->syncConnect = $config['syncConnect'] ?? true; - $this->nonControlFrameType = $config['nonControlFrameType'] ?? NonControlFrameType::TEXT; + $this->nonControlFrameType = $config['nonControlFrameType'] ?? NonControlFrameType::Text; } /** @@ -363,7 +363,7 @@ public function push(int|string $clientId, string $data, int $opcode = 1): bool /** * {@inheritDoc} */ - public function getNonControlFrameType(): int + public function getNonControlFrameType(): NonControlFrameType { return $this->nonControlFrameType; } diff --git a/src/Components/swoole/tests/unit/WebSocketServer/config/config.php b/src/Components/swoole/tests/unit/WebSocketServer/config/config.php index 8358cf6c42..e4b03d032a 100644 --- a/src/Components/swoole/tests/unit/WebSocketServer/config/config.php +++ b/src/Components/swoole/tests/unit/WebSocketServer/config/config.php @@ -67,7 +67,7 @@ 'port' => 13002, 'mode' => \SWOOLE_BASE, 'syncConnect' => true, - 'nonControlFrameType' => NonControlFrameType::BINARY, + 'nonControlFrameType' => NonControlFrameType::Binary, 'configs' => [ 'worker_num' => 2, 'task_worker_num' => 1, diff --git a/src/Components/workerman-gateway/src/Workerman/Server/Gateway/GatewayServer.php b/src/Components/workerman-gateway/src/Workerman/Server/Gateway/GatewayServer.php index 7fc0352f4f..95768d9593 100644 --- a/src/Components/workerman-gateway/src/Workerman/Server/Gateway/GatewayServer.php +++ b/src/Components/workerman-gateway/src/Workerman/Server/Gateway/GatewayServer.php @@ -24,7 +24,7 @@ class GatewayServer extends \Imi\Workerman\Server\Tcp\Server /** * 非控制帧类型. */ - private int $nonControlFrameType = NonControlFrameType::TEXT; + private NonControlFrameType $nonControlFrameType = NonControlFrameType::Text; /** * {@inheritDoc} @@ -32,7 +32,7 @@ class GatewayServer extends \Imi\Workerman\Server\Tcp\Server public function __construct(string $name, array $config) { parent::__construct($name, $config); - $this->nonControlFrameType = $config['nonControlFrameType'] ?? NonControlFrameType::TEXT; + $this->nonControlFrameType = $config['nonControlFrameType'] ?? NonControlFrameType::Text; } /** @@ -45,7 +45,7 @@ protected function bindEvents(): void try { // @phpstan-ignore-next-line - $connection->websocketType = NonControlFrameType::TEXT === $this->nonControlFrameType ? Websocket::BINARY_TYPE_BLOB : Websocket::BINARY_TYPE_ARRAYBUFFER; + $connection->websocketType = NonControlFrameType::Text === $this->nonControlFrameType ? Websocket::BINARY_TYPE_BLOB : Websocket::BINARY_TYPE_ARRAYBUFFER; // @phpstan-ignore-next-line $clientId = $connection->id; RequestContext::muiltiSet([ @@ -69,7 +69,7 @@ protected function bindEvents(): void /** * Get 非控制帧类型. */ - public function getNonControlFrameType(): int + public function getNonControlFrameType(): NonControlFrameType { return $this->nonControlFrameType; } diff --git a/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php b/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php index d3ca8c6552..2826f48cec 100644 --- a/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php +++ b/src/Components/workerman-gateway/tests/unit/AppServer/config/config.php @@ -113,7 +113,7 @@ 'namespace' => 'Imi\WorkermanGateway\Test\AppServer\Gateway', 'type' => Imi\WorkermanGateway\Workerman\Server\Type::GATEWAY, 'socketName' => 'websocket://127.0.0.1:13002', - 'nonControlFrameType' => NonControlFrameType::BINARY, + 'nonControlFrameType' => NonControlFrameType::Binary, 'configs' => [ 'lanIp' => '127.0.0.1', 'startPort' => 12900, diff --git a/src/Components/workerman/src/Server/WebSocket/Server.php b/src/Components/workerman/src/Server/WebSocket/Server.php index bcd3c52225..372ffb0f1e 100644 --- a/src/Components/workerman/src/Server/WebSocket/Server.php +++ b/src/Components/workerman/src/Server/WebSocket/Server.php @@ -31,7 +31,7 @@ class Server extends Base implements IWebSocketServer /** * 非控制帧类型. */ - private int $nonControlFrameType = NonControlFrameType::TEXT; + private NonControlFrameType $nonControlFrameType = NonControlFrameType::Text; /** * {@inheritDoc} @@ -40,7 +40,7 @@ public function __construct(string $name, array $config) { parent::__construct($name, $config); $this->worker->protocol = Websocket::class; - $this->nonControlFrameType = $config['nonControlFrameType'] ?? NonControlFrameType::TEXT; + $this->nonControlFrameType = $config['nonControlFrameType'] ?? NonControlFrameType::Text; } /** @@ -76,7 +76,7 @@ protected function bindEvents(): void try { // @phpstan-ignore-next-line - $connection->websocketType = NonControlFrameType::TEXT === $this->nonControlFrameType ? Websocket::BINARY_TYPE_BLOB : Websocket::BINARY_TYPE_ARRAYBUFFER; + $connection->websocketType = NonControlFrameType::Text === $this->nonControlFrameType ? Websocket::BINARY_TYPE_BLOB : Websocket::BINARY_TYPE_ARRAYBUFFER; $clientId = $connection->id; $worker = $this->worker; $request = new WorkermanRequest($worker, $connection, new Request($httpHeader), 'ws'); @@ -172,7 +172,7 @@ public function push(int|string $clientId, string $data, int $opcode = 1): bool /** * {@inheritDoc} */ - public function getNonControlFrameType(): int + public function getNonControlFrameType(): NonControlFrameType { return $this->nonControlFrameType; } diff --git a/src/Components/workerman/tests/unit/AppServer/config/config.php b/src/Components/workerman/tests/unit/AppServer/config/config.php index 038835c406..ebbd5ccc97 100644 --- a/src/Components/workerman/tests/unit/AppServer/config/config.php +++ b/src/Components/workerman/tests/unit/AppServer/config/config.php @@ -83,7 +83,7 @@ 'host' => env('SERVER_HOST', '127.0.0.1'), 'port' => 13002, 'shareWorker' => 'http', - 'nonControlFrameType' => NonControlFrameType::BINARY, + 'nonControlFrameType' => NonControlFrameType::Binary, 'configs' => [ ], ], diff --git a/src/Cron/Annotation/Cron.php b/src/Cron/Annotation/Cron.php index 6b670f1634..a7cd271cf7 100644 --- a/src/Cron/Annotation/Cron.php +++ b/src/Cron/Annotation/Cron.php @@ -5,6 +5,7 @@ namespace Imi\Cron\Annotation; use Imi\Bean\Annotation\Base; +use Imi\Cron\Consts\UniqueLevel; /** * 定时任务注解. @@ -62,7 +63,7 @@ public function __construct( /** * 定时任务唯一性设置;当前实例唯一: current;所有实例唯一: all;不唯一: null. */ - public ?string $unique = null, + public ?UniqueLevel $unique = null, /** * 用于锁的 `Redis` 连接池名. */ diff --git a/src/Cron/Consts/CronTaskType.php b/src/Cron/Consts/CronTaskType.php index 05f9d57159..6a34ea0ed2 100644 --- a/src/Cron/Consts/CronTaskType.php +++ b/src/Cron/Consts/CronTaskType.php @@ -4,16 +4,12 @@ namespace Imi\Cron\Consts; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - /** * 定时任务类型. */ -class CronTaskType extends BaseEnum +class CronTaskType { use \Imi\Util\Traits\TStaticClass; - #[EnumItem(text: '定时任务进程')] public const CRON_PROCESS = 'cron_process'; } diff --git a/src/Cron/Consts/UniqueLevel.php b/src/Cron/Consts/UniqueLevel.php index 85345a012b..0e323a5541 100644 --- a/src/Cron/Consts/UniqueLevel.php +++ b/src/Cron/Consts/UniqueLevel.php @@ -4,19 +4,18 @@ namespace Imi\Cron\Consts; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - /** * 任务唯一性等级. */ -class UniqueLevel extends BaseEnum +enum UniqueLevel: string { - use \Imi\Util\Traits\TStaticClass; - - #[EnumItem(text: '当前实例唯一')] - public const CURRENT = 'current'; + /** + * 当前实例唯一 + */ + case Current = 'current'; - #[EnumItem(text: '所有实例唯一')] - public const ALL = 'all'; + /** + * 所有实例唯一 + */ + case All = 'all'; } diff --git a/src/Cron/Contract/ICronManager.php b/src/Cron/Contract/ICronManager.php index dd1196accb..ebd88aa69c 100644 --- a/src/Cron/Contract/ICronManager.php +++ b/src/Cron/Contract/ICronManager.php @@ -5,6 +5,7 @@ namespace Imi\Cron\Contract; use Imi\Cron\Annotation\Cron; +use Imi\Cron\Consts\UniqueLevel; use Imi\Cron\CronTask; /** @@ -20,7 +21,7 @@ public function addCronByAnnotation(Cron $cron, string $pointClass): void; /** * 增加定时任务 */ - public function addCron(string $id, ?string $type, callable|string $task, array $cronRules, mixed $data, float $lockExpire = 3, ?string $unique = null, ?string $redisPool = null, float $lockWaitTimeout = 3, bool $force = false): void; + public function addCron(string $id, ?string $type, callable|string $task, array $cronRules, mixed $data, float $lockExpire = 3, ?UniqueLevel $unique = null, ?string $redisPool = null, float $lockWaitTimeout = 3, bool $force = false): void; /** * 移除定时任务 diff --git a/src/Cron/CronLock.php b/src/Cron/CronLock.php index bcf8499d67..a8ea889124 100644 --- a/src/Cron/CronLock.php +++ b/src/Cron/CronLock.php @@ -42,10 +42,10 @@ public function lock(CronTask $task): bool { case null: return $this->noLocks[$id] = true; - case UniqueLevel::ALL: + case UniqueLevel::All: $keyPrefix = 'imi:cron:lock:unique:all:'; break; - case UniqueLevel::CURRENT: + case UniqueLevel::Current: $keyPrefix = 'imi:cron:lock:unique:' . App::get(ProcessAppContexts::MASTER_PID) . ':'; break; default: diff --git a/src/Cron/CronManager.php b/src/Cron/CronManager.php index 1c862003ec..8e8f071f15 100644 --- a/src/Cron/CronManager.php +++ b/src/Cron/CronManager.php @@ -9,6 +9,7 @@ use Imi\Cli\ImiCommand; use Imi\Cron\Annotation\Cron; use Imi\Cron\Consts\CronTaskType; +use Imi\Cron\Consts\UniqueLevel; use Imi\Cron\Contract\ICronManager; use Imi\Cron\Contract\ICronTask; use Imi\Util\Process\ProcessAppContexts; @@ -85,7 +86,7 @@ public function addCronByAnnotation(Cron $cron, string $pointClass): void /** * {@inheritDoc} */ - public function addCron(string $id, ?string $type, callable|string $task, array $cronRules, mixed $data, float $lockExpire = 3, ?string $unique = null, ?string $redisPool = null, float $lockWaitTimeout = 3, bool $force = false, bool $successLog = true): void + public function addCron(string $id, ?string $type, callable|string $task, array $cronRules, mixed $data, float $lockExpire = 3, ?UniqueLevel $unique = null, ?string $redisPool = null, float $lockWaitTimeout = 3, bool $force = false, bool $successLog = true): void { if (isset($this->tasks[$id])) { diff --git a/src/Cron/CronTask.php b/src/Cron/CronTask.php index 30383d08e8..72f0f38343 100644 --- a/src/Cron/CronTask.php +++ b/src/Cron/CronTask.php @@ -7,6 +7,8 @@ /** * 定时任务对象 */ +use Imi\Cron\Consts\UniqueLevel; + class CronTask { /** @@ -51,12 +53,9 @@ public function __construct( */ private readonly float $maxExecutionTime = 3, /** - * 定时任务唯一性设置 - * 当前实例唯一: current - * 所有实例唯一: all - * 不唯一: null. + * 定时任务唯一性设置. */ - private readonly ?string $unique = null, + private readonly ?UniqueLevel $unique = null, /** * 用于锁的 `Redis` 连接池名. */ @@ -139,7 +138,7 @@ public function getData(): mixed /** * Get 在当前服务实例中唯一,只能同时执行一个. */ - public function getUnique(): ?string + public function getUnique(): ?UniqueLevel { return $this->unique; } diff --git a/src/Db/Mysql/Consts/LogicalOperator.php b/src/Db/Mysql/Consts/LogicalOperator.php index 5f7886bb93..7deed8bfb4 100644 --- a/src/Db/Mysql/Consts/LogicalOperator.php +++ b/src/Db/Mysql/Consts/LogicalOperator.php @@ -4,28 +4,31 @@ namespace Imi\Db\Mysql\Consts; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - -class LogicalOperator extends BaseEnum +class LogicalOperator { use \Imi\Util\Traits\TStaticClass; - #[EnumItem] public const AND = 'and'; - #[EnumItem] public const OR = 'or'; - #[EnumItem] public const XOR = 'xor'; - #[EnumItem] public const AND_NOT = 'and not'; - #[EnumItem] public const OR_NOT = 'or not'; - #[EnumItem] public const XOR_NOT = 'xor not'; + + public static function values(): array + { + return [ + static::AND, + static::OR, + static::XOR, + static::AND_NOT, + static::OR_NOT, + static::XOR_NOT, + ]; + } } diff --git a/src/Db/Mysql/Query/FullText/SearchModifier.php b/src/Db/Mysql/Query/FullText/SearchModifier.php index 9ecd86f397..e4d0f33687 100644 --- a/src/Db/Mysql/Query/FullText/SearchModifier.php +++ b/src/Db/Mysql/Query/FullText/SearchModifier.php @@ -4,25 +4,28 @@ namespace Imi\Db\Mysql\Query\FullText; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - /** * 搜索修饰符. */ -class SearchModifier extends BaseEnum +class SearchModifier { - use \Imi\Util\Traits\TStaticClass; - - #[EnumItem(text: '自然语言模式')] + /** + * 自然语言模式. + */ public const IN_NATURAL_LANGUAGE_MODE = 'IN NATURAL LANGUAGE MODE'; - #[EnumItem(text: '自然语言模式,带查询扩展')] + /** + * 自然语言模式,带查询扩展. + */ public const IN_NATURAL_LANGUAGE_MODE_WITH_QUERY_EXPANSION = 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION'; - #[EnumItem(text: '布尔模式')] + /** + * 布尔模式. + */ public const IN_BOOLEAN_MODE = 'IN BOOLEAN MODE'; - #[EnumItem(text: '带查询扩展')] + /** + * 带查询扩展. + */ public const WITH_QUERY_EXPANSION = 'WITH QUERY EXPANSION'; } diff --git a/src/Db/Query/Traits/TWhereCollector.php b/src/Db/Query/Traits/TWhereCollector.php index 28235739ae..7c71aeaf62 100644 --- a/src/Db/Query/Traits/TWhereCollector.php +++ b/src/Db/Query/Traits/TWhereCollector.php @@ -149,7 +149,12 @@ protected function parseWhereEx(array $condition): array $result = []; foreach ($condition as $key => $value) { - if (null === LogicalOperator::getText(strtolower($key))) + if (\in_array(strtolower($key), LogicalOperator::values())) + { + // 逻辑运算符 + $result[] = new WhereBrackets(fn () => $this->parseWhereEx($value), $key); + } + else { // 条件 k => v if (\is_array($value)) @@ -195,11 +200,6 @@ protected function parseWhereEx(array $condition): array $result[] = new Where($key, '=', $value); } } - else - { - // 逻辑运算符 - $result[] = new WhereBrackets(fn () => $this->parseWhereEx($value), $key); - } } return $result; diff --git a/src/Model/IdGenerator/UUIDGenerator.php b/src/Model/IdGenerator/UUIDGenerator.php index 78f47de143..055695b483 100644 --- a/src/Model/IdGenerator/UUIDGenerator.php +++ b/src/Model/IdGenerator/UUIDGenerator.php @@ -9,17 +9,20 @@ class UUIDGenerator implements IIdGenerator { + /** + * @param array{type?: UUIDGeneratorType, ns?: string, nsField?: string, name?: string, nameField?: string} $options + */ public function generate(?BaseModel $model, array $options = []): mixed { - switch ($type = $options['type'] ?? UUIDGeneratorType::RANDOM) + switch ($type = $options['type'] ?? UUIDGeneratorType::Random) { - case UUIDGeneratorType::TIME: + case UUIDGeneratorType::Time: return uuid_create(UUID_TYPE_TIME); - case UUIDGeneratorType::RANDOM: + case UUIDGeneratorType::Random: return uuid_create(UUID_TYPE_RANDOM); case UUIDGeneratorType::MD5: case UUIDGeneratorType::SHA1: - $functionName = 'uuid_generate_' . $type; + $functionName = 'uuid_generate_' . $type->name; if (isset($options['ns'])) { $ns = $options['ns']; @@ -44,7 +47,7 @@ public function generate(?BaseModel $model, array $options = []): mixed return $functionName($ns, $name); default: - throw new \InvalidArgumentException(sprintf('Invalid value %s in enum %s', $type, static::class)); + throw new \InvalidArgumentException(sprintf('Invalid value %s in enum %s', $type->name, static::class)); } } } diff --git a/src/Model/IdGenerator/UUIDGeneratorType.php b/src/Model/IdGenerator/UUIDGeneratorType.php index 12e8e5d5ad..ea721f5422 100644 --- a/src/Model/IdGenerator/UUIDGeneratorType.php +++ b/src/Model/IdGenerator/UUIDGeneratorType.php @@ -4,20 +4,16 @@ namespace Imi\Model\IdGenerator; -use Imi\Enum\BaseEnum; - /** * UUID 生成器类型. */ -class UUIDGeneratorType extends BaseEnum +enum UUIDGeneratorType { - use \Imi\Util\Traits\TStaticClass; - - public const TIME = 'time'; + case Time; - public const RANDOM = 'random'; + case Random; - public const MD5 = 'md5'; + case MD5; - public const SHA1 = 'sha1'; + case SHA1; } diff --git a/src/Server/WebSocket/Contract/IWebSocketServer.php b/src/Server/WebSocket/Contract/IWebSocketServer.php index a501d12c15..3d5165521b 100644 --- a/src/Server/WebSocket/Contract/IWebSocketServer.php +++ b/src/Server/WebSocket/Contract/IWebSocketServer.php @@ -6,6 +6,7 @@ use Imi\Server\Contract\IServer; use Imi\Server\Group\Contract\IServerGroup; +use Imi\Server\WebSocket\Enum\NonControlFrameType; interface IWebSocketServer extends IServer, IServerGroup { @@ -17,5 +18,5 @@ public function push(int|string $clientId, string $data, int $opcode = 1): bool; /** * 非控制帧类型. */ - public function getNonControlFrameType(): int; + public function getNonControlFrameType(): NonControlFrameType; } diff --git a/src/Server/WebSocket/Dispatcher.php b/src/Server/WebSocket/Dispatcher.php index 853ab8b0c0..35234083be 100644 --- a/src/Server/WebSocket/Dispatcher.php +++ b/src/Server/WebSocket/Dispatcher.php @@ -33,7 +33,7 @@ public function dispatch(IFrame $frame): void { /** @var IWebSocketServer $server */ $server = RequestContext::getServer(); - $server->push($frame->getClientId(), $server->getBean(DataParser::class)->encode($responseData), $server->getNonControlFrameType()); + $server->push($frame->getClientId(), $server->getBean(DataParser::class)->encode($responseData), $server->getNonControlFrameType()->value); } } diff --git a/src/Server/WebSocket/Enum/NonControlFrameType.php b/src/Server/WebSocket/Enum/NonControlFrameType.php index 08944f205d..d6d387b53b 100644 --- a/src/Server/WebSocket/Enum/NonControlFrameType.php +++ b/src/Server/WebSocket/Enum/NonControlFrameType.php @@ -4,19 +4,18 @@ namespace Imi\Server\WebSocket\Enum; -use Imi\Enum\Annotation\EnumItem; -use Imi\Enum\BaseEnum; - /** * Websocket 非控制帧类型. */ -class NonControlFrameType extends BaseEnum +enum NonControlFrameType: int { - use \Imi\Util\Traits\TStaticClass; - - #[EnumItem(text: '文本帧')] - public const TEXT = 1; + /** + * 文本帧. + */ + case Text = 1; - #[EnumItem(text: '二进制帧')] - public const BINARY = 2; + /** + * 二进制帧. + */ + case Binary = 2; } diff --git a/src/Util/EnumUtil.php b/src/Util/EnumUtil.php new file mode 100644 index 0000000000..33600aa021 --- /dev/null +++ b/src/Util/EnumUtil.php @@ -0,0 +1,48 @@ +name === $case) + { + return $c; + } + } + + return null; + } + + public static function in(string $enum, mixed $value): bool + { + foreach ($enum::cases() as $case) + { + if ($case === $value || ($case->value ?? $case->name) === $value) + { + return true; + } + } + + return false; + } +} diff --git a/src/Validate/ValidatorHelper.php b/src/Validate/ValidatorHelper.php index 47c734069b..5101afea65 100644 --- a/src/Validate/ValidatorHelper.php +++ b/src/Validate/ValidatorHelper.php @@ -4,7 +4,7 @@ namespace Imi\Validate; -use Imi\Enum\BaseEnum; +use Imi\Util\EnumUtil; /** * 验证器工具类. @@ -319,22 +319,25 @@ public static function notIn(mixed $value, string|array $list): bool /** * 值在枚举值范围内. - * - * @param class-string $enumClass */ public static function inEnum(mixed $value, string $enumClass): bool { - return \in_array($value, $enumClass::getValues()); + if (is_subclass_of($enumClass, \UnitEnum::class)) + { + return EnumUtil::in($enumClass, $value); + } + else + { + return \in_array($value, $enumClass::getValues()); + } } /** * 值不在枚举值范围内. - * - * @param class-string $enumClass */ public static function notInEnum(mixed $value, string $enumClass): bool { - return !\in_array($value, $enumClass::getValues()); + return !static::inEnum($value, $enumClass); } /** diff --git a/tests/unit/Component/Bean/EnumBean.php b/tests/unit/Component/Bean/EnumBean.php new file mode 100644 index 0000000000..86e08b1424 --- /dev/null +++ b/tests/unit/Component/Bean/EnumBean.php @@ -0,0 +1,38 @@ +enum1; + } + + public function getEnum2(): TestEnumBeanBacked + { + return $this->enum2; + } + + public function getEnum3(): TestEnumBean|TestEnumBeanBacked + { + return $this->enum3; + } +} diff --git a/tests/unit/Component/Enum/TestEnumBean.php b/tests/unit/Component/Enum/TestEnumBean.php new file mode 100644 index 0000000000..2900cbfa15 --- /dev/null +++ b/tests/unit/Component/Enum/TestEnumBean.php @@ -0,0 +1,11 @@ + 'sha1', 'ns' => '99e4edaf-8363-466e-bddf-7254db57675c', 'nameField' => 'title'])] + #[Id(index: false, generator: 'Imi\\Model\\IdGenerator\\UUIDGenerator', generatorOptions: ['type' => UUIDGeneratorType::SHA1, 'ns' => '99e4edaf-8363-466e-bddf-7254db57675c', 'nameField' => 'title'])] protected ?string $content = null; /** diff --git a/tests/unit/Component/Tests/BeanTest.php b/tests/unit/Component/Tests/BeanTest.php index ed114394e4..3b402c6596 100644 --- a/tests/unit/Component/Tests/BeanTest.php +++ b/tests/unit/Component/Tests/BeanTest.php @@ -11,6 +11,8 @@ use Imi\Test\Component\Bean\BeanA; use Imi\Test\Component\Bean\BeanB; use Imi\Test\Component\Bean\BeanC; +use Imi\Test\Component\Enum\TestEnumBean; +use Imi\Test\Component\Enum\TestEnumBeanBacked; use Imi\Util\Imi; /** @@ -386,6 +388,33 @@ public function testReadOnlyBean(): void $this->assertEquals('ReadOnlyBean', $bean->test()); } + public function testEnumBean(): void + { + /** @var \Imi\Test\Component\Bean\EnumBean $bean */ + // @phpstan-ignore-next-line + $bean = App::getBean('EnumBean1'); + // @phpstan-ignore-next-line + $this->assertInstanceOf(\Imi\Test\Component\Bean\EnumBean::class, $bean); + // @phpstan-ignore-next-line + $this->assertEquals(TestEnumBean::A, $bean->getEnum1()); + // @phpstan-ignore-next-line + $this->assertEquals(TestEnumBeanBacked::B, $bean->getEnum2()); + // @phpstan-ignore-next-line + $this->assertEquals(TestEnumBean::A, $bean->getEnum3()); + + /** @var \Imi\Test\Component\Bean\EnumBean $bean */ + // @phpstan-ignore-next-line + $bean = App::getBean('EnumBean2'); + // @phpstan-ignore-next-line + $this->assertInstanceOf(\Imi\Test\Component\Bean\EnumBean::class, $bean); + // @phpstan-ignore-next-line + $this->assertEquals(TestEnumBean::B, $bean->getEnum1()); + // @phpstan-ignore-next-line + $this->assertEquals(TestEnumBeanBacked::A, $bean->getEnum2()); + // @phpstan-ignore-next-line + $this->assertEquals(TestEnumBeanBacked::B, $bean->getEnum3()); + } + // @phpstan-ignore-next-line private function test1(): self { diff --git a/tests/unit/Component/Tests/Util/EnumTest.php b/tests/unit/Component/Tests/Util/EnumTest.php new file mode 100644 index 0000000000..4e875a295a --- /dev/null +++ b/tests/unit/Component/Tests/Util/EnumTest.php @@ -0,0 +1,37 @@ +assertEquals(TestEnumBean::A, EnumUtil::fromName(TestEnumBean::class, 'A')); + $this->expectException(\ValueError::class); + EnumUtil::fromName(TestEnumBean::class, 'ABC'); + } + + public function testTryFromName(): void + { + $this->assertEquals(TestEnumBean::A, EnumUtil::tryFromName(TestEnumBean::class, 'A')); + $this->assertNull(EnumUtil::tryFromName(TestEnumBean::class, 'ABC')); + } + + public function testIn(): void + { + $this->assertTrue(EnumUtil::in(TestEnumBean::class, 'A')); + $this->assertTrue(EnumUtil::in(TestEnumBean::class, TestEnumBean::A)); + $this->assertFalse(EnumUtil::in(TestEnumBean::class, 'ABC')); + + $this->assertTrue(EnumUtil::in(TestEnumBeanBacked::class, 'hello')); + $this->assertTrue(EnumUtil::in(TestEnumBeanBacked::class, TestEnumBeanBacked::A)); + $this->assertFalse(EnumUtil::in(TestEnumBeanBacked::class, 'hello imi')); + } +} diff --git a/tests/unit/Component/Tests/ValidatorHelperTest.php b/tests/unit/Component/Tests/ValidatorHelperTest.php index 35eda68a26..831485af63 100644 --- a/tests/unit/Component/Tests/ValidatorHelperTest.php +++ b/tests/unit/Component/Tests/ValidatorHelperTest.php @@ -6,6 +6,8 @@ use Imi\Test\BaseTest; use Imi\Test\Component\Enum\TestEnum; +use Imi\Test\Component\Enum\TestEnumBean; +use Imi\Test\Component\Enum\TestEnumBeanBacked; use Imi\Validate\ValidatorHelper; use PHPUnit\Framework\Assert; @@ -349,12 +351,24 @@ public function testInEnum(): void { Assert::assertTrue(ValidatorHelper::inEnum(TestEnum::A, TestEnum::class)); Assert::assertFalse(ValidatorHelper::inEnum(4, TestEnum::class)); + Assert::assertTrue(ValidatorHelper::inEnum(TestEnumBean::A, TestEnumBean::class)); + Assert::assertTrue(ValidatorHelper::inEnum('A', TestEnumBean::class)); + Assert::assertFalse(ValidatorHelper::inEnum(4, TestEnumBean::class)); + Assert::assertTrue(ValidatorHelper::inEnum(TestEnumBeanBacked::A, TestEnumBeanBacked::class)); + Assert::assertTrue(ValidatorHelper::inEnum('hello', TestEnumBeanBacked::class)); + Assert::assertFalse(ValidatorHelper::inEnum(4, TestEnumBeanBacked::class)); } public function testNotInEnum(): void { Assert::assertTrue(ValidatorHelper::notInEnum(4, TestEnum::class)); Assert::assertFalse(ValidatorHelper::notInEnum(TestEnum::A, TestEnum::class)); + Assert::assertTrue(ValidatorHelper::notInEnum(4, TestEnumBean::class)); + Assert::assertFalse(ValidatorHelper::notInEnum(TestEnumBean::A, TestEnumBean::class)); + Assert::assertFalse(ValidatorHelper::notInEnum('A', TestEnumBean::class)); + Assert::assertTrue(ValidatorHelper::notInEnum(4, TestEnumBeanBacked::class)); + Assert::assertFalse(ValidatorHelper::notInEnum(TestEnumBeanBacked::A, TestEnumBeanBacked::class)); + Assert::assertFalse(ValidatorHelper::notInEnum('hello', TestEnumBeanBacked::class)); } public function testCnIdcard(): void diff --git a/tests/unit/Component/config/config.php b/tests/unit/Component/config/config.php index af2aefeff7..555c7a8ee9 100644 --- a/tests/unit/Component/config/config.php +++ b/tests/unit/Component/config/config.php @@ -88,6 +88,16 @@ 'DbQueryLog' => [ 'enable' => true, ], + 'EnumBean1' => [ + 'enum1' => 'A', + 'enum2' => 'imi', + 'enum3' => 'A', + ], + 'EnumBean2' => [ + 'enum1' => 'B', + 'enum2' => 'hello', + 'enum3' => 'imi', + ], ], 'imi-framework' => 'very six',