Laravel 5.4 Eloquent 从单个输入过滤

Laravel 5.4 Eloquent filter from a single input

我正在尝试使用 laravel eloquent 进行查询以加入带有地址和电话号码的公司 table 以便用户可以在单个输入字段中键入内容,例如地址行或数字,它将查询多个 tables/columns 且仅 return 个具有潜在匹配项。

我已经查看了 wherehas,但如果数字和地址 table 都匹配,它似乎会停止所有结果。 我相信在这些 table 上使用标准的左连接,我可以让它工作,但如果可能的话,我想要一个干净的解决方案。下面是我正在处理的内容,实际上 return 没有任何过滤结果,所以我有点摸不着头脑。

目标是单一输入以便于使用,但在多个 columns/tables 和 returning 行中搜索仅匹配。是否有 wherehas 选项但可能适用于多种情况?希望有人能理解我在做什么。

public function addresses(){
    return $this->hasMany(Company_addresses::class, 'company_id', 'id');
}

public function digits(){
    return $this->hasMany(Company_digit::class, 'company_id', 'id');
}

public static function search($request)
{
    $filters = $request->all();
    $sortby = isset($filters['sortby']) ? $filters['sortby'] : 'created_at';
    $orderby = isset($filters['orderby']) ? $filters['orderby'] : 'desc';

    return static::with([
        'addresses' => function ($query) use ($filters) {
        $query->where('address_line_1', "LIKE", '%'.$filters['name'].'%')
            ->orWhere('address_line_2', "LIKE", '%'.$filters['name'].'%')
            ->orWhere('city', "LIKE", '%'.$filters['name'].'%')
            ->orWhere('county', "LIKE", '%'.$filters['name'].'%')
            ->orWhere('post_code', "LIKE", '%'.$filters['name'].'%');
        },
        'digits' => function ($query) use ($filters) {
        $query->where('number', "LIKE", '%'.$filters['name'].'%')
            ->orWhere('extension', "LIKE", '%'.$filters['name'].'%');
        }])
        ->orderBy('companies.'.$sortby, $orderby)
        ->select(['id', 'registered_name', 'trading_name', 'created_at', 'type'])
        ->paginate(20);
}

这就是您使用关系方法的方式。

您确实需要使用 ->whereHas(),但您需要将 ->whereHas('addresses', ...)->orWhereHas('digits', ...) 都包装在 ->where(function ($q) ...) 方法中。

像这样:

public static function search($request)
{
    $filters = $request->all();
    $sortby = isset($filters['sortby']) ? $filters['sortby'] : 'created_at';
    $orderby = isset($filters['orderby']) ? $filters['orderby'] : 'desc';

    return self::where(function ($q) use ($filters) {
            $q->whereHas('addresses', function ($q) use ($filters) {
                $q->where('address_line_1', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('address_line_2', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('city', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('county', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('post_code', "LIKE", '%'.$filters['name'].'%');
            })
            ->orWhereHas('digits', function ($q) use ($filters) {
                $q->where('number', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('extension', "LIKE", '%'.$filters['name'].'%');
            });
        })
        ->with(['addresses', 'digits'])
        ->orderBy('companies.'.$sortby, $orderby)
        ->select(['id', 'registered_name', 'trading_name', 'created_at', 'type'])
        ->paginate(20);
}

虽然上面的代码应该有效,但我建议将搜索方法从 static 方法重写为 scope。我肯定会重写它以保持 $request 不在其中,因为请求与模型无关。

像这样:

// Use it like: \App\Company::search($request->all())->paginate(20);
public function scopeSearch($q, $filters)
{
    $sortBy = isset($filters['sortby']) ? $filters['sortby'] : 'created_at';
    $orderBy = isset($filters['orderby']) ? $filters['orderby'] : 'desc';

    return $q->where(function ($q) use ($filters) {
            $q->whereHas('addresses', function ($q) use ($filters) {
                $q->where('address_line_1', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('address_line_2', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('city', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('county', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('post_code', "LIKE", '%'.$filters['name'].'%');
            })
            ->orWhereHas('digits', function ($q) use ($filters) {
                $q->where('number', "LIKE", '%'.$filters['name'].'%')
                    ->orWhere('extension', "LIKE", '%'.$filters['name'].'%');
            });
        })
        ->with(['addresses', 'digits'])
        ->orderBy('companies.'.$sortby, $orderby)
        ->select(['id', 'registered_name', 'trading_name', 'created_at', 'type']);
}

因为你在我还没能理解之前就得到了答案。这是我在澄清问题后 post 对代码进行的简单重构。

public static function search()
{
    $name = request('name');

    return static::whereHas('addresses', function ($query) use ($name) {
            $query->where('address_line_1', "like", "%{$name}%")
                ->orWhere('address_line_2', "like", "%{$name}%")
                ->orWhere('city', "like", "%{$name}%")
                ->orWhere('county', "like", "%{$name}%")
                ->orWhere('post_code', "like", "%{$name}%");
        })->orWhereHas('digits', function ($query) use ($name) {
            $query->where('number', "like", "%{$name}%")
                ->orWhere('extension', "like", "%{$name}%");
        })
        ->orderBy('companies.'.request('sortby', 'created_at'), request('orderby', 'desc'))
        ->select(['id', 'registered_name', 'trading_name', 'created_at', 'type'])
        ->paginate(20);
}