danilovl / doctrine-entity-dto-bundle
这个Symfony包提供了一个简单的机制,用于将Doctrine实体转换为DTO对象。
Requires
- php: ^8.3
- doctrine/doctrine-bundle: ^2
- doctrine/orm: ^2.17
- symfony/finder: ^7.0
- symfony/framework-bundle: ^7.0
- symfony/property-access: ^7.0
Requires (Dev)
- phpunit/phpunit: ^10.2
README
DoctrineEntityDtoBundle
关于
这个Symfony包提供了一个简单的机制,用于将Doctrine实体转换为DTO对象。
需求
- PHP 8.3 或更高版本
- Symfony 7.0 或更高版本
- Doctrine 2
1. 安装
使用Composer安装 danilovl/doctrine-entity-dto-bundle
包
composer require danilovl/doctrine-entity-dto-bundle
如果未自动添加,请将 DoctrineEntityDtoBundle
添加到应用程序的包中
<?php // config/bundles.php return [ // ... Danilovl\DoctrineEntityDtoBundle\DoctrineEntityDtoBundle::class => ['all' => true] ];
2. 配置
安装包后,您可以在 danilovl_doctrine_entity_dto.yaml
中更改配置设置。
默认配置。
danilovl_doctrine_entity_dto: isEnableEntityDTO: false isEnableEntityRuntimeNameDTO: false isAsEntityDTO: false entityDTO: [] isEnableScalarDTO: false isAsScalarDTO: false scalarDTO: []
3. 使用
3.1 实体DTO
如果 isEnableEntityDTO
为 true,则 DoctrineEntityDtoBundle
会自动为每个实体类名创建 doctrine 活化。
danilovl_doctrine_entity_dto: isEnableEntityDTO: true
您可以添加一个控制属性 isAsEntityDTO
,只有具有此属性的实体才会创建 DTO 活化。
danilovl_doctrine_entity_dto: isEnableEntityDTO: true isAsEntityDTO: true
#[ORM\Table(name: 'cheque')] #[AsEntityDTO] class Cheque
您可以选择自己的实体数组。
danilovl_doctrine_entity_dto: isEnableEntityDTO: true entityDTO: - App\Domain\Cheque\Entity\Cheque
或者,您可以将列表与属性控制结合使用。
danilovl_doctrine_entity_dto: isEnableEntityDTO: true isAsEntityDTO: true entityDTO: - App\Domain\Cheque\Entity\Cheque
您只需要使用实体的别名名称,并将实体类名称添加到 getResult
方法中。
别名名称选择表中的所有数据。
$result = $this->entityManager ->getRepository(Cheque::class) ->baseQueryBuilder() ->select('cheque, city, shop, product') ->leftJoin('cheque.shop', 'shop') ->leftJoin('shop.city', 'city') ->leftJoin('cheque.orderList', 'orderList') ->leftJoin('orderList.product', 'product') ->setMaxResults(10) ->getQuery() ->getResult(Cheque::class);
结果将与 Doctrine 的结果相同,但无需与工作单元连接。
array:2 [▼ 0 => App\Domain\Cheque\Entity\Cheque {#1107 ▼ +price: "105.4" +chequeNumber: "0119-201703119-02-9380" +shop: App\Domain\Shop\Entity\Shop {#1091 ▶} +currency: ? App\Domain\Currency\Entity\Currency +orderList: ? Doctrine\Common\Collections\Collection +walletTransaction: ? App\Domain\Wallet\Entity\WalletTransaction #id: 4 #date: DateTime @1489878000 {#1083 ▶} #createdAt: DateTime @1489878000 {#1081 ▶} #updatedAt: DateTime @1489878000 {#1071 ▶} } 1 => App\Domain\Cheque\Entity\Cheque {#1094 ▼ +price: "311.27" +chequeNumber: "0019-20170318-05-9278" +shop: App\Domain\Shop\Entity\Shop {#1141 ▶} +currency: ? App\Domain\Currency\Entity\Currency +orderList: ? Doctrine\Common\Collections\Collection +walletTransaction: ? App\Domain\Wallet\Entity\WalletTransaction #id: 5 #date: DateTime @1489791600 {#1142 ▶} #createdAt: DateTime @1489791600 {#1139 ▶} #updatedAt: DateTime @1489791600 {#1138 ▶} } ]
如果您希望 DTO 类的名称与实体类名称不同,请使用参数 isEnableEntityRuntimeNameDTO
。
它根据模式 %sRuntimeDTO
创建名称。
请注意,此功能使用 eval
函数。
array:2 [▼ 0 => ChequeRuntimeDTO {#1107 ▼ +price: "105.4" +chequeNumber: "0119-201703119-02-9380" +shop: App\Domain\Shop\Entity\Shop {#1091 ▶} +currency: ? App\Domain\Currency\Entity\Currency +orderList: ? Doctrine\Common\Collections\Collection +walletTransaction: ? App\Domain\Wallet\Entity\WalletTransaction #id: 4 #date: DateTime @1489878000 {#1083 ▶} #createdAt: DateTime @1489878000 {#1081 ▶} #updatedAt: DateTime @1489878000 {#1071 ▶} } 1 => ChequeRuntimeDTO {#1094 ▼ +price: "311.27" +chequeNumber: "0019-20170318-05-9278" +shop: App\Domain\Shop\Entity\Shop {#1141 ▶} +currency: ? App\Domain\Currency\Entity\Currency +orderList: ? Doctrine\Common\Collections\Collection +walletTransaction: ? App\Domain\Wallet\Entity\WalletTransaction #id: 5 #date: DateTime @1489791600 {#1142 ▶} #createdAt: DateTime @1489791600 {#1139 ▶} #updatedAt: DateTime @1489791600 {#1138 ▶} } ]
3.2 基本DTO
如果 isAsScalarDTO
为 true,它将自动扫描 src
项目目录中的每个文件,尝试找到具有 AsScalarDTO
属性的类。
当您使用 AsScalarDTO
属性时,结果命名空间将缓存到 prod
环境。
danilovl_doctrine_entity_dto: isEnableScalarDTO: true isAsScalarDTO: true
您可以在配置中声明自己的 DTO 类的命名空间列表,而无需使用属性。
danilovl_doctrine_entity_dto: isEnableScalarDTO: true scalarDTO: - App\Domain\Cheque\EntityDTO\ChequeDTO
或者,您可以将属性和列表结合使用。最终结果将合并。
danilovl_doctrine_entity_dto: isEnableScalarDTO: true isAsScalarDTO: true scalarDTO: - App\Domain\Cheque\EntityDTO\ChequeDTO
ChequeDTO
的示例。
<?php declare(strict_types=1); namespace App\Domain\Cheque\EntityDTO; use Danilovl\DoctrineEntityDtoBundle\Attribute\AsScalarDTO; #[AsScalarDTO] class ChequeDTO { public function __construct( public readonly int $id, public readonly string $chequeNumber ) {} }
在执行基本选择之前,您需要将类名设置为静态属性 $dtoClass
。
在调用 getResult
之后,ScalarHydration
将静态 $dtoClass
参数设置为 null
。
这是 Doctrine 活化的限制,当您使用基本选择时,Doctrine ResultSetMapping
为空。
ScalarHydration::$dtoClass = ChequeDTO::class; $this->entityManager ->getRepository(Cheque::class) ->baseQueryBuilder() ->select('cheque.id, cheque.chequeNumber') ->setMaxResults(2) ->getQuery() ->getResult(ChequeDTO::class);
因此,选择查询返回 DTO 对象数组。
array:2 [▼ 0 => App\Domain\Cheque\EntityDTO\ChequeDTO {#1065 ▼ +id: 4136 +chequeNumber: "165791" } 1 => App\Domain\Cheque\EntityDTO\ChequeDTO {#1066 ▼ +id: 5838 +chequeNumber: "539349913" } ]
4. 其他
例如,当您使用 knplabs/knp-components
创建分页器并将 Doctrine 查询设置为分页时,如果要将 DTO 对象作为结果创建,请简单地将类使用 setHydrationMode
方法添加。
$this->paginator->paginate($query->setHydrationMode(class::class));
如果使用 Gedmo Translatable DoctrineExtensions,还需要 setHint
。
$query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class); $query->setHydrationMode(Product::class);
许可证
DoctrineEntityDtoBundle 是开源软件,许可协议为 MIT 许可证。