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

如何在Laravel中基于用户信息统一过滤Country模型及嵌套子模型?

基于用户所属国家的模型全局过滤方案

针对你的需求,这里提供几个可行的方案,无需在每个子模型中重复编写whereHas过滤逻辑,将过滤逻辑集中处理:

方案1:给Country模型添加全局作用域

通过全局作用域限制Country模型仅查询当前登录用户所属的国家,子模型通过关联查询时会自动继承该过滤条件。

代码实现

在Country模型中注册全局作用域:

// app/Models/Country.php
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    protected static function booted()
    {
        // 仅对登录用户应用过滤
        static::addGlobalScope('user_country', function (Builder $builder) {
            $user = auth()->user();
            if ($user) {
                $builder->where('id', $user->country_id);
            }
        });
    }

    // 关联定义
    public function states()
    {
        return $this->hasMany(State::class);
    }
}

在LibraryController中查询时,只需通过嵌套关联触发Country的过滤:

// app/Http/Controllers/LibraryController.php
public function index()
{
    // 自动返回当前用户所属国家的所有图书馆
    $libraries = Library::whereHas('city.state.country')->get();
    return $libraries;
}

方案2:封装统一的过滤服务类

创建一个服务类集中管理所有模型的国家过滤逻辑,后续维护只需修改这个类即可。

代码实现

// app/Services/CountryFilterService.php
use Illuminate\Database\Eloquent\Builder;
use App\Models\Country;
use App\Models\State;
use App\Models\City;
use App\Models\Library;

class CountryFilterService
{
    public static function apply(Builder $query): Builder
    {
        $user = auth()->user();
        if (!$user) {
            return $query;
        }

        $model = $query->getModel();
        match (true) {
            $model instanceof Country => $query->where('id', $user->country_id),
            $model instanceof State => $query->whereHas('country', fn($q) => $q->where('id', $user->country_id)),
            $model instanceof City => $query->whereHas('state.country', fn($q) => $q->where('id', $user->country_id)),
            $model instanceof Library => $query->whereHas('city.state.country', fn($q) => $q->where('id', $user->country_id)),
            default => null
        };

        return $query;
    }
}

控制器中调用方式:

// app/Http/Controllers/LibraryController.php
public function index()
{
    $libraries = CountryFilterService::apply(Library::query())->get();
    return $libraries;
}

方案3:定义全局查询宏

通过全局查询宏给所有Eloquent查询构建器添加统一的过滤方法,调用方式更简洁。

代码实现

在AppServiceProvider中注册宏:

// app/Providers/AppServiceProvider.php
use Illuminate\Database\Eloquent\Builder;
use App\Models\Country;
use App\Models\State;
use App\Models\City;
use App\Models\Library;

public function boot()
{
    Builder::macro('forUserCountry', function () {
        $user = auth()->user();
        if (!$user) {
            return $this;
        }

        $model = $this->getModel();
        match (true) {
            $model instanceof Country => $this->where('id', $user->country_id),
            $model instanceof State => $this->whereHas('country', fn($q) => $q->where('id', $user->country_id)),
            $model instanceof City => $this->whereHas('state.country', fn($q) => $q->where('id', $user->country_id)),
            $model instanceof Library => $this->whereHas('city.state.country', fn($q) => $q->where('id', $user->country_id)),
            default => null
        };

        return $this;
    });
}

控制器中直接调用宏方法:

// app/Http/Controllers/LibraryController.php
public function index()
{
    $libraries = Library::forUserCountry()->get();
    return $libraries;
}

方案对比

  • 方案1适合仅需限制Country模型查询的场景,子模型依赖关联自动过滤,代码最精简
  • 方案2逻辑集中,便于后续扩展更多模型的过滤规则
  • 方案3调用方式最简洁,全局通用,推荐作为优先方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:18:03