【问题标题】:Laravel, pivot table with childsLaravel,带孩子的数据透视表
【发布时间】:2022-03-19 19:25:12
【问题描述】:

我正在使用由数据透视表链接的 2 个模型,模块和客户端。

第一个,modules模型,可以有子模块,如下表结构,

| id |...| module_id |

module_id 指的是父模块。

这个模型有如下关系:

public function parentModule()
{
    return $this->belongsTo(Module::class, 'module_id');
}

public function childModules()
{
    return $this->hasMany(Module::class, 'module_id')
                ->with('childModules')
                ->orderBy('order');
}

public function Clients()
{
    return $this->belongsToMany(Client::class, 'client_module', 'module_id', 'client_id');
}

public function scopeBaseModules($query)
{
    return $query->whereNull('module_id');
}

所以,如果我这样做:

Module::BaseModules()->with('childModules')->get()

我得到了所有模块及其各自的孩子。

Module 1
->second level child module X
->->third level child module Y
Module 2
...

Client 模型是一个简单的表,带有 Id 和其他信息,并具有以下关系:

public function modules()
{
    return $this->belongsToMany(Module::class, 'client_module', 'client_id', 'module_id');
}

两个表通过数据透视表 client_module 链接,结构如下:

| client_id | module_id |

所以,如果我这样做:

Module::BaseModules()
      ->with('childModules')
      ->with('clients')
      ->get()

我将获取所有模块,它们各自的子模块,以及链接到它们的客户端。

现在我需要获取该查询,但只返回来自特定客户端的模块和子项。我试过范围:

public function scopeClient($query, $client)
{
    return $query->wherePivot('client_id', $client);
}

假设这会将查询过滤到特定于客户端的 id,但不会!

请有人指导我正确的方向吗?

【问题讨论】:

    标签: laravel eloquent scope pivot


    【解决方案1】:

    好的!

    我将把解决方案留在这里,也许它对其他人有用。

    经过多次前后左右,我终于设法找到了解决我一直在寻找的问题的解决方案。

    Module::BaseModules()
          ->with(['ChildModules' => function($q) use($client) {
             $q->whereHas('clients', function($q) use($client) {
                $q->where('clients.id', $client);
             });
          }])
          ->whereHas('clients', function($q) use($client) {
             $q->where('clients.id', $client);
          })
          ->orderBy('order')
          ->get();
    

    这会检索客户端过滤的模块的递归集合。

    检查查询创建的 SQL,这似乎不是一个糟糕的解决方案。

    **** 毕竟,这是一个糟糕的解决方案......这个解决方案只过滤第一级孩子! ****

    最终解决方案:

    我创建了一个非递归关系父/子。

    public function childModule()
    {
        return $this->hasMany(Module::class, 'parent_id')->orderBy('order');
    }
    

    然后,为了使代码更易于阅读,我创建了两个范围:

    public function scopeGetByClient($query, $client_id)
    {
        return $query->whereHas('clients', function ($q) use ($client_id) {
            $q->where('clients.id', $client_id);
        });
    }
    
    public function scopeGetChildsByClient($query, $client_id)
    {
        return $query->with(['ChildModule' => function ($q) use ($client_id) {
                $q->whereHas('clients', function ($q) use ($client_id) {
                    $q->where('clients.id', $client_id);
                })
                ->getChildsByClient($client_id);
        }]);
    }
    

    第一个范围按客户端过滤父级别。 第二个获取第一级子级,按客户端过滤它们,然后再次调用相同的范围,递归调用所有级别的子级。

    最后,调用所有这些方法:

    $modules = Module::BaseModules()
            ->getByClient($client->id)
            ->getChildsByClient($client->id)
            ->orderBy('order')
            ->get();
    

    【讨论】:

      猜你喜欢
      • 2018-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 2017-12-15
      • 2021-08-17
      • 1970-01-01
      相关资源
      最近更新 更多