Включение отношений в коллекцию красноречивых ресурсов по желанию
Я хочу загрузить отношения опционально на конечной точке API коллекции
Конечная точка будет что-то вроде
http://127.0.0.1:8000/api/posts/?include=comments includes comments with posts and I can add more using comma, like
http://127.0.0.1:8000/api/posts/?include=comments,images
но когда я не передаю эти параметры запроса, он должен только вернуть posts
с конечной точкой http://127.0.0.1:8000/api/posts
а также http://127.0.0.1:8000/api/posts?page=10
RequestQueryFilter
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
class RequestQueryFilter
{
public function attach($resource, Request $request = null)
{
$request = $request ?? request();
return tap($resource, function($resource) use($request) {
$this->getRequestIncludes($request)->each(function($include) use($resource) {
$resource->load($include);
});
});
}
protected function getRequestIncludes(Request $request)
{
// return collect(data_get($request->input(), 'include', [])); //single relationship
return collect(array_map('trim', explode(',', data_get($request->input(), 'include', [])))); //multiple relationships
}
}
в помощнике
<?php
if ( ! function_exists('filter') ) {
function filter($attach)
{
return app('filter')->attach($attach);
}
}
?>
В PostController
public funciton index(Request $request) {
$posts = Post::all();
return new PostCollection(filter($posts));
}
В PostCollection
return [
'data' => $this->collection->transform(function($post){
return [
'id' => $post->id,
'title' => $post->title,
'body' => $post->body,
'comments' => new CommentCollection($post->whenLoaded('comments')),
'images' => new ImageCollection($post->whenLoaded('images'))
];
}),
];
показ
Вызовите неопределенный метод App\Models\Post::whenLoaded()", но если я использую ресурс одной модели, он работает нормально.
Обновление: Причина:- преобразование после сбора дает
Collection gives
Post {#363
#guarded: array:1 [
0 => "id"
]
#connection: "mysql"
#table: "posts"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:9 [
но пост ресурс $this
дает
Post {#344
+resource: Post {#343
#guarded: array:1 [
0 => "id"
]
#connection: "mysql"
#table: "posts"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:9 [
теперь конвертируем PostCollection $post в PostResource
'data' => $this->collection->transform(function($post) use ($request) {
$post = new PostResource($post);
dd($post);
Используя это
'comments' => new CommentCollection($post->whenLoaded('comments')),
всегда будет возвращать комментарии, даже нет comments
в include
$post->relationLoaded('comments')
всегда возвращает истину
1 ответ
Я не знаю, если это дизайн или ошибка. Я думаю, что это не работает с коллекциями, потому что whenLoaded($relation)
является методом класса ресурса, а не самой модели. Но в качестве обходного пути должно работать следующее:
return [
'data' => $this->collection->transform(function ($post) {
return [
'id' => $post->id,
'title' => $post->title,
'body' => $post->body,
'comments' => $this->when($post->relationLoaded('comments'), function () use ($post) {
return new CommentCollection($post->comments);
}),
'images' => $this->when($post->relationLoaded('images'), function () use ($post) {
return new ImageCollection($post->images);
})
];
}),
];
Как вы всегда получаете true
вернулся $post->relationLoaded('comments')
, я предлагаю создать новый метод на вашей базовой модели (или, если у вас его нет, Post
модель), которая проверяет не только состояние загрузки, но и содержимое отношения:
public function relationLoadedAndNotEmpty(string $relation): bool
{
return $this->relationLoaded($relation) &&
$this->getRelation($relation) instanceof \Illuminate\Support\Collection &&
$this->getRelation($relation)->isNotEmpty();
}
Использование этого метода в ресурсе, как предложено выше, вместо "$post-> RelationsLoaded('comments')` должно дать вам желаемые результаты, поскольку это также позволит избежать печати атрибута, если коллекция пуста.