首页 > 解决方案 > Laravel:当一张表与多张表相关时,我如何组合返回数据?

问题描述

因此,在我的应用程序中,我有模型:用户、类别、服务(即子类别)和 userService。

用户与类别、用户与服务之间存在多对多的关系。类别和服务之间是一对多的。

// 表格

Users        : id, name, email, password
Categories   : id, name
Services     : id, name, category_id
user_services: id, user_id, category_id, service_id

关系在模型中定义为:

// 用户模型

    public function services()
    {
        return $this->belongsToMany('App\Models\V1\Service', 'user_services', 'user_id', 'service_id');
    }

    public function categories()
    {
        return $this->belongsToMany('App\Models\V1\Category', 'user_services', 'user_id', 'category_id');
    }

// 类别模型

 public function services()
    {
        return $this->hasMany(Service::class);
    }

用一些随机数据填充我的数据库后,user_services 表如下所示:

// 用户服务表

id   user_id   category_id  service_id 
1    1         1            1
2    1         1            2
3    2         1            1

到目前为止代码很好,但是当我想要特定用户的服务和类别时,我无法按预期获得它。

用于通过服务和类别获取用户的 eloquent 方法:

public function userWithCategoryServices(Request $request)
{
  return User::where('id', $request->id)->with(categories.services)->get();
}

这样做的问题是:

  1. 由于存在一个用户拥有一个类别可以拥有多个服务的情况,因此这种雄辩的方法将多次返回相同的类别。但是我希望属于一个类别的所有服务都分组在该特定用户的单个类别键中。

  2. 另一个问题,不是只获取该特定用户的服务,而是从数据库中获取用户特定类别的所有服务。

            [
            {
             "id": 1,
             "name": "Ashish Bogati",
             "email": "abbaasdaashisdh23@gmail.com",
             "categories": [
             {
             "id": 1,
             "name": "IT",
             "pivot": {
                       "user_id": 1,
                       "category_id": 1
                      },
             "services": [
                 {
                     "id": 1,
                     "name": "Web Developer",
                     "category_id": 1, 
                 },
                 {
                     "id": 2,
                     "name": "Web Design",
                     "category_id": 1
                 },
                 {
                     "id": 3,
                     "name": "Database Design",
                     "category_id": 1
                 }
             ]
         },
         {
             "id": 1,
             "name": "IT",
             "pivot": {
                       "user_id": 1,
                       "category_id": 1
                      },
             "services": {
                     "id": 1,
                     "name": "Web Developer",
                     "category_id": 1
                 },
                 {
                     "id": 2,
                     "name": "Web Design",
                     "category_id": 1
                 },
                 {
                     "id": 3,
                     "name": "Database Design",
                     "category_id": 1
                 }
             ]
         }
     ]
    

    }]

在此响应中,类别名称 IT 为用户重复两次,并且为该类别获取所有服务,而不是仅针对特定用户。

我想要的回应:

           [
           {
            "id": 1,
            "name": "Ashish Bogati",
            "email": "abbaasdaashisdh23@gmail.com",
            "categories": [
            {
            "id": 1,
            "name": "IT",
            "pivot": {
                      "user_id": 1,
                      "category_id": 1
                     },
            "services": [
                {
                    "id": 1,
                    "name": "Web Developer",
                    "category_id": 1, 
                },
                {
                    "id": 2,
                    "name": "Web Design",
                    "category_id": 1
                },
            ]
        }
]

标签: phplaraveleloquenteloquent-relationship

解决方案


数据库设计有点奇怪。我们在 user_services 中遇到了重复的 category_id。但这不是问题

//in service model
public function category()
{
  return $this->hasOne(Category::class);
}
public function userWithCategoryServices(Request $request)
{
  $services = User::where('id', $request->id)->with("services.category")->get();
  $servicesGrouped = $services['services']->groupBy('category_id');
}

服务将是正确的。不会有更多不需要的数据。
到目前为止,我们可以通过 Laravel 雄辩地做到这一点。
因为关系图是 user->services->category.not user->categories->services


使用 php 构建所需响应的结构。
但是作为Restful原则。你应该使api纯粹。这意味着一个api只给一种类型的实体。客户端会更清楚其余的api并自己处理复杂的结构。

public function userWithCategoryServices(Request $request)
{
  $services = User::where('id', $request->id)->with("services.category")->get()->toArray();
  $categories = []
  for($services as $service){
      if(!isset($categories[$service['category_id']])){
        $categories[$service['category_id']] = $service['category'];
        $categories[$service['category_id']]['services'] = [];
      }
      unset($service['category']);
      $categories[$service['category_id']]['services'][] = $service;
  }
  $categories = array_values($categories);
  unset($services['services']);
  $services['categories'] = $categories;
  return $services;
}

推荐阅读