Skip to content

Commit

Permalink
支持枚举和联合类型的控制器方法参数 (#676)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurunsoft committed Feb 8, 2024
1 parent b9aae3b commit d3cb325
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 88 deletions.
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,18 @@ parameters:
- dev/PHPStan/FileFinder.php
- '#Class UnitEnum not found#'
- '#Class BackedEnum not found#'
- '#Class ReflectionEnum not found#i'
- '#unknown class UnitEnum#'
- '#unknown class BackedEnum#'
- '#unknown class ReflectionEnum#'
- '#Call to static method .+\(\) on an unknown class (Backed|Unit)Enum#'
- '#Method Imi\\Util\\EnumUtil::.+\(\) has invalid return type (Backed|Unit)Enum#'
- '#unknown class Imi\\Test\\Component\\Bean\\EnumBean#'
- '#unknown class Imi\\Test\\Component\\Enum\\TestEnumBean#'
- '#unknown class Imi\\Test\\Component\\Enum\\TestEnumBeanBacked#'
- '#unknown class Imi\\Test\\Component\\Enum\\TestEnumBeanBackedInt#'
- '#Class Imi\\Test\\Component\\Bean\\EnumBean not found#'
- '#Class Imi\\Test\\Component\\Enum\\TestEnumBean not found#'
- '#Class Imi\\Test\\Component\\Enum\\TestEnumBeanBacked not found#'
- '#Class Imi\\Test\\Component\\Enum\\TestEnumBeanBackedInt not found#'
services:
64 changes: 52 additions & 12 deletions src/Components/grpc/src/Middleware/ActionMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Imi\Server\Session\Session;
use Imi\Server\View\View;
use Imi\Util\DelayServerBeanCallable;
use Imi\Util\EnumUtil;
use Imi\Util\Http\Consts\MediaType;
use Imi\Util\Http\Consts\RequestHeader;
use Imi\Util\Http\Consts\ResponseHeader;
Expand Down Expand Up @@ -262,9 +263,10 @@ private function prepareActionParams(Request $request, RouteResult $routeResult)
}
elseif ($actionMethodCacheItem->hasDefault())
{
$value = $actionMethodCacheItem->getDefault();
$result[] = $actionMethodCacheItem->getDefault();
continue;
}
elseif (null !== ($type = $actionMethodCacheItem->getType()) && class_exists($type))
elseif (($types = $actionMethodCacheItem->getTypes()) && ActionMethodItem::TYPE_COMMON === $types[0]['type'] && class_exists($type = $types[0]['name']))
{
if (is_subclass_of($type, \Google\Protobuf\Internal\Message::class))
{
Expand All @@ -290,17 +292,55 @@ private function prepareActionParams(Request $request, RouteResult $routeResult)
}
if (null !== $value)
{
switch ($actionMethodCacheItem->getType())
foreach ($actionMethodCacheItem->getTypes() as $type)
{
case 'int':
$value = (int) $value;
break;
case 'float':
$value = (float) $value;
break;
case 'bool':
$value = (bool) $value;
break;
switch ($type['name'])
{
case 'int':
$value = (int) $value;
break 2;
case 'float':
$value = (float) $value;
break 2;
case 'bool':
$value = (bool) $value;
break 2;
default:
switch ($type['type'])
{
case ActionMethodItem::TYPE_UNIT_ENUM:
$newValue = EnumUtil::tryFromName($type['name'], $value);
if (null !== $newValue)
{
$value = $newValue;
break 3;
}
break;
case ActionMethodItem::TYPE_BACKED_ENUM:
if ('int' === $type['enumBackingType'])
{
if (filter_var($value, \FILTER_VALIDATE_INT))
{
$newValue = $type['name']::tryFrom((int) $value);
if (null !== $newValue)
{
$value = $newValue;
break 3;
}
}
}
else
{
$newValue = $type['name']::tryFrom($value);
if (null !== $newValue)
{
$value = $newValue;
break 3;
}
}
break;
}
}
}
}
$result[] = $value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,28 @@
use Imi\Server\Http\Route\Annotation\Controller;
use Imi\Test\Component\Enum\TestEnumBean;
use Imi\Test\Component\Enum\TestEnumBeanBacked;
use Imi\Test\Component\Enum\TestEnumBeanBackedInt;
#[Controller(prefix: '/enum/')]
class EnumController extends HttpController
{
#[Action]
public function test1(TestEnumBean $enum, TestEnumBeanBacked $enumBacked): array
public function test1(TestEnumBean $enum, TestEnumBeanBacked $enumBacked, TestEnumBeanBackedInt $enumBackedInt): array
{
return [
'enum' => $enum,
'enumBacked' => $enumBacked,
'enum' => $enum,
'enumBacked' => $enumBacked,
'enumBackedInt' => $enumBackedInt,
];
}
#[Action]
public function test2(TestEnumBean|string $enum = '', TestEnumBeanBacked|string $enumBacked = ''): array
public function test2(TestEnumBean|string $enum = '', TestEnumBeanBacked|string $enumBacked = '', TestEnumBeanBackedInt|int $enumBackedInt = 0): array
{
return [
'enum' => $enum,
'enumBacked' => $enumBacked,
'enum' => $enum,
'enumBacked' => $enumBacked,
'enumBackedInt' => $enumBackedInt,
];
}
}
Expand Down
26 changes: 15 additions & 11 deletions src/Components/swoole/tests/unit/HttpServer/Tests/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -392,25 +392,29 @@ public function testEnum(): void
$this->markTestSkipped();
}
$http = new HttpRequest();
$response = $http->get($this->host . 'enum/test1?enum=A&enumBacked=imi');
$response = $http->get($this->host . 'enum/test1?enum=A&enumBacked=imi&enumBackedInt=1');
$this->assertEquals([
'enum' => 'A',
'enumBacked' => 'imi',
'enum' => 'A',
'enumBacked' => 'imi',
'enumBackedInt' => 1,
], $response->json(true));
$response = $http->get($this->host . 'enum/test2');
$this->assertEquals([
'enum' => '',
'enumBacked' => '',
'enum' => '',
'enumBacked' => '',
'enumBackedInt' => 0,
], $response->json(true));
$response = $http->get($this->host . 'enum/test2?enum=A&enumBacked=imi');
$response = $http->get($this->host . 'enum/test2?enum=A&enumBacked=imi&enumBackedInt=1');
$this->assertEquals([
'enum' => 'A',
'enumBacked' => 'imi',
'enum' => 'A',
'enumBacked' => 'imi',
'enumBackedInt' => 1,
], $response->json(true));
$response = $http->get($this->host . 'enum/test2?enum=x&enumBacked=x');
$response = $http->get($this->host . 'enum/test2?enum=x&enumBacked=x&enumBackedInt=0');
$this->assertEquals([
'enum' => 'x',
'enumBacked' => 'x',
'enum' => 'x',
'enumBacked' => 'x',
'enumBackedInt' => 0,
], $response->json(true));
}
}
79 changes: 53 additions & 26 deletions src/Server/Http/Middleware/ActionMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,14 @@ private function prepareActionParams(Request $request, RouteResult $routeResult)
}
elseif ($actionMethodCacheItem->hasDefault())
{
$value = $actionMethodCacheItem->getDefault();
$result[] = $actionMethodCacheItem->getDefault();
continue;
}
elseif ($actionMethodCacheItem->allowNull())
{
$value = null;
}
elseif (($type = $actionMethodCacheItem->getType()) && (UploadedFileInterface::class === $type || is_subclass_of($type, UploadedFileInterface::class)))
elseif (($types = $actionMethodCacheItem->getTypes()) && ActionMethodItem::TYPE_UPLOADED_FILE === $types[0]['type'])
{
$uploadedFiles ??= $request->getUploadedFiles();
if (!isset($uploadedFiles[$paramName]))
Expand All @@ -268,38 +269,64 @@ private function prepareActionParams(Request $request, RouteResult $routeResult)
{
throw new \RuntimeException(sprintf('Upload file failed. error:%d', $value->getError()));
}
$result[] = $value;
continue;
}
else
{
throw new \InvalidArgumentException(sprintf('Missing parameter: %s', $paramName));
}
if (null !== $value)
{
switch ($actionMethodCacheItem->getType())
foreach ($actionMethodCacheItem->getTypes() as $type)
{
case 'int':
$value = (int) $value;
break;
case 'float':
$value = (float) $value;
break;
case 'bool':
$value = (bool) $value;
break;
case \UnitEnum::class:
$newValue = EnumUtil::tryFromName($actionMethodCacheItem->getTypeClass(), $value);
if (null !== $newValue)
{
$value = $newValue;
}
break;
case \BackedEnum::class:
$newValue = $actionMethodCacheItem->getTypeClass()::tryFrom($value);
if (null !== $newValue)
{
$value = $newValue;
}
break;
switch ($type['name'])
{
case 'int':
$value = (int) $value;
break 2;
case 'float':
$value = (float) $value;
break 2;
case 'bool':
$value = (bool) $value;
break 2;
default:
switch ($type['type'])
{
case ActionMethodItem::TYPE_UNIT_ENUM:
$newValue = EnumUtil::tryFromName($type['name'], $value);
if (null !== $newValue)
{
$value = $newValue;
break 3;
}
break;
case ActionMethodItem::TYPE_BACKED_ENUM:
if ('int' === $type['enumBackingType'])
{
if (filter_var($value, \FILTER_VALIDATE_INT))
{
$newValue = $type['name']::tryFrom((int) $value);
if (null !== $newValue)
{
$value = $newValue;
break 3;
}
}
}
else
{
$newValue = $type['name']::tryFrom($value);
if (null !== $newValue)
{
$value = $newValue;
break 3;
}
}
break;
}
}
}
}
$result[] = $value;
Expand Down

0 comments on commit d3cb325

Please sign in to comment.