tatilcom / dto-bundle
为 symfony 应用程序的数据传输对象库
Requires
- php: >=7.0
- doctrine/annotations: ~1.0
- sensio/framework-extra-bundle: ~5.0
- symfony/http-foundation: ^3.4|^4.4|^5.0
- symfony/options-resolver: ^3.4|^4.4|^5.0
- symfony/property-access: ^3.4|^4.4|^5.0
Requires (Dev)
- symfony/phpunit-bridge: ^4.2
This package is not auto-updated.
Last update: 2024-09-25 12:32:43 UTC
README
此包专注于将请求参数注入到数据传输对象中。
安装
请确保已全局安装 Composer,如 Composer 文档中的安装章节所述。
使用 Symfony Flex 的应用程序
打开命令行,进入您的项目目录并执行
$ composer require metglobal-compass/dto-bundle
不使用 Symfony Flex 的应用程序
步骤 1:下载包
打开命令行,进入您的项目目录,然后执行以下命令以下载此包的最新稳定版本
$ composer require metglobal-compass/dto-bundle
步骤 2:启用包
然后,通过将其添加到项目 config/bundles.php
文件中注册的包列表中启用该包
// config/bundles.php return [ // ... Metglobal\DTOBundle\DTOBundle::class => ['all' => true], ];
步骤 3:启用参数转换器
Metglobal\DTOBundle\DTOParamConverter: tags: - { name: request.param_converter, priority: -2, converter: dto_converter }
如何使用
使用类型提示定义控制器方法参数。类型提示必须是 \Metglobal\Compass\Domain\DTO\Request
的实例。如果是 symfony,它将尝试使用默认配置解析参数。使用 \Metglobal\DTOBundle\DTOParamConverter
。
见: \Metglobal\DTOBundle\DTOParamConverter::supports
。
默认参数解析器参数(见: \Metglobal\DTOBundle\OptionsResolver\ParameterOptionsResolver
,\Metglobal\DTOBundle\OptionsResolver\DateParameterOptionsResolver
)
[ 'type' => 'string', 'scope' => 'request', 'disabled' => false, 'options' => [], 'undefined' => false ]
属性注解示例
@Metglobal\Compass\Annotation\DTO\Parameter(
type="string",
scope="request",
path="pathOfThisParameter",
disabled=false,
options={},
undefined=false
)
可用的属性注解选项
转换器将尝试使用默认值自动解析所有内容,但您可以使用 Metglobal\Compass\Annotation\DTO\Parameter
注解配置以下参数,并且如果没有定义此注解到属性,它也会尝试解析自身。
type
变量的类型。可用的类型有:'string','boolean','bool','integer','int' 和 'mixed'。混合类型允许您将任何类型的值应用于属性。
警告:布尔类型是例外,见: \Symfony\Component\HttpFoundation\ParameterBag::getBoolean
。
scope
变量的作用域。可用的作用域有:'request','query','headers','attributes'
path
变量的路径。默认值是属性名,但您可以自定义变量的路径。例如:URL:*.com?testPath=3
/** * @Parameter(scope="query", path="testPath") */ public $differentName;
它将 3 设置到 $differentName。
警告:此参数需要每个属性单独指定,如果您没有定义,它将尝试使用属性名解析参数。这意味着在上面的示例中,路径将是 differentName
。
disabled
禁用选定参数的注入。
options
format:
-------
Available when you set type to date. You can configure input datetime's format with this property.
timezone:
--------
Available when you set type to date. You can configure datetime's timezone with this property.
undefinedable
使属性可未定义。此属性使您能够找到未定义的属性。
额外的注解提示
此注解可以在属性或类中使用。如果您将此属性定义为类,它将影响所有类的属性。
Default parameters overrides --> Class annotation parameters (If exists) overrides --> Property annotation parameters (If exists)
对于每个参数,它调用一个方法来找到每个属性的最终注入配置。
<?php namespace Metglobal\Compass\Request; use Metglobal\DTOBundle\Annotation\Parameter; use Metglobal\DTOBundle\Request; use Metglobal\DTOBundle\Undefined; /** * @Parameter(scope="query") */ class DummyRequest implements Request { /** * @Parameter(type="int") * * @var int|null */ public $foo; /** * @Parameter(type="int") * * @var int|null */ public $bar; }
在上面的类中,$foo 将从 query
作用域注入,而 $bar 将从查询中注入,并转换为整数类型。
空/未定义变量
每个定义的属性如果没有默认值,则是可空的,可以未定义。
警告:如果您为属性定义了默认值,转换器将注入默认值而不是空值。
示例
namespace Metglobal\Compass\Request; use Metglobal\DTOBundle\Annotation\Parameter; use Metglobal\DTOBundle\Request; use Metglobal\DTOBundle\Undefined; class DummyRequest implements Request { /** * @Parameter(scope="query", undefined=true) * * @var string|null|Undefined */ public $foo; }
结果将是
生命周期事件
\Metglobal\DTOBundle\Annotation\PreSet
将此注解定义在方法上允许您在将请求参数设置到目标类之前访问属性。
\Metglobal\DTOBundle\Annotation\PostSet
将此注解应用到方法上,允许你在将请求参数设置到目标类后访问属性。
\Metglobal\DTOBundle\CallableRequest 接口
您应使用上述配置通过 @Metglobal\Compass\Annotation\DTO\Parameter
注解注入所有简单参数,但如果存在注解无法处理的复杂逻辑,您可以使用此接口作为回调方法。
在 call()
方法中,您可以使用 ...$args
变量修改对象的属性。提示 1:推荐使用生命周期事件处理基本过程。只有当您需要向目标类中注入任何内容时才使用此接口。提示 2:如果您不知道 ...$args
的含义,请参阅 RFC:[https://wiki.php.net/rfc/argument_unpacking](https://wiki.php.net/rfc/argument_unpacking)。
示例用法
控制器
<?php namespace Metglobal\Compass\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Annotation\Route; ... class DummyController extends Controller { /** * @Route("/dummy/{id}", requirements={"id" = "\d+"}, methods={"DELETE"}, name="dummy_route") */ public function __invoke(FooService $fooService, BarService $barService, BazService $bazService, DummyRequest $request): JsonResponse { $request->call($fooService, $barService); return new JsonResponse($bazService->handle($request)); } }
请求
<?php namespace Metglobal\Compass\Request; use Metglobal\DTOBundle\Annotation\Parameter; use Metglobal\DTOBundle\Annotation\PostSet; use Metglobal\DTOBundle\Annotation\PreSet; use Metglobal\DTOBundle\CallableRequest; use Metglobal\DTOBundle\Undefined; /** * @Parameter(scope="query") */ class DummyRequest implements CallableRequest { /** * @Parameter(type="int") * * @var int|null */ public $foo; public $bar; public $baz; /** * @var \DateTime|null * * @Parameter(type="date", options={format="Y-m-d"}) */ public $fooBar; public function call(...$args) { [ $fooService, $barService ] = $args; $this->foo = $fooService->aMethod($barService->bMethod($this->foo)); } /** * This method will run before setting the parameters * * @PreSet() */ public function preSetXMethod(){ $this->baz = 1; } /** * This method will run after setting the parameters * * @PostSet() */ public function postSetXMethod(){ $this->baz = 5; } }
分组
您可以使用 @Metglobal\DTOBundle\Annotation\Group
注解对注入的属性进行分组。
示例
<?php namespace Metglobal\Compass\Request; use Metglobal\DTOBundle\Annotation\Parameter; use Metglobal\DTOBundle\CallableRequest; use Metglobal\DTOBundle\Undefined; /** * @Group("fooGroup") * @Parameter(scope="query") */ class DummyRequest implements CallableRequest { /** * @Parameter(type="int", undefined=true) * @Group(target="barGroup") * * @var int|null|Undefined */ public $foo; /** * @Group(disabled=true) */ public $bar; public $baz; /** @var array */ public $fooGroup; }
查询:?foo=fooValue&bar=barValue&baz=bazValue&exampleGroup=bug&nextGroup=bug
$fooGroup
将是
[ 'baz' => 'bazValue', ];
$barGroup
将是(动态定义)
[ 'foo' => 'fooValue', ];
可用的分组注解选项
您可以将此注解应用于类(它将应用于每个属性),或应用于属性
目标
目标组变量。无论目标是否定义,转换器都将变量放入给定的目标。
disabled
您仍然可以使用属性注入,但它将禁用属性或整个类的分组。
重要提示
- 分组属性不可注入
- 分组注解可用于类或属性
- 您可以使用
@Metglobal\DTOBundle\Annotation\PostSet
事件修改分组 - 如果您禁用了属性注入(
@Metglobal\DTOBundle\Annotation\Parameter(disabled=true)
),它也会将属性设置到分组中。要禁用,将分组的disabled
选项设置为 true。
贡献
如果您遇到问题、发现错误或有功能建议,请在 Github 上记录问题。如果您想自己尝试,请 fork 包并提交 pull request。请包括任何添加或更改的功能的测试。如果是错误,请包括回归测试。