
本文详解如何在 Laravel 中正确实现带条件搜索的数据库查询,解决原始代码中因混用原生 SQL 与集合操作导致的 where() on Array 和 explode() expects string 等典型错误,并推荐使用 Eloquent 模型替代原始查询以提升可维护性与安全性。
本文详解如何在 laravel 中正确实现带条件搜索的数据库查询,解决原始代码中因混用原生 sql 与集合操作导致的 `where() on array` 和 `explode() expects string` 等典型错误,并推荐使用 eloquent 模型替代原始查询以提升可维护性与安全性。
在 Laravel 开发中,实现动态搜索功能时,常见误区是先执行原生 SQL 查询获取数组结果,再试图对 PHP 数组调用 Collection 的链式方法(如 where()),这必然导致 Call to a member function where() on Array 错误;而若强行将数组转为 Collection 后误用于不兼容上下文(如某些 Blade 渲染或 JSON 序列化场景),又可能触发 explode() expects parameter 2 to be string, object given 等隐式类型错误。
根本解法是避免“先查后滤”,改用 Eloquent 查询构建器在数据库层完成搜索逻辑,既高效又安全。以下是重构后的专业实践:
✅ 正确做法:使用 Eloquent + Query Builder 动态构建搜索条件
假设你已为 pengguna 表定义了 User 模型(建议遵循 Laravel 命名规范,如 App\Models\User),并建立好关联关系:
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'pengguna';
protected $guarded = [];
// 可选:定义关联(简化后续 JOIN 逻辑)
public function effectiveRank()
{
return $this->belongsTo(Rank::class, 'effective_rank', 'id');
}
public function appointedRank()
{
return $this->belongsTo(Rank::class, 'appointed_rank', 'id');
}
public function hierarchy()
{
return $this->belongsTo(Hierarchy::class, 'userrank', 'id');
}
public function leader()
{
return $this->belongsTo(User::class, 'placement', 'id');
}
}
然后在控制器中重写 index 方法:
use App\Models\User;
use Illuminate\Http\Request;
public function index($mid, Request $request)
{
$search = $request->input('search', '');
// 构建基础查询(含所有 LEFT JOIN 关系)
$query = User::select([
'a.id',
'a.alternate_id',
'a.setujuterma',
'a.mykad',
'a.nama',
'a.email',
'a.notel',
'a.etunai',
'b.ranktitle as effective_rank_title',
'c.ranktitle as appointed_rank_title',
'd.nama as hirarki',
'e.alternate_id as placement',
'e.nama as leadername',
'a.akses',
'a.suspendreason',
'a.regstamp',
'a.matagajet',
'f.display as hirarkidisplay',
\DB::raw('IF(a.mykadverify = "3", "1", "0") as mykadverifydecode'),
])
->from('pengguna as a')
->leftJoin('penggunarank as b', 'a.effective_rank', '=', 'b.id')
->leftJoin('penggunarank as c', 'a.appointed_rank', '=', 'c.id')
->leftJoin('hirarki as d', 'a.userrank', '=', 'd.id')
->leftJoin('pengguna as e', 'a.placement', '=', 'e.id')
->leftJoin('hirarkimid as f', function ($join) use ($mid) {
$join->on('a.userrank', '=', 'f.hirarki')
->on('a.mid', '=', 'f.mid');
})
->where('a.mid', $mid)
->where('a.akses', '!=', -1);
// 动态添加搜索条件(仅当 search 非空时)
if (!empty($search)) {
$query->where(function ($q) use ($search) {
$q->where('a.alternate_id', 'LIKE', "%{$search}%")
->orWhere('a.nama', 'LIKE', "%{$search}%")
->orWhere('a.mykad', 'LIKE', "%{$search}%")
->orWhere('a.notel', 'LIKE', "%{$search}%")
->orWhere('a.email', 'LIKE', "%{$search}%");
});
}
// 执行查询并排序
$users = $query->orderByDesc('a.alternate_id')->get();
$count = $users->count();
// 注意:原代码中 $user 未定义,此处应返回 $users
return response()->json([
'data' => $users,
'count' => $count,
]);
}
⚠️ 关键注意事项
- 永远不要拼接用户输入到 SQL 字符串中:原始代码中 WHERE a.mid ='. $mid .' 存在严重 SQL 注入风险,必须使用参数绑定(如 where('a.mid', $mid))。
- collect()->where() 是客户端过滤,性能差且易出错:尤其在数据量大时,应在数据库层完成 WHERE ... LIKE 过滤。
- $collection->where(...) 语法错误:Collection 的 where() 不接受闭包,正确用法是 $collection->filter(fn($item) => ...);但再次强调——优先用数据库查询。
- 返回值一致性:确保 API 返回结构清晰(如 data 和 count 字段),避免未定义变量(如原文中的 $user)。
✅ 总结
Laravel 搜索功能的黄金准则:
? 用 Eloquent/Query Builder 在 DB 层过滤,而非 PHP 层遍历数组;
? 始终校验并清理用户输入,杜绝 SQL 注入;
? 合理建模与关联,让复杂 JOIN 更可读、可复用;
? 返回标准化 JSON 响应,便于前端消费。
遵循以上方式,即可写出健壮、安全、高性能的搜索接口。











