
本文深入探讨了在 Laravel 8 中利用查询构建器(Query Builder)或 Eloquent 进行动态搜索的最佳实践。针对根据可选请求参数构建复杂查询的场景,文章详细介绍了如何使用 `when` 方法优雅地实现条件查询,避免冗余的 `if` 语句,从而编写出更简洁、可读性更强的代码。
在开发基于 Laravel 的应用程序时,经常需要根据用户提供的可选参数(例如搜索关键词、筛选条件等)动态构建数据库查询。传统的做法是使用一系列 if 语句来判断参数是否存在,然后有条件地向查询链中添加 where 子句。然而,这种方法在面对多个可选条件时,可能导致代码冗长且难以维护。Laravel 提供了一种更为优雅和强大的解决方案:when 方法。
动态查询构建的挑战
考虑一个常见的场景:用户可以通过 URL 查询字符串(如 ?q=john&gender=m)来搜索用户列表。如果 q 或 gender 参数不存在,则不应将其作为查询条件。
初始的尝试可能如下所示:
public function index (Request $request){ $role = getRoleCode($request->role); $rolesQuery = Role::where('role', '=', $role); // 注意:这里应是 $rolesQuery 而非 $roles if ($request->q) { // 错误:$request->$q 是错误的变量引用方式 $rolesQuery->where('name', 'like', "%$request->$q%"); } if ($request->gender) { $rolesQuery->where('gender', '=', $request->gender); } // 在实际执行查询之前,可能需要将结果赋值给一个变量 $roles = $rolesQuery->orderBy('id', 'desc')->paginate(20); return view('admin.users.index', [ 'roles' => $roles, // ... 其他视图数据 ]);}登录后复制上述代码中存在几个问题:
变量命名不一致,$roles 在条件语句中被当做查询构建器实例,但在最后又被赋值为分页结果。$request-youjiankuohaophpcn$q 是一种错误的变量引用方式,正确的应是 $request->q 或 $request->input('q')。虽然 if 语句可以实现条件查询,但当条件增多时,代码的层级和复杂度会增加,降低可读性。优雅的解决方案:使用 when 方法
Laravel 的查询构建器和 Eloquent 模型都提供了 when 方法,用于实现条件性地向查询中添加子句。when 方法的签名如下:
WowTo 用AI建立视频知识库
60 查看详情
when(mixed $value, callable $callback, callable $default = null): static登录后复制
它接受三个参数:
$value:一个用于判断条件的布尔值或可以被评估为布尔值的值。如果此值为 true(或“真值”),则执行第二个参数 $callback。$callback:一个闭包函数,它将接收当前查询构建器实例作为第一个参数,以及 $value 作为第二个参数(如果 $value 是一个非布尔值且为真)。$default (可选):如果 $value 为 false(或“假值”),则执行此闭包函数。利用 when 方法,我们可以将上述动态查询重构为以下简洁且高效的形式:
<?phpnamespace App\Http\Controllers\Admin;use App\Http\Controllers\Controller;use Illuminate\Http\Request;use App\Models\Role; // 假设 Role 是你的模型class UserController extends Controller{ public function index(Request $request) { // 假设 getRoleCode 方法存在并返回角色代码 $roleCode = getRoleCode($request->role); $roles = Role::where('role', $roleCode) // 当 $request->input('q') 非空时,执行闭包添加 name 搜索条件 ->when($request->input('q'), function ($query, $search) { return $query->where('name', 'like', '%' . $search . '%'); }) // 当 $request->input('gender') 非空时,执行闭包添加 gender 筛选条件 ->when($request->input('gender'), function ($query, $gender) { return $query->where('gender', $gender); }) ->orderBy('id', 'DESC') ->paginate(20); return view('admin.users.index', [ 'roles' => $roles, 'role_name' => config('settings.roles')[$roleCode], // 假设配置存在 'role_en_name' => $request->role, 'q' => $request->input('q'), 'gender' => $request->input('gender'), ]); } // 假设这是一个辅助函数,用于获取角色代码 protected function getRoleCode($roleName) { // 实现根据角色名称获取角色代码的逻辑 // 例如: switch ($roleName) { case 'supervisor': return 'SUP'; case 'admin': return 'ADM'; default: return 'USR'; } }}登录后复制代码解析:
Role::where('role', $roleCode):这是所有查询的基础条件。->when($request->input('q'), function ($query, $search) { ... }):$request->input('q'):安全地从请求中获取 q 参数的值。如果 q 参数不存在或为空字符串,input() 方法将返回 null 或空字符串,这在布尔上下文中被评估为 false。function ($query, $search) { ... }:这是一个闭包函数。$query:代表当前的查询构建器实例。$search:如果 $request->input('q') 的值是“真值”,那么 $search 将接收到 $request->input('q') 的实际值。return $query->where('name', 'like', '%' . $search . '%');:在这个闭包中,我们向查询中添加了 name 字段的模糊搜索条件。务必从闭包中返回 $query 实例,以便继续链式调用。->when($request->input('gender'), function ($query, $gender) { ... }):同理,这会根据 gender 参数的值添加精确匹配条件。->orderBy('id', 'DESC')->paginate(20):最后,应用排序和分页。注意事项与最佳实践
使用 $request->input():始终建议使用 $request->input('param_name') 来获取请求参数,因为它比 $request->param_name 更健壮,可以处理 GET 和 POST 请求,并且在参数不存在时返回 null 而不是抛出错误。链式调用:when 方法的强大之处在于它保持了查询构建器的链式调用特性,使得代码流程清晰。闭包返回值:在 when 方法的闭包中,一定要返回修改后的 $query 实例,否则后续的链式操作将无法生效。可读性:when 方法显著提高了代码的可读性和简洁性,特别是当有多个可选条件时。PHP 7.4+ 箭头函数:如果你的项目使用 PHP 7.4 或更高版本,可以使用箭头函数进一步简化闭包的写法,如示例答案中所示:fn ($query, $search) => $query->where('name', 'like', '%'. $search .'%')。总结
Laravel 的 when 方法是处理动态条件查询的利器,它提供了一种优雅、高效且可读性强的方式来构建复杂的数据库查询。通过合理运用 when 方法,开发者可以避免冗余的 if 语句,使控制器代码更加简洁和专业,从而提升应用程序的可维护性和开发效率。掌握这一技巧对于任何 Laravel 开发者来说都至关重要。
以上就是掌握 Laravel 查询构建器中的条件查询技巧的详细内容,更多请关注php中文网其它相关文章!

