在搜索功能中从模型访问表列的问题

时间:2020-06-29 13:01:30

标签: php laravel

我有一个搜索功能,可以根据用户输入的过滤条件(年龄/年龄,身高/年龄)来搜索用户。问题是age列在users表(用户模型)中,height列在user_profiles表(UserProfile模型)中。我可以轻松地从每个模型获得结果,但是我希望在结合这两个条件时获取结果。例如,获取年龄在30至40岁之间且在180厘米至190厘米之间的用户。任何帮助表示赞赏。这是我的代码。

SearchController.php

class SearchController extends Controller
{
    public function search(Request $request, User $user)
    {
        $query = User::query();   // HERE I NEED TO FETCH USER PROFILE COLUMNS FROM MODEL ALONG WITH USER
        dd($query);

        // HEIGHT SETTING
        if ($request->has('from_cm')) {
            $request->get('from_cm');
        }

        if ($request->has('to_cm')) {
            $request->get('to_cm');
        }

        if ($request->from_cm && $request->to_cm) {
            $query->whereBetween('height', [$request->from_cm, $request->to_cm]);
        } elseif ($request->from_cm) {
            $query->where('height', '>=', $request->from_cm);
        } elseif ($request->to_cm) {
            $query->where('height', '<=', $request->to_cm);
        }

        // AGE SETTING
        if ($request->has('from_age')) {
            $request->get('from_age');
        }

        if ($request->has('to_age')) {
            $request->get('to_age');
        }

        if ($request->from_age && $request->to_age) {
            $query->whereBetween('age', [$request->from_age, $request->to_age]);
        } elseif ($request->from_age) {
            $query->where('age', '>=', $request->from_age);
        } elseif ($request->to_age) {
            $query->where('age', '<=', $request->to_age);
        }

        $results = $query->get();
        //dd($results);
    }
}

User.php

protected $fillable = [
        'username', 
        'email', 
        'first_name',
        'last_name',
        'age',
    ];  

public function userProfile()
{
    return $this->hasOne(UserProfile::class);
}

UserProfile.php

protected $fillable = [
        'user_id',
        'interested_in',
        'height',
      
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

因此,需要明确的是,我不需要特定用户及其用户个人资料,而是将用户和用户个人资料模型中的列合并到一个变量中($ query)。

2 个答案:

答案 0 :(得分:1)

据我了解,您需要类似以下查询:

$users = User::with('userProfile')
->whereBetween('age', [$minAge, $maxAge])
->whereHas('userProfile', function($query){
    $query->whereBetween('height', [$minHeight, $maxHeight]);
});

这将使用年龄在$minAge$maxAge之间且个人资料的高度在$minHeight$maxHeight之间的个人资料获取所有用户。

编辑

如果您希望能够与文件管理器分别检索数据,那么您需要的是conditional clauses。代码如下所示:

$users = User::with('userProfile')
->when($ageFilterActive, function($query, $ageFilterActive) {
    $query->whereBetween('age', [$minAge, $maxAge]);
})->when($heightFilterActive, function($query, $heightFilterActive) {
    $query->whereHas('userProfile', function($query){
        $query->whereBetween('height', [$minHeight, $maxHeight]);
    });
});

我希望我不会弄乱语法,但是您明白了。另外,您可以通过扩展if-else变量的$query语句来实现相同的目的,但是我个人更喜欢Laravel优雅的when语法。

答案 1 :(得分:1)

我将执行以下操作:

  1. 从控制器中提取此逻辑并将其放入用户模型。
  2. 由于您在控制器中为用户模型使用了依赖注入,因此您可以在控制器中执行类似的操作

$user->filter($request->input('min_height'),$request->input('max_height'),$request->input('min_age'),$request->input('max_age'));

这样,控制器将负责将所需的数据传递到模型,然后您就可以在模型内部进行查询。

这样做的好处是

  1. 更清晰的控制器
  2. 控制器将只处理请求,传递所需的数据并将结果传递给索引。
  3. 只要拥有用户实例,您就可以在任何地方重复使用此过滤器
  4. 责任将在模型和控制器之间分配,控制器将不会做任何事情

在您的用户模型中,查询将如下所示:

public function scopeWithUserProfile($query)
{
    // Left join or inner join depends on your needs
    return $query->join('user_profile', 'users.id', '=', 'user_profile.user_id');
}

public function filter($minHeight, $maxHeight, $minAge, $maxAge) {
    $query = $this->query()
        ->withUserProfile();
    
    if (!is_null($minHeight) && !is_null($maxHeight)) {
        $query->whereBetween('height', [$minHeight, $maxHeight]);
    }
    
    if (!is_null($minAge) && !is_null($maxAge)) {
        $query->whereBetween('age', [$minAge, $maxAge]);
    }
    
    return $query;
}
  1. 我们返回雄辩的实例而我们没有这样做的原因 $query->get()就是这样,我们可以在控制器中以及在每个 我们正在重用此代码,我们可以根据调用地方的需要来执行诸如orderBygroupByfirstget之类的操作。因为如果您进行$query->get(),则只能使用Collection
  2. 之后,我们可以在控制器$query->get()中执行类似的操作,然后从那里我们将收集所需的数据。

在最后的控制器中,您必须具有类似的内容

public function search(Request $request, User $user)
{
    $user->filter($request->input('min_height'),$request->input('max_height'),$request->input('min_age'),$request->input('max_age'));
    
    return view('your.view.here', [
        'userData' => $user->get(),
    ]);
}

我不知道解释是否足够清楚,但是只要我可以:P

我希望语法不错,但是您可以通过添加更多的If和else语句来根据需要过滤它们,从而满足您的需求。