You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Eloquent+Slim Framework实现带可选where子句的嵌套预加载遇阻

解决Slim Framework中Eloquent多级预加载的可选Where子句问题

嘿,我完全懂你现在的困扰——多级关联的可选条件预加载确实容易绕晕,但Eloquent其实提供了很灵活的闭包方式来处理这个场景,我结合你的三张表结构给你一步步拆解解决方案。

首先先确认你的模型关联是正确的(如果还没定义好,先补上):

模型关联定义

// Category 模型
class Category extends Model
{
    protected $table = 'Category';
    public function subCategories()
    {
        return $this->hasMany(Sub_category::class, 'category_id');
    }
}

// Sub_category 模型
class Sub_category extends Model
{
    protected $table = 'Sub_category';
    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id');
    }
    public function childCategories()
    {
        return $this->hasMany(Child_category::class, 'sub_category_id');
    }
}

// Child_category 模型
class Child_category extends Model
{
    protected $table = 'Child_category';
    public function subCategory()
    {
        return $this->belongsTo(Sub_category::class, 'sub_category_id');
    }
}

接下来分两种常见场景来实现可选条件的多级预加载:

场景1:仅给最内层的Child_category加可选过滤

比如你想根据请求参数(比如child_name)来过滤Child_category,参数存在时才应用条件,不存在时就加载全部数据:

// 从Slim请求中获取可选参数
$childNameFilter = $request->getParam('child_name');

// 执行带可选条件的多级预加载
$categories = Category::with(['subCategories.childCategories' => function ($query) use ($childNameFilter) {
    // 只有当过滤参数存在时,才添加WHERE子句
    if ($childNameFilter) {
        $query->where('name', 'like', "%{$childNameFilter}%");
    }
}])->get();

场景2:给中间层Sub_category和最内层Child_category同时加可选过滤

如果需要同时对Sub_category和它关联的Child_category做可选过滤,比如同时有sub_cat_name和child_cat_name两个参数,可以嵌套闭包来实现:

$subCatFilter = $request->getParam('sub_cat_name');
$childCatFilter = $request->getParam('child_cat_name');

$categories = Category::with(['subCategories' => function ($subQuery) use ($subCatFilter, $childCatFilter) {
    // 可选过滤Sub_category
    if ($subCatFilter) {
        $subQuery->where('name', 'like', "%{$subCatFilter}%");
    }
    // 同时给关联的Child_category加可选过滤
    $subQuery->with(['childCategories' => function ($childQuery) use ($childCatFilter) {
        if ($childCatFilter) {
            $childQuery->where('name', 'like', "%{$childCatFilter}%");
        }
    }]);
}])->get();

进阶优化:用模型作用域简化代码

如果可选过滤逻辑会多次用到,建议把它封装成模型的查询作用域,让代码更简洁易维护:

// 在Child_category模型中添加作用域
public function scopeFilterByName($query, $name)
{
    if ($name) {
        return $query->where('name', 'like', "%{$name}%");
    }
    // 参数为空时返回原查询,不做过滤
    return $query;
}

// 同理可以给Sub_category模型加作用域
public function scopeFilterByName($query, $name)
{
    if ($name) {
        return $query->where('name', 'like', "%{$name}%");
    }
    return $query;
}

之后使用的时候就可以简化成:

$categories = Category::with(['subCategories' => function ($subQuery) use ($subCatFilter, $childCatFilter) {
    $subQuery->filterByName($subCatFilter)->with(['childCategories' => function ($childQuery) use ($childCatFilter) {
        $childQuery->filterByName($childCatFilter);
    }]);
}])->get();

注意点

  • 当可选参数为空时,Eloquent会自动跳过对应的WHERE子句,不会影响正常的全量预加载,所以不用担心空参数导致数据丢失。
  • 如果需要更复杂的条件组合(比如多个字段过滤),只需要在闭包或作用域里添加对应的判断逻辑即可。

内容的提问来源于stack exchange,提问作者Biswajit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:34:44