danilovl/doctrine-entity-dto-bundle

这个Symfony包提供了一个简单的机制,用于将Doctrine实体转换为DTO对象。

v0.1.9 2024-05-21 21:45 UTC

This package is auto-updated.

Last update: 2024-09-16 09:35:29 UTC


README

phpunit downloads latest Stable Version license

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 许可证