0

我希望在集合 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

请求查询过滤器

<?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')

总是返回真。

4

1 回答 1

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')` 应该会给您所需的结果,因为如果集合为空,它还将避免打印属性。

于 2019-08-16T07:56:58.800 回答