定制 eve/dto 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

eve/dto

Composer 安装命令:

composer require eve/dto

包简介

Simplistic, flexible Data Transfer Object library

README 文档

README

Main Latest version

A simplistic, flexible Data Transfer Object library written in PHP.

Why?

It's arguably a common practice to pass data as associative arrays between layers. For example, a service method to create a new user may look like this:

// UserService.php
public function createUser(array $attributes): User
{
    return User::create($attributes);
}

The method can be called by e.g., a controller this way:

// UserController.php
public function store(CreateUserRequest $request)
{
    $this->userService->create($request->toArray());
}

This kind of works, but with several drawbacks:

  • An associative array is pretty much unstructured—there's virtually no restriction on what can be put in it or what the data type of each element should be. This makes the code hard to reason about (no exact clue what's inside the array) and can lead to serious security issues.
  • One would always have to refer to the documentation (if one exists) for the "shape" of the array. This reduces both reusability and productivity.
  • Static code analysis and IDE auto-completion support are greatly hindered.

Now imagine instead of using an arbitrary array, we use an object with typed properties:

// UserCreationData.php
class UserCreationData
{
    public string $email;
    public string $password;
    public ?int $age;
}

// UserService.php
public function createUser(UserCreationData $data): User
{
    return User::create($data->toArray());
}

// UserController.php
public function store(CreateUserRequest $request)
{
    $this->userService->create(UserCreationData::fromRequest($request));
}

With this approach, we have a clear idea of what fields to expect as user creation data, their types and other restrictions, and we can enjoy all type-hinting, auto-completion, static analysis etc. This is exactly what eve/dto allows you to do.

Requirements and Installation

You can install eve/dto via Composer:

composer require eve/dto

This package requires PHP ≥7.4.

Migrate from v1.x

v1.x versions of this library include a strict type check—for example, assigning a string to a boolean property will throw an error. Though certainly useful, this feature doesn't belong in the scope of a DTO and has been removed from v2. You're encouraged to use a static analysis tool like PHPStan or Psalm for the task instead.

Usage

Basic Usage

Following the example above, firstly, we make UserCreationData extends Eve\DTO\DataTransferObject and define all attributes as public properties:

class UserCreationData extends \Eve\DTO\DataTransferObject
{
    public string $email;
    public string $password;
    public ?int $age;
}

To construct a new UserCreationData instance, call make with an array of parameters:

$data = UserCreationData::make([
   'email' => 'alice@company.tld',
   'password' => 'SoSecureWow',
   'age' => 30,
]);

Alternatively, you can explicitly set the attributes. The code above is essentially the same as:

$data = UserCreationData::make();
$data->email = 'alice@company.tld';
$data->password = 'SoSecureWow';
$data->age = 30;

Or you can use the fluent set method, which can take either an associative array or two separated $name, $value parameters:

$data = UserCreationData::make()
    ->set('email', 'alice@company.tld')
    ->set([
       'password' => 'SoSecureWow',
       'age' => 30,
    ]);

If any of the passed properties doesn't exist in the class definition, an exception will be thrown:

UserCreationData::make(['nope' => 'bar']); // throws "Public property $nope does not exist in class UserCreationData"

Then we can call the toArray() method to transform the object into an associative array:

$arr = $data->toArray(); // ['email' => 'alice@company.tld', 'password' => 'SoSecureWow', 'age' => 30]

Note that non-set properties will NOT be included in the output array:

$data = UserCreationData::make();

// Only setting email now
$data->email = 'alice@company.tld';

$arr = $data->toArray(); // ['email' => 'alice@company.tld']

This is especially handy e.g., if you have a method to patch a database record, as it allows the operation to be totally flexible—you can patch all properties or only a subset of them.

Nested DTOs

Nested DTOs will be transformed into their corresponding arrays:

class UserCreationData extends \Eve\DTO\DataTransferObject
{
    public string $email;
    public string $password;
    public UserInformationData $information;
}

class UserInformationData extends \Eve\DTO\DataTransferObject
{
    public int $age;
}

$data = UserCreationData::make([
   'email' => 'alice@company.tld',
   'password' => 'SoSecureWow',
   'information' => UserInformationData::make(['age' => 30]),
]);

$data->toArray(); // ['email' => 'alice@company.tld', 'password' => 'SoSecureWow', ['information' => ['age' => 30]]

Helper Functions

  • DataTransferObject::only(string ...$names): static returns the object that includes only $names in the output array.

    $data = UserCreationData::make([
       'email' => 'alice@company.tld',
       'password' => 'SoSecureWow',
       'age' => 30,
    ]);
    
    $data->only('email', 'password')->toArray(); // ['email' => 'alice@company.tld', 'password' => 'SoSecureWow']
  • DataTransferObject::except(string ...$names): static returns the object that exludes $names from the output array.

    $data = UserCreationData::make([
       'email' => 'alice@company.tld',
       'password' => 'SoSecureWow',
       'age' => 30,
    ]);
    
    $data->except('email', 'password')->toArray(); // ['age' => 30]
  • DataTransferObject::compact(): static returns the object that includes only properties whose values are not NULL in the output array.

    $data = UserCreationData::make([
       'email' => 'alice@company.tld',
       'password' => 'SoSecureWow',
       'age' => null,
    ]);
    
    $data->compact()->toArray(); // ['email' => 'alice@company.tld', 'password' => 'SoSecureWow']
  • DataTransferObject::get(string $name, $default = null): mixed returns the value of $name property. If $name doesn't exist in the class definition, an exception will be thrown. If $name exists but not initialized, $default will be returned.

    Important: PHP treats non-typed properties e.g., public $prop as initialized with NULL.

    $data = UserCreationData::make([
       'email' => 'alice@company.tld',
       'password' => 'SoSecureWow',
    ]);
    
    $data->get('email'); // 'alice@company.tld'
    $data->password; // 'SoSecureWow'
    
    $data->age; // throws "UserCreationData::$age must not be accessed before initialization."
    $data->get('age', 30); // 30
    
    $data->get('nope'); // throws "Public property $nope does not exist in class UserCreationData."
    $data->nope; // throws "Public property $nope does not exist in class UserCreationData."

Differences from spatie/data-transfer-object

Though eve/dto is inspired by and shares some similarities with spatie/data-transfer-object, the two packages have certain differences, the most significant of which are as follows:

  • spatie/data-transfer-object requires all not-null properties to be supplied right from instantiation. This behavior is not always feasible or desirable (refer to the data patching example above). eve/dto opts for a much more forgiving approach, which allows a DTO to be created with any subset of properties.
  • spatie/data-transfer-object can't detect or prevent you from assigning a non-existent property directly (e.g., $userData->non_existent = 'foo'), which is something eve/dto does to help ensure your object's integrity.
  • spatie/data-transfer-object implements such features as "Data Transfer Object Collection" and "Flexible Data Transfer Objects." To keep things simple and concise, eve/dto doesn't have these implementations.

License

MIT

eve/dto 适用场景与选型建议

eve/dto 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 14.81k 次下载、GitHub Stars 达 12, 最近一次更新时间为 2021 年 03 月 04 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 eve/dto 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 eve/dto 我们能提供哪些服务?
定制开发 / 二次开发

基于 eve/dto 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 14.81k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 12
  • 点击次数: 16
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 12
  • Watchers: 6
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-03-04