As a work around to bug https://github.com/cloudcreativity/laravel-json-api/issues/218 where filtering doesn't work when requesting record by ID, I also experimented with utilizing multiple filters. Which isn't the desired API spec, but hey, kicking the wheels here. Goal is filter related model when requesting a specific record.
eg.
http://demo-laravel-json-api.homestead/api/v1/posts?include=author&filter[user.name]=Bob&filter[id]=15
I found that filtering by ID stops any other filters from running and only returns filtering based on ID only.
{
"data": [
{
"type": "posts",
"id": "15",
"attributes": {
"created-at": "2018-08-17T22:50:11+00:00",
"updated-at": "2018-08-17T22:50:11+00:00",
"title": "Neque hic repudiandae.",
"slug": "qui-aut-quis-sint-voluptate-ea-in-impedit",
"content": "Facere at fugit magni quidem aliquam voluptas. Est asperiores quidem ullam provident et et hic id. Vel ad quod quod sapiente eos.\n\nAutem qui quia dolorem fugiat at. Perferendis totam aspernatur eum quaerat blanditiis. Voluptatibus cumque eaque vitae esse optio sit. Earum odio consectetur voluptatem iure voluptate.\n\nQuo harum odit id. Repellat rem atque placeat aut molestiae dolores ducimus. Aperiam sunt voluptatem aliquid veritatis velit inventore.",
"published-at": "1980-04-26T06:41:59+00:00"
},
"relationships": {
"author": {
"data": {
"type": "users",
"id": "5"
},
"links": {
"self": "http://demo-laravel-json-api.homestead/api/v1/posts/15/relationships/author",
"related": "http://demo-laravel-json-api.homestead/api/v1/posts/15/author"
}
},
"comments": {
"links": {
"self": "http://demo-laravel-json-api.homestead/api/v1/posts/15/relationships/comments",
"related": "http://demo-laravel-json-api.homestead/api/v1/posts/15/comments"
}
},
"tags": {
"links": {
"self": "http://demo-laravel-json-api.homestead/api/v1/posts/15/relationships/tags",
"related": "http://demo-laravel-json-api.homestead/api/v1/posts/15/tags"
}
}
},
"links": {
"self": "http://demo-laravel-json-api.homestead/api/v1/posts/15"
}
}
],
"included": [
{
"type": "users",
"id": "5",
"attributes": {
"created-at": "2018-08-17T22:50:11+00:00",
"updated-at": "2018-08-17T22:50:11+00:00",
"name": "Fabian Hermiston"
}
}
]
}
* User with name Bob was not filtered.
If id is used a filter, the protected function filter() is not called in Posts.Adapter. It seems that AbstractAdapter has it's own method in query for filtering by ID.
Line 150 AbstractAdapter
/** Find by ids */
if ($this->isFindMany($filters)) {
return $this->findByIds($query, $filters);
}
/** Filter and sort */
$this->filter($query, $filters);
$this->sort($query, (array) $parameters->getSortParameters());
I would expect that we should be able to define any filter desired in Post.Adapter filter function
eg. Specifying a filter for ID and username, or any other various combination.
protected function filter($query, Collection $filters)
{
if ($filters->has('title')) {
$query->where('posts.title', 'like', '%' . $filters->get('title') . '%');
}
if ($filters->has('slug')) {
$query->where('posts.slug', $filters->get('slug'));
}
if ($filters->has('id') && $filters->has('user.name')) {
$query->with(['author' => function ($related) use ($filters) {
$related->where('name', 'like', '%' . $filters->get('user.name') . '%');
}])->where('id', $filters->get('id'));
}
A quick fix seems to be swapping the "Filter and sort" section with the "Find By Ids" section, so that the filters run first, that way any custom filters aren't blocked.
Line 150 AbstractAdapter
/** Filter and sort */
$this->filter($query, $filters);
$this->sort($query, (array) $parameters->getSortParameters());
/** Find by ids */
if ($this->isFindMany($filters)) {
return $this->findByIds($query, $filters);
}
However, maybe that isn't the most elegant way to handle it. I know JSON API doesn't have any specs for how to handle filtering, but having it hard wired in and preventing other filters seems problematic.
Could we chain these at all? so isFindMany($filters) returns a $query object, that could have further query criteria added to it when running through the other filters?
Yeah, I was aware this was a bug and was in my head to fix!
This change has a number of subtle breaking impacts, which I've documented here:
https://github.com/cloudcreativity/laravel-json-api/blob/3e613b1e0e0df49c47180a648951fff4e9b6ab70/docs/upgrade.md#filtering-by-id