liteacz/dto

此包已被废弃,不再维护。作者建议使用 litea/dto 包。

数据传输库,帮助您处理未知数据

v0.0.1 2020-05-04 10:04 UTC

This package is auto-updated.

Last update: 2020-05-05 09:37:45 UTC


README

不需要阅读关于DTO动机的细节吗?

🚀 直接跳转到操作!

我们试图解决这个问题

<?php
$user = $client->getUser();

// How do we access user's name?
// Like this?
echo $user['name'];

// Or is it more like this?
echo $user['first_name'];

// I don't remember, it's been while...
// Is it something like this?
echo $user['full_name'];

// Or was it camelCased?!
echo $user['fullName'];

现在,有了数据传输库

<?php

use \Litea\DataTransfer\DataObject;

class User extends DataObject
{
    /**
     * @var string
     * @dto-property first_name
     * So it was snake_case after all...
     */
    public $fistName;

    /**
     * @var string
     * @dto-property LastName
     * And last name is PascalCased? What?
     * It's weird API we're dealing with, indeed.
     * Fortunately we can easily rename it for our purposes.
     */
    public $lastName;
}

$response = $client->getUser();
$user = User::create($response);

// There we go!
// Now, we've got an auto-completion and everything.
echo $user->firstName;
echo $user->lastName;

📖 文档

以下您将找到此库的基本用法。更多详情请参阅此仓库的 docs 目录中的文档。

目录

关于

处理外部数据时,通常以非常通用和动态的形式出现,这使得在一段时间后返回代码时难以推理。

这可以通过所谓的数据传输对象(DTOs)来解决,它们提供具有静态属性的对象包装,这些属性可以提供对底层值的访问。

这些对象很快就会变得重复,在第二个或第三个DTO之后,您就会想使用好的旧CTRL+C、CTRL+V,这很容易出错且难以维护。

这是一个实际生活中的DTO对象示例,可以帮助您更好地控制传入的数据

<?php

class InitCallResponse
{
    public const REDIRECT_URL = 'redirectURL';
    public const REQUEST_ID = 'requestID';

    /**
     * @var string
     */
    public $redirectUrl;

    /**
     * @var string
     */
    public $requestId;

    /**
     * InitCallResponse constructor.
     * @param string $redirectUrl
     * @param string $requestId
     */
    public function __construct(string $redirectUrl, string $requestId)
    {
        $this->redirectUrl = $redirectUrl;
        $this->requestId = $requestId;
    }

    /**
     * @param array $data
     * @return self
     * @throws MissingDataTransferPropertyException
     */
    public static function create(array $data): self
    {
        $required = [
            self::REDIRECT_URL,
            self::REQUEST_ID
        ];

        foreach ($required as $field) {
            if (!array_key_exists($field, $data)) {
                throw new MissingDataTransferPropertyException(sprintf(
                    'Mandatory field %s is missing in response data',
                    $field
                ));
            }
        }

        return new self(
            $data[self::REDIRECT_URL],
            $data[self::REQUEST_ID]
        );
    }
}

如您所见,当需要维护几十个这样的对象时,显然有一个改进的地方。这就是我们决定提取一些常见的DTO功能,并以此包的形式提供它们的原因。

安装

安装此库的最简单方法是使用 composer

composer require litea/dto

基本用法

没有DTO

<?php

// Include composer's auto-loading features
require_once __DIR__ . '/vendor/autoload.php';

$client = new \GuzzleHttp\Client();
$response = $client->request('GET', 'https://jsonplaceholder.typicode.com/posts/1');
$post = json_decode((string)$response->getBody(), true);

// Now we access the data:
$postId = $post['id'];
$authorId = $post['authorId'];
$title = $post['tilte'];

// And the result:
// Notice: Undefined index: authorId in index.php on line 18
// Notice: Undefined index: tilte in index.php on line 19
// What?!
// We need to refer to the API documentation or run the code and
// debug it to find out what does the response body actually look like.
//
// As you can see, this is very error prone. First we find out, that 
// the field for accessing author's id is actually named `userId`.
// Then we might discover the typo we made and correct `tilte` to `title`.

现在假设您在应用程序中多次使用此服务。您需要特别注意不要在字段命名上犯错误或打字错误。您的IDE在这里无法帮助您。

有DTO

首先,我们需要一个表示数据的对象

<?php
namespace MyApp\DTO;

class Post extends \Litea\DataTransfer\DataObject
{
    public string $id;
    public int $userId;
}

然后,我们像往常一样获取数据

<?php

// ...
// first lines are the same
// then we get the post:
$postRaw = json_decode((string)$response->getBody(), true);

// Now we wrap it up with the DTO magic:
$post = MyApp\DTO\Post::create($postRaw);

// Now we know the structure we are dealing with:
$postId = $post->id;
$authorId = $post->userId; 

// And then, they lived happily ever after...
// The end

就是这样。如您所见,在 simplest 形式下,使用DTO对象只是定义一个扩展 Litea\DataTransfer\DataObject 的类,然后调用 MyObject::create

有关可用配置选项的更多信息,请参阅 文档 或工作 示例