dkx/json-api

该软件包已被废弃且不再维护。未建议替代软件包。

Json api 转换器

2.0.2 2020-02-05 14:31 UTC

This package is auto-updated.

Last update: 2024-02-05 23:23:12 UTC


README

框架无关的PHP JsonApi转换器。

安装

$ composer require dkx/json-api

转换器

<?php

use DKX\JsonApi\Item;
use DKX\JsonApi\Transformer;
use DKX\JsonApi\TransformContext;

class BookTransformer implements Transformer
{    
    public function supports(object $item): bool 
    {
        return $item instanceof Book;
    }
    
    public function transform(object $item, TransformContext $ctx): Item
    {
        if (!$item instanceof Book) {
            throw new ShouldNotHappenException;
        }
        
        return new Item('book', $item->id, [
            Item::ATTRIBUTES => [
                'title' => $item->title,
                'content' => $item->content,
            ],
        ]);
    }
}

使用

<?php

use DKX\JsonApi\Manager;

$manager = new Manager;
$manager->addTransformer(new BookTransformer);

$json = $manager->itemToArray($books->getById(5));

// or collection

$json = $manager->collectionToArray($books->getAll());

关系

<?php

use DKX\JsonApi\Item;

new Item('book', $item->id, [
    Item::ATTRIBUTES => [
        'title' => $item->title,
        'content' => $item->content,
    ],
    Item::RELATIONSHIPS => [
       'user' => $item->user,
   ],
]);

现在我们可以这样加载user关系

<?php

$manager->itemToArray($books->getOneById(5), ['user']);

懒加载关系

<?php

use DKX\JsonApi\Item;

new Item('book', $item->id, [
    Item::ATTRIBUTES => [
        'title' => $item->title,
        'content' => $item->content,
    ],
    Item::RELATIONSHIPS => [
        'user' => function () use ($item) {
            return $users->getOneById($item->userId);
        },
    ],
]);

解决N+1问题

<?php

use DKX\JsonApi\Deferred;
use DKX\JsonApi\Item;

new Item('book', $item->id, [
    Item::ATTRIBUTES => [
        'title' => $item->title,
        'content' => $item->content,
    ],
    Item::RELATIONSHIPS => [
        'user' => function () use ($item) {
            MyUserBuffer::add($item->userId);

            return new Deferred(function () use ($item) {
                MyUserBuffer::loadBuffered();
                return MyUserBuffer::get($item->userId);
            });
        },
    ],
]);

在这里解决N+1问题的逻辑是将所有ID存储到缓冲区中,然后通过一个查询(使用IN(?) SQL子句)加载所有实体,然后从加载的数组中选取所需的实体。

批量处理

Batch只是Deferred的另一种形式,使用更简单。

<?php

use DKX\JsonApi\Batch;
use DKX\JsonApi\Item;

new Item('book', $item->id, [
    Item::ATTRIBUTES => [
        'title' => $item->title,
        'content' => $item->content,
    ],
    Item::RELATIONSHIPS => [
        'user' => function () use ($item) {
            return new Batch('bookUsersById', $item->userId, function (array $ids) {
                return $usersRepository->getByIds($ids);
            }, function (array $users) use ($item) {
                return $users[$item->userId];
            });
        },
    ],
]);

每个Batch必须有一个作用域(例如:bookUsersById),用于收集所有关系ID(Batch的第二个参数)。

第一个回调必须返回一个包含所有可能通过所有ID(在作用域中收集)选择的关系的数组。

第二个回调接收第一个回调返回的数据,必须为当前项返回一个关系数据。