可以选择在雄辩的资源收集中包含关系

时间:2019-08-16 06:41:06

标签: laravel eloquent eloquent--relationship laravel-eloquent-resource

我希望在集合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/postshttp://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')

始终返回true。

1 个答案:

答案 0 :(得分:0)

我不知道这是设计使然还是错误。我最好的猜测是它不适用于集合,因为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-> relationLoaded('comments')`应该会为您提供所需的结果,因为如果集合为空,它也将避免打印属性。