dkx / json-api
This package is abandoned and no longer maintained.
No replacement package was suggested.
Json api transformers
2.0.2
2020-02-05 14:31 UTC
Requires
- php: ^7.3
- dkx/json-api-serializer: ^2.0.0
Requires (Dev)
- phpstan/extension-installer: ^1.0
- phpstan/phpstan: ^0.11.8
- phpstan/phpstan-phpunit: ^0.11.2
- phpstan/phpstan-strict-rules: ^0.11.1
- phpunit/phpunit: ^8.0
README
Framework agnostic PHP JsonApi transformer.
Installation
$ composer require dkx/json-api
Transformer
<?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,
],
]);
}
}
Usage
<?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());
Relationships
<?php
use DKX\JsonApi\Item;
new Item('book', $item->id, [
Item::ATTRIBUTES => [
'title' => $item->title,
'content' => $item->content,
],
Item::RELATIONSHIPS => [
'user' => $item->user,
],
]);
Now we can load the user
relationship like this:
<?php
$manager->itemToArray($books->getOneById(5), ['user']);
Lazy relationships
<?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);
},
],
]);
Solving N+1 Problem
<?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);
});
},
],
]);
The logic behind solving the N+1 problem here is to store all IDs into a buffer, then load all entities with one query
(with IN(?)
SQL clause) and later select the requested entity from loaded array.
Batch:
Batch
is just another form of Deferred
with simpler usage.
<?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];
});
},
],
]);
Each Batch
must have a scope (eg. bookUsersById
) which is used to collect all relationship ids (second argument of Batch
).
First callback must return an array with all possible relationships selected by all ids (collected in scope).
Second callback receives data returned from the first callback and must return one relationship data for current item.