coder-sapient / json-api-document-builder
Json Api Document Builder
v1.0.0
2022-03-28 10:42 UTC
Requires
- php: >=8.0
- ext-json: *
- guzzlehttp/promises: ^1.5
- json-api-php/json-api: ^2.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.4
- laminas/laminas-diactoros: ^2.8
- phpunit/phpunit: ^9.5
- vimeo/psalm: ^4.15
README
这个库可以将查询对象解析为JSON:API文档。
功能
- 使用以下运算符进行分页、排序和过滤(
eq
、neq
、gt
、lt
、gte
、lte
、like
)。 - 多级嵌套路径资源包含(例如
article, article.author, article.comments.user
)。 - 异步资源包含(Guzzle Promises/A+)。
- 缓存解析的资源。
- 完全单元测试
请求示例
GET /api/v1/articles/{id}?include=author
GET /api/v1/articles?include=author,comments.user&page=1&per_page=15
GET /api/v1/articles?sort=id,-title // sort id in asc, title in desc
GET /api/v1/articles?filter[id]=100,101&filter[title][like]=value
要求
- PHP版本 >=8.0
安装
使用composer安装包
composer require coder-sapient/json-api-document-builder
基本用法
控制器操作示例
final class ShowArticleAction { public function __construct(private SingleDocumentBuilder $builder) { } public function __invoke(ShowArticleRequest $request): string { try { $document = $this->builder->build($request->toQuery()); } catch (JsonApiException $e) { return json_encode($e->jsonApiErrors()); } return json_encode($document); } }
您可以将以下特质添加到您的请求类中
- SingleDocumentRequest:用于关于单个顶级资源的文档。
- DocumentsRequest:用于关于顶级资源集合的文档。
SingleDocumentRequest
final class ShowArticleRequest extends Request { use SingleDocumentRequest; protected function resourceId(): string { // return from URL ~/articles/{resourceId} } protected function resourceType(): string { return 'articles'; } protected function acceptableIncludes(): array { return ['author', 'comments', 'comments.user']; } }
DocumentsRequest
final class ListArticlesRequest extends Request { use DocumentsRequest; protected function resourceType(): string { return 'articles'; } protected function acceptableSorting(): array { return ['title', 'created_at']; } protected function acceptableIncludes(): array { return ['author', 'comments', 'comments.user']; } protected function acceptableFilters(): array { return [ 'author_id' => ['eq'], 'title' => ['eq', 'like'], ]; } }
Builder
要初始化Builder,您需要提供ResourceResolverFactory和ResourceCache实例。
SingleDocumentBuilder
SingleDocumentBuilder扩展Builder
。
DocumentsBuilder
DocumentsBuilder扩展Builder
。
Resolver
Factory
ResourceResolverFactory是一个工厂,通过资源类型返回ResourceResolver。
interface ResourceResolverFactory { /** * @throws ResourceResolverNotFoundException */ public function make(string $resourceType): ResourceResolver; }
有一个基本实现InMemoryResourceResolverFactory。
$factory = new InMemoryResourceResolverFactory(); $factory->add( 'articles', // resource type new ArticleResourceResolver() ); $factory->add( 'users', new AuthorResourceResolver() ); $factory->add( 'comments', new CommentResourceResolver() ); $builder = new SingleDocumentBuilder($factory, new InMemoryResourceCache()); $singleDocument = $builder->build($request->toQuery());
ResourceResolver
构建器使用ResourceResolver实例根据ID或查询条件查找资源。
interface ResourceResolver { /** * @param DocumentsQuery $query * * @return ResourceObject[] */ public function resolveMany(DocumentsQuery $query): array; /** * @param SingleDocumentQuery $query * * @return ResourceObject|null */ public function resolveOne(SingleDocumentQuery $query): ?ResourceObject; /** * @param string ...$resourceIds * * @return ResourceObject[]|PromiseInterface */ public function resolveByIds(string ...$resourceIds): array|PromiseInterface; }
在解析顶级资源集合时,它将提供由过滤器、排序和分页组成的查询条件。您需要使用查询构建器(Doctrine、Eloquent等)与条件匹配。
当尝试包含相关资源并异步加载时,构建器可以接受Guzzle Promises。
PaginationResolver
interface PaginationResolver { /** * @param DocumentsQuery $query * * @return PaginationResponse */ public function paginate(DocumentsQuery $query): PaginationResponse; }
如果资源解析器实现了PaginationResolver,构建器将在结果文档中添加顶级Links
和Meta
对象。
{
"links": {
"first": "https:///api/v1/articles?page=1&per_page=15",
"prev": "https:///api/v1/articles?page=1&per_page=15",
"next": "https:///api/v1/articles?page=2&per_page=15",
"last": "https:///api/v1/articles?page=3&per_page=15",
},
"meta": {
"total": 45,
"page": 1,
"per_page": 15,
"last_page": 3
}
}
ResourceCache
构建器使用ResourceCache实例缓存所有解析的资源。
interface ResourceCache { /** * @param string $key * * @return ResourceObject|null */ public function getByKey(string $key): ?ResourceObject; /** * @return ResourceObject[] */ public function getByKeys(string ...$keys): array; /** * @param JsonApiQuery $query * * @return ResourceObject[] */ public function getByQuery(JsonApiQuery $query): array; /** * @param ResourceObject ...$resources * * @return void */ public function setByKeys(ResourceObject ...$resources): void; /** * @param JsonApiQuery $query * @param ResourceObject ...$resources * * @return void */ public function setByQuery(JsonApiQuery $query, ResourceObject ...$resources): void; /** * @param string ...$keys * * @return void */ public function removeByKeys(string ...$keys): void; /** * @param string ...$resourceTypes * * @return void */ public function removeByTypes(string ...$resourceTypes): void; /** * @return void */ public function flush(): void; }
有一个基本实现InMemoryResourceCache。如果您不需要缓存,请使用NullableResourceCache。
许可证
麻省理工学院许可证(MIT)。请参阅更多信息许可协议。