提问者:小点点

在搜索函数中从模型访问表列时出现问题


我有一个搜索功能,可以根据用户输入的过滤器(从/到年龄,从/到身高)搜索用户。 问题是年龄列在users表(User model)中,而身高列在user_profiles表(UserProfile model)中。 我可以从每个模型中单独地获得结果,但是我想在将这两个条件结合起来时获得结果。 例如,获取年龄在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个答案

匿名用户

据我所知,您需要一个类似于以下内容的查询:

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

这将获取所有用户及其配置文件,其中UER的年龄介于$minage$maxage之间,并且其配置文件的高度介于$minheight$maxheight之间。

编辑

如果您希望能够用filer单独检索数据,那么您需要的是条件子句。 代码如下所示:

$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]);
    });
});

我希望我没有搞砸语法,但是你明白了。 或者,您也可以使用扩展$query变量的if-else语句来实现同样的功能,但我个人更喜欢Laravel的优雅的when语法。

匿名用户

我会做以下工作:

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

$user->筛选器($request->输入('min_height'),$request->输入('max_height'),$request->输入('min_age'),$request->输入('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. 我们返回的是eloquent的实例,而不是执行$query->get()的原因是,这样我们可以在控制器中执行它,并且对于我们重用此代码的每个地方,我们可以执行诸如orderbygroupbyfirstget之类的操作,以及根据我们调用它的地方的需要执行其他操作。 因为如果执行$query->get(),您将只使用集合
  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(),
    ]);
}

我不知道这个解释是否足够清楚,但我会非常乐意回答你的任何问题,只要我能回答的话

我希望语法没有问题,但是您可以通过添加更多的If和else语句来实现您的需要,以便根据需要对它们进行过滤。