aaronbullard/dogpile

JSON:API 辅助库,用于干净地导入包含的关联关系

v1.0 2019-06-28 14:49 UTC

This package is auto-updated.

Last update: 2024-09-27 09:19:14 UTC


README

Maintainability

JSON:API 辅助库,用于干净地导入包含的关联关系

安装

git clone git@github.com:aaronbullard/dogpile.git

Composer

安装PHP Composer

composer require aaronbullard/dogpile

测试

composer test

用法

首先,访问https://jsonapi.fullstack.org.cn获取JSON:API标准的文档。此库试图简化和模块化API调用中包含的相关资源对象。

Ex. GET /posts/1?include=author,comments,comments.author

此库将快速查询并包含与资源相关联的'作者'和'评论'。要做到这一点,需要实现一些接口。

// Example contoller method for GET /posts/1?include=author,comments,comments.author
public function show(Request $httpRequest): JsonResponse
{
    $postId = $httpRequest->get('postId');
    $includes = explode(',', $httpRequest->get('include')); //['author', 'comments', 'comments.author'];

    // In this example, $post implements the Dogpile\Contracts\Resource interface;
    $post = $this->myPostRepo->find($postId);

    // Example of using Dogpile\ResourceManager::class
    $includedResources = $this->resourceManager->newQuery()
        ->setRelationships($post->relationships())
        ->include(...$includes)
        ->query();

    return new JsonResponse([
        'data' => $post->toJsonapi(), // or however you want to transform your model
        'included' => array_map(function($resource){
            return $resource->toJsonapi();
        }, $includedResources);
    ], 200);
}

工作原理

Dogpile\ResourceManager类包含每个资源类型的多个ResourceQuery对象。当提供一个包含关联关系的数组时,Dogpile\QueryBuilder类将使用RelationshipCollection中的ResourceIdentifiers通过RepositoryQuery::findHavingIds()方法查询资源。每个资源只会查询一次。

设置

首先

Dogpile需要为每个资源实现Dogpile\Contracts\ResourceQuery接口。例如,你将想要为'people'(查询作者)实现一个,以及一个为'comments'。

<?php

namespace Dogpile\Contracts;

use Dogpile\Collections\ResourceCollection;

interface ResourceQuery
{
    /**
     * Returns the type of Resource Objects
     *
     * @return void
     */
    public function resourceType(): string;

    /**
     * Queries the resource based on the ids provided
     * 
     * Must return an array of objects implementing the ResourceObject interface
     *
     * @param array $ids
     * @return array
     * @throws NotFoundException
     */
    public function findHavingIds(array $ids): ResourceCollection;
}

第二

将你的ResourceQuery处理程序注册到Dogpile\ResourceManager中

<?php
// some bootstrap file

use Dogpile\ResourceManager;

$conn = $app['database_connection'];

$app[ResouceManager::class] = new ResourceManager(
    new AuthorsResourceQuery($conn),
    new CommentsResourceQuery($conn)
);

第三

Dogpile\Contracts\ResourceQuery::findHavingIds()必须返回一个包含实现Dogpile\Contracts\Resource接口的对象的Dogpile\Collections\ResourceCollection类。

<?php

namespace Dogpile\Contracts;

use Dogpile\Collections\RelationshipCollection;

interface Resource
{
    /**
     * Resource type
     *
     * @return string
     */
    public function type(): string;

    /**
     * Resource id
     *
     * @return string
     */
    public function id(): string;

    /**
     * Returns an array of ResourceIdentifiers
     *
     * @return RelationshipCollection
     */
    public function relationships(): RelationshipCollection;
}

第四

如上所述,每个资源对象必须实现Resource::realtionships()接口,该接口返回一个RelationshipCollection类。Dogpile\Collections\RelationshipCollection类可以按以下方式实现。

<?php

// Example data
$jsonapiData = [
    'type' => 'posts',
    'id' => '42',
    'attributes' => [
        'title' => 'Bridge of Death',
        'body' => 'What is the airspeed velocity of an unladed swallow?'
    ],
    'relationships' => [
        'author' => [
            'data' => ['type' => 'people', 'id' => '24']
        ],
        'comments' => [
            'data' => [
                ['type' => 'comments', 'id' => '1'],
                ['type' => 'comments', 'id' => '2'],
                ['type' => 'comments', 'id' => '3']
            ]
        ]
    ]
]

// Example model
use Dogpile\ResourceIdentifier;
use Dogpile\Contracts\Resource;
use Dogpile\Collections\RelationshipCollection;

class SomeObjectModel implements Resource
{
    protected $jsonapiData = [];

    public function __construct(array $jsonapiData)
    {
        $this->jsonapiData = $jsonapiData;
    }

    public function type(): string
    {
        return $this->jsonapiData['type'];
    }

    public function id(): string
    {
        return $this->jsonapiData['id'];
    }

    public function relationships(): RelationshipCollection
    {
        $collection = new RelationshipCollection();

        // add author
        $authorIdent = $this->jsonapiData['relationships']['author']['data'];
        $collection->addRelationships('author', ResourceIdentifier::create($authorIdent['type'], $authorIdent['id']));

        // add comments
        $commentIdentifiers = array_map(function($comment){
            return ResourceIdentifier::create($comment['type'], $comment['id']);
        }, $this->jsonapiData['relationships']['comments']['data']);


        $collection->addRelationships('comments', ...$commentIdentifiers);


        return $collection;
    }
}

更多示例,请参阅测试:tests\Functional\ResourceManagerTest.php