cerbero/laravel-dto

Laravel 的数据传输对象 (DTO)

资助包维护!
cerbero90

2.2.2 2021-05-17 13:19 UTC

This package is auto-updated.

Last update: 2024-09-09 14:29:37 UTC


README

Author PHP Version Laravel Version Octane Compatibility Build Status Coverage Status Quality Score Latest Version Software License PSR-12 Total Downloads

Laravel DTO 集成了 DTO 包,这是一个受 Lachlan Krautz 的优秀 数据传输对象 启发的包,并增加了 Laravel 的功能。

数据传输对象 (DTO) 是在进程间携带数据的对象。DTO 除了存储、检索、序列化和反序列化自身数据外,没有其他行为。DTO 应该是简单的对象,不应包含任何业务逻辑,而应用于数据传输。

以下将解释该包为 Laravel 应用程序带来的优势。要了解 DTO 的所有功能,请参阅 完整的 DTO 文档

安装

通过 Composer

composer require cerbero/laravel-dto

为了自定义此包的一些方面,可以通过以下方式生成 config/dto.php 文件

php artisan vendor:publish --tag=dto

使用

生成 DTO

Eloquent 模型的 DTO 可以通过运行以下 Artisan 命令自动生成

php artisan make:dto App/User

将指定模型的数据库表扫描以填充 DTO 属性。此外,如果模型有关系,还会为每个相关模型生成一个 DTO。例如,如果我们的 User 模型看起来像

class User extends Model
{
    public function posts()
    {
        return $this->hasMany('App\Post');
    }
}

生成的 DTO 如下所示 App\Dtos\UserDataApp\Dtos\PostData

use Cerbero\LaravelDto\Dto;
use Carbon\Carbon;

use const Cerbero\Dto\PARTIAL;
use const Cerbero\Dto\IGNORE_UNKNOWN_PROPERTIES;

/**
 * The data transfer object for the User model.
 *
 * @property int $id
 * @property string $name
 * @property Carbon $createdAt
 * @property Carbon $updatedAt
 * @property PostData[] $posts
 */
class UserData extends Dto
{
    /**
     * The default flags.
     *
     * @var int
     */
    protected static $defaultFlags = PARTIAL | IGNORE_UNKNOWN_PROPERTIES;
}

/**
 * The data transfer object for the Post model.
 *
 * @property int $id
 * @property string $content
 * @property int $userId
 * @property Carbon $createdAt
 * @property Carbon $updatedAt
 * @property UserData $user
 */
class PostData extends Dto
{
    /**
     * The default flags.
     *
     * @var int
     */
    protected static $defaultFlags = PARTIAL | IGNORE_UNKNOWN_PROPERTIES;
}

默认情况下,DTO 在 Dtos 目录中生成,该目录与模型所在的目录相同。例如,App\User 的 DTO 生成为 App\Dtos\UserData,而 App\Users\User 的 DTO 生成为 App\Users\Dtos\UserData

要更改生成的 DTO 的位置或后缀 Data,我们可以通过实现接口 DtoQualifierContract 创建 DTO 标准化器,并在 config/dto.php 中替换默认标准器。以下示例将 DTO 标准化到模型的目录中,并添加后缀 Dto

use Cerbero\LaravelDto\DtoQualifierContract;

class MyDtoQualifier implements DtoQualifierContract
{
    public function qualify(string $model): string
    {
        return $model . 'Dto';
    }
}

// in config/dto.php
return [
    'qualifier' => MyDtoQualifier::class,
];

最后,如果模型已生成自己的 DTO,我们可以使用 --force-f 选项覆盖它

php artisan make:dto App/User --force

实例化 DTO

除了 传统的 DTO 实例化方法 之外,Laravel DTO 还提供了方便的方法,可以从 HTTP 请求、Eloquent 模型或其他 Laravel 中常见的接口创建 DTO 的新实例。

例如,可以通过调用 fromRequest() 方法从 HTTP 请求中实例化 UserData

use App\Dtos\UserData;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function store(Request $request)
    {
        $dto = UserData::fromRequest($request);
    }
}

传递给 fromRequest() 方法的请求是可选的:如果不提供,将使用当前应用程序请求来实例化 UserData

默认情况下,当从请求实例化DTO时,会应用PARTIALIGNORE_UNKNOWN_PROPERTIES标志。可以通过将附加标志作为第二个参数传递,以进一步自定义DTO的行为。

要从Eloquent模型实例化DTO,我们可以调用fromModel()方法。

$user = new User(['name' => 'Phil']);

$dto = UserData::fromModel($user);

当从模型实例化DTO时,会应用PARTIALIGNORE_UNKNOWN_PROPERTIESCAST_PRIMITIVES标志。可以通过将附加标志作为第二个参数传递。

最后,from()方法可以从多个接口(特定于Laravel或不是)实例化DTO,包括

  • Illuminate\Support\Enumerable
  • Illuminate\Contracts\Support\Arrayable
  • Illuminate\Contracts\Support\Jsonable
  • JsonSerializable
  • Traversable
  • 任何可以转换为数组的值

在这种情况下,默认情况下不应用任何标志,但它们仍然可以作为第二个参数传递。

解析 DTO

只要在DTO的默认标志中设置了PARTIAL,则此类DTO可以由Laravel IoC容器自动解析,使用当前应用程序请求携带的数据

use App\Dtos\UserData;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    public function store(UserData $dto)
    {
        // ...
    }
}

转换为 DTO

获取不同对象DTO实例的另一种方法是让它们使用特性TurnsIntoDto并调用方法toDto()

use Cerbero\LaravelDto\Traits\TurnsIntoDto;

class StoreUserRequest extends Request
{
    use TurnsIntoDto;
}

class User extends Model
{
    use TurnsIntoDto;

    protected $dtoClass = UserData::class;
}

class Example
{
    use TurnsIntoDto;

    protected function getDtoClass(): ?string
    {
        return $condition ? UserData::class : OtherDto::class;
    }
}

$dto = $request->toDto(UserData::class, MUTABLE);
$dto = $user->toDto(CAST_PRIMITIVES);
$dto = $example->toDto();

使用特性的类可以指定要转换的DTO

  • 通过将DTO类名作为toDto()方法的第一个参数传递
  • 定义属性$dtoClass
  • 如果需要自定义逻辑,则覆盖方法getDtoClass()

可以可选地作为第二个参数传递标志,或者如果DTO类已在使用特性的类中定义,则作为第一个参数。当模型转换为DTO时,将添加标志CAST_PRIMITIVES以帮助转换值,如果Eloquent模型上未定义转换。

转换为数组

默认情况下,Laravel DTO为Carbon实例注册了一个值转换器。当将DTO转换为数组时,所有其Carbon对象都转换为原子字符串,然后在实例化新DTO时转换回Carbon实例。

$dto = UserData::make(['created_at' => '2000-01-01']);
$dto->createdAt; // Carbon instance
$data = $dto->toArray(); // ['created_at' => '2000-01-01T00:00:00+00:00']

$dto = UserData::make($data);
$dto->createdAt; // Carbon instance

可以在config/dto.php文件中添加或删除转换,具体是通过键conversions

use Carbon\Carbon;
use Cerbero\LaravelDto\Manipulators\CarbonConverter;

return [
    'conversions' => [
        Carbon::class => CarbonConverter::class,
    ],
];

监听事件

此软件包添加到监听器的唯一功能是能够通过Laravel IoC容器解析依赖关系。可以将依赖关系注入到监听器的构造函数中,以便自动解析。

可以在config/dto.php文件中添加或删除监听器,具体是通过键listeners

return [
    'listeners' => [
        UserData::class => UserDataListener::class,
    ],
];

全局定义标志

有时我们可能希望所有DTO共享相同的标志,例如,始终使用可变DTO的需求。完成此操作的一种简单方法是在config/dto.php文件中定义此类标志。

return [
    'flags' => MUTABLE,
];

支持宏

如果需要向所有DTO添加功能,则可以使用宏。请参阅Laravel文档以查看如何注册宏的示例。

DTO 调试

当使用辅助函数 dump()dd() 时,只会显示 DTO 数据,而不是使包工作的底层架构。

dd($dto);

// only DTO data is shown:

App\Dtos\UserData {#3224
  +name: "Phil"
}

变更日志

有关最近更改的更多信息,请参阅变更日志

测试

composer test

贡献

有关详细信息,请参阅贡献指南行为准则

安全

如果您发现任何安全相关的问题,请通过电子邮件andrea.marco.sartori@gmail.com联系,而不是使用问题跟踪器。

鸣谢

许可协议

MIT 许可协议(MIT)。有关更多信息,请参阅许可文件