knobik/data-transfer-object

带电池的数据传输对象

1.9.0 2019-04-10 08:05 UTC

README

基于https://github.com/spatie/data-transfer-object

Latest Version on Packagist Build Status Quality Score StyleCI Total Downloads

安装

您可以通过composer安装此软件包

composer require spatie/data-transfer-object

您是否曾经…

…与从请求、CSV文件或JSON API检索的数组数据一起工作,并想知道其中有什么内容?

以下是一个示例

public function handleRequest(array $dataFromRequest)
{
    $dataFromRequest[/* what to do now?? */];
}

此软件包的目标是结构化“非结构化数据”,这些数据通常存储在关联数组中。通过将此数据结构化为对象,我们可以获得几个优势

  • 我们可以对数据传输对象进行类型提示,而不仅仅是调用它们array
  • 通过使我们的对象的所有属性都是可类型的,我们可以确保它们的值永远不会是我们未预期的。
  • 由于属性是类型的,我们可以静态分析它们,并具有自动完成功能。

让我们看看一个JSON API调用的示例

$post = $api->get('posts', 1); 

[
    'title' => '',
    'body' => '',
    'author_id' => '',
]

处理此数组很困难,因为我们始终必须参考文档才能知道其中确切的内容。此软件包允许您创建数据传输对象定义,类,这些类将以结构化的方式表示数据。

我们尽量减少语法和开销

class PostData extends DataTransferObject
{
    /** @var string */
    public $title;
    
    /** @var string */
    public $body;
    
    /** @var \Author */
    public $author;
}

现在可以像这样构建PostData对象

$postData = new PostData([
    'title' => '',
    'body' => '',
    'author_id' => '',
]);

现在您可以使用结构化的方式使用这些数据

$postData->title;
$postData->body;
$postData->author_id;

当然,您可以为PostData添加静态构造函数

class PostData extends DataTransferObject
{
    // …
    
    public static function fromRequest(Request $request): self
    {
        return new self([
            'title' => $request->get('title'),
            'body' => $request->get('body'),
            'author' => Author::find($request->get('author_id')),
        ]);
    }
}

通过为我们属性添加文档块,它们的值将与给定的类型进行验证;如果值不符合给定的类型,将抛出TypeError

以下是声明类型可能的几种方式

class PostData extends DataTransferObject
{
    /**
     * Built in types: 
     *
     * @var string 
     */
    public $property;
    
    /**
     * Classes with their FQCN: 
     *
     * @var \App\Models\Author
     */
    public $property;
    
    /**
     * Lists of types: 
     *
     * @var \App\Models\Author[]
     */
    public $property;
    
    /**
     * Union types: 
     *
     * @var string|int
     */
    public $property;
    
    /**
     * Nullable types: 
     *
     * @var string|null
     */
    public $property;
    
    /**
     * Mixed types: 
     *
     * @var mixed|null
     */
    public $property;
    
    /**
     * No type, which allows everything
     */
    public $property;
}

当PHP 7.4引入类型属性时,您只需简单地删除文档块,并使用新的内置语法类型化属性。

处理集合

如果您正在处理DTO的集合,您可能希望对您的集合也进行自动完成和适当的类型验证。此软件包添加了一个简单的集合实现,您可以从它扩展。

use \Spatie\DataTransferObject\DataTransferObjectCollection;

class PostCollection extends DataTransferObjectCollection
{
    public function current(): PostData
    {
        return parent::current();
    }
}

通过重写current方法,您将在IDE中获得自动完成,并像这样使用集合。

foreach ($postCollection as $postData) {
    $postData-> // … your IDE will provide autocompletion.
}

$postCollection[0]-> // … and also here.

当然,您可以自由地实现自己的静态构造函数

class PostCollection extends DataTransferObjectCollection
{
    public static function create(array $data): PostCollection
    {
        $collection = [];

        foreach ($data as $item)
        {
            $collection[] = PostData::create($item);
        }

        return new self($collection);
    }
}

嵌套DTO的自动转换

如果您有嵌套DTO字段,传递给父DTO的数据将自动进行转换。

class PostData extends DataTransferObject
{
    /** @var \AuthorData */
    public $author;
}

PostData现在可以构建如下

$postData = new PostData([
    'author' => [
        'name' => 'Foo',
    ],
]);

嵌套数组DTO的自动转换

类似于上述内容,嵌套数组DTO将自动进行转换。

class TagData extends DataTransferObject
{
    /** @var string */
   public $name;
}

class PostData extends DataTransferObject
{
    /** @var \TagData[] */
   public $tags;
}

PostData将自动构建标签如下

$postData = new PostData([
    'tags' => [
        ['name' => 'foo'],
        ['name' => 'bar']
    ]
]);

注意:要使嵌套类型转换正常工作,您的Docblock定义需要是完整限定类名(例如\App\DTOs\TagData[]而不是TagData[],并在顶部使用use语句)

不可变性

如果您希望数据对象永远不会更改(在某些情况下这是一个好主意),您可以使其不可变

$postData = PostData::immutable([
    'tags' => [
        ['name' => 'foo'],
        ['name' => 'bar']
    ]
]);

尝试在构建$postData后更改其属性将导致DataTransferObjectError

辅助函数

还提供了一些辅助函数,用于同时处理多个属性。

$postData->all();

$postData
    ->only('title', 'body')
    ->toArray();
    
$postData
    ->except('author')
    ->toArray();

您还可以链接这些方法

$postData
    ->except('title')
    ->except('body')
    ->toArray();

请注意,exceptonly 是不可变的,它们不会更改原始的数据传输对象。

异常处理

除了属性类型验证外,您还可以确信整个数据传输对象始终有效。在构建数据传输对象时,我们将验证所有必需的(非可为空的)属性是否已设置。如果没有,将抛出 Spatie\DataTransferObject\DataTransferObjectError

同样,如果您尝试设置未定义的属性,您将得到一个 DataTransferObjectError

测试

composer test

变更日志

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

贡献

有关详细信息,请参阅贡献指南

安全

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

明信片软件

您可以使用这个包,但如果它进入您的生产环境,我们非常感谢您从您的家乡给我们寄一张明信片,注明您正在使用我们哪个包。

我们的地址是:Spatie,Samberstraat 69D,2060 安特卫普,比利时。

我们将在我们的公司网站上发布所有收到的明信片

致谢

我们的 Arr 类包含从 Laravel 的 Arr 辅助函数中复制的函数。

支持我们

Spatie 是一家位于比利时的安特卫普网页设计公司。您可以在我们的网站上找到所有开源项目的概述在这里

您的业务依赖于我们的贡献吗?联系我们在Patreon上的支持。所有承诺都将专门用于分配人力进行维护和新奇事物。

许可证

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