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

Laravel宏中使用函数:无需扩展Eloquent Builder拆分搜索逻辑

没问题,我刚好有几个实用的方案能帮你解决这个问题——不用完全扩展Eloquent Builder就能把复杂的search逻辑拆分成清晰的小函数:

方案一:用工具类封装拆分逻辑(最推荐)

把拆分后的逻辑放到单独的工具类里,让每个方法专注处理一部分逻辑,然后在macro回调里调用这些方法。这样既保持了代码的模块化,又不会污染Builder的作用域。

首先创建一个工具类,比如BuilderSearchHelper:

class BuilderSearchHelper
{
    /**
     * 处理基础字段搜索
     */
    public function handleBasicSearch($builder, string $searchBy)
    {
        $builder->where('name', 'like', "%{$searchBy}%")
                ->orWhere('email', 'like', "%{$searchBy}%");
    }

    /**
     * 处理关联模型的搜索逻辑
     */
    public function handleRelatedSearch($builder, string $searchBy)
    {
        $builder->orWhereHas('category', function ($query) use ($searchBy) {
            $query->where('title', 'like', "%{$searchBy}%");
        });
    }

    /**
     * 处理复杂的过滤条件
     */
    public function handleAdvancedFilters($builder, string $searchBy)
    {
        // 这里可以添加更复杂的逻辑,比如多条件组合、范围查询等
        $builder->orWhere(function ($query) use ($searchBy) {
            $query->where('status', '=', 'active')
                  ->where('created_at', '>=', now()->subMonth());
        });
    }
}

然后在服务提供者的boot方法里调用这个工具类:

use Illuminate\Database\Eloquent\Builder;

public function boot()
{
    Builder::macro('search', function (string $searchBy) {
        $searchHelper = new \App\Helpers\BuilderSearchHelper();
        
        // 依次调用拆分后的逻辑方法
        $searchHelper->handleBasicSearch($this, $searchBy);
        $searchHelper->handleRelatedSearch($this, $searchBy);
        $searchHelper->handleAdvancedFilters($this, $searchBy);
        
        // 记得返回Builder实例,保持链式调用
        return $this;
    });
}

这个方案的优点是逻辑完全解耦,每个方法职责单一,后期维护、测试都非常方便。

方案二:绑定服务提供者的方法到Builder作用域

如果不想额外创建工具类,想把拆分的方法留在服务提供者里,可以利用PHP的闭包绑定功能,把服务提供者的私有方法绑定到Builder实例的作用域中,这样方法里的$this就会指向Builder对象。

示例代码:

use Illuminate\Database\Eloquent\Builder;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Builder::macro('search', function (string $searchBy) {
            // 将服务提供者的handleBasicSearch方法绑定到当前Builder实例
            $basicSearch = \Closure::fromCallable([$this, 'handleBasicSearch'])->bindTo($this, Builder::class);
            $basicSearch($searchBy);
            
            // 同理绑定其他拆分方法
            $relatedSearch = \Closure::fromCallable([$this, 'handleRelatedSearch'])->bindTo($this, Builder::class);
            $relatedSearch($searchBy);
            
            return $this;
        });
    }

    /**
     * 基础搜索逻辑
     */
    private function handleBasicSearch(string $searchBy)
    {
        // 这里的$this已经是Eloquent Builder实例了
        $this->where('name', 'like', "%{$searchBy}%");
    }

    /**
     * 关联模型搜索逻辑
     */
    private function handleRelatedSearch(string $searchBy)
    {
        $this->orWhereHas('category', function ($query) use ($searchBy) {
            $query->where('title', 'like', "%{$searchBy}%");
        });
    }
}

这个方案适合逻辑拆分不多、不想额外建类的场景,把所有逻辑都留在服务提供者里,但依然保持代码的整洁。

方案三:用Trait复用拆分的逻辑

如果你的搜索逻辑需要在多个macro或者项目的其他地方复用,可以用Trait来封装这些方法,然后直接在macro里调用(不用全局修改Builder类)。

首先创建Trait:

trait SearchableBuilder
{
    /**
     * 静态方法接收Builder实例,处理基础搜索
     */
    public static function handleBasicSearch($builder, string $searchBy)
    {
        $builder->where('name', 'like', "%{$searchBy}%");
    }

    /**
     * 处理关联搜索
     */
    public static function handleRelatedSearch($builder, string $searchBy)
    {
        $builder->orWhereHas('category', function ($query) use ($searchBy) {
            $query->where('title', 'like', "%{$searchBy}%");
        });
    }
}

然后在服务提供者里调用:

use Illuminate\Database\Eloquent\Builder;

public function boot()
{
    Builder::macro('search', function (string $searchBy) {
        // 直接调用Trait里的静态方法,传入当前Builder实例
        \App\Traits\SearchableBuilder::handleBasicSearch($this, $searchBy);
        \App\Traits\SearchableBuilder::handleRelatedSearch($this, $searchBy);
        
        return $this;
    });
}

这个方案适合需要复用搜索逻辑的场景,Trait可以在多个地方被调用,避免重复代码。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 09:02:43