Laravel 预加载和API资源的使用,解决多表关联查询的返回数据结构

Laravel在5.5以后,更新了API资源

资源的生成和介绍相关,请自行查看文档: Laravel 5.8文档

动机

我一直用的都是其他框架,Laravel是最近一个项目才去实际接触,确实是很赞的一款框架。
在项目中,我碰到了这样一个问题:

User模型和Article模型 1对多关联,而Article模型和Caregory模型1对1关联。
我现在需要通过User模型获取到Article表和Category表中的数据。

第一次尝试:预加载 + 远程关联

在阅读文档时,预加载模型,可以很好的去获取关联模型的字段。如下:

	public function index(int $id)
    {
        return User::with('articles')->find($id);
    }

获取的结果集像这样:

{
    "id": 9,
    "name": "张三",
    "create_time": "2019-03-18 17:40:59",
    "articles": [
        {
            "id": 1,
            "title": "Laravel",
            "user_id": 9,
            "content": "测试1",
            "category_id": 1,
            "created_at": "2019-04-13 17:59:12"
        },
        {
            "id": 2,
            "title": "Thinkphp",
            "user_id": 9,
            "content": "测试2",
            "category_id": 2,
            "created_at": "2019-04-13 17:59:13"
        }
    ]
}

但我想要的数据,还需要很多第三个category表的字段,他和user表并无关联,所以无法用with加载。
于是我想到远程关联:

在User的model中定义方法
/**
     * 远程一对多关联Category模型
     *
     */
    public function categories()
    {
        return $this->hasManyThrough(
            'App\Models\Category',
            'App\Models\Article',
            'user_id',
            'id',
            'id',
            'category_id'
        );
    }

控制器中with加上categories
public function index(int $id)
    {
        return User::with(['articles','categories'])->find($id);
    }

获取到的结果

{
    "id": 9,
    "name": "张三",
    "create_time": "2019-03-18 17:40:59",
    "articles": [
        {
            "id": 1,
            "title": "Laravel",
            "user_id": 9,
            "content": "测试1",
            "category_id": 1,
            "created_at": "2019-04-13 17:59:12"
        },
        {
            "id": 2,
            "title": "Thinkphp",
            "user_id": 9,
            "content": "测试2",
            "category_id": 2,
            "created_at": "2019-04-13 17:59:13"
        }
    ],
    "categories": [
        {
            "id": 1,
            "name": "Laravel",
            "created_at": "2019-04-13 17:59:48",
            "laravel_through_key": 9
        },
        {
            "id": 2,
            "name": "TP",
            "created_at": "2019-04-13 17:59:57",
            "laravel_through_key": 9
        }
    ]
}

虽然我拿到了所有想要拿到的数据,但数据结构,并不理想,并且修改起来想一想好像很麻烦,于是,我尝试第二种方法:API资源

二、 API资源

这东西,我理解为就是一个中间的加工厂,在你获取结果之后,进行字段和数据结构的处理。

首先,创建UserResource和ArticleResource,在toArray方法中,把你想要返回的字段做处理,里面可以随意的去修改字段,包括随便添加个aaa,bbb,返回什么就写什么。
如果,想在不同的方法里,都使用这个Resource的字段处理,我没想到太好的办法,我是通过判断路由来处理的,

注意:如果你想获取的主要数据是单条数据,使用的是find和first方法,那么直接实例化一个资源类就好: new xxxResource(Model::find(1))。但如果你想要获取的是多条数据,或是分页数据,那么就要使用资源集合,如xxxResource::collection(Model::paginate(10))。

	/**
     *   UserController中
     */ 
public function index(int $id)
    {
        $users = User::with('articles')->find($id);
        return new UserResource($users);
    }

	/**
     *   UserResource 中
     */ 
public function toArray($request)
    {
        $data = [
            'id' => $this->id,
            'name' => $this->name,
            'articles' => ArticleResource::collection($this->whenLoaded('articles'))
        ];

        // is_route方法是自己写的判断当前请求的路由名称是否与写入的相等。
        if(is_route('user.show')) {
            $data = [
                // 想要返回字段
            ];
        }

        return $data;
    }

	/**
     *  ArticleResource 中
     */ 
public function toArray($request)
    {
        return [
            'id'    => $this->id,
            'title' => $this->title,
            'category_id'   => $this->category_id,
            'category_name' => $this->getCategoryField('name'),
            'category_aaa'  => $this->getCategoryField('aaa')
        ];
    }


    protected function getCategoryField($field)
    {
        if(empty($this->categoryModel)){
            $this->categoryModel = new Category();
        }
        return $this->categoryModel->find($this->category_id)->$field;
    }

这样,我就获取到了自己想要的数据结构:

{
    "data": {
        "id": 9,
        "name": "张三",
        "articles": [
            {
                "id": 1,
                "title": "Laravel",
                "category_id": 1,
                "category_name": "Laravel",
                "category_aaa": "111"
            },
            {
                "id": 2,
                "title": "Thinkphp",
                "category_id": 2,
                "category_name": "TP",
                "category_aaa": "222"
            }
        ]
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43490690/article/details/89285723