
本文详解如何在 Laravel 中正确实现数据库搜索功能,解决原始代码中因混用原生 SQL 与集合过滤导致的 Call to a member function where() on Array 和 explode() expects parameter 2 to be string, object given 等典型错误,并推荐基于 Eloquent 的安全、可维护、可扩展的搜索方案。
本文详解如何在 laravel 中正确实现数据库搜索功能,解决原始代码中因混用原生 sql 与集合过滤导致的 `call to a member function where() on array` 和 `explode() expects parameter 2 to be string, object given` 等典型错误,并推荐基于 eloquent 的安全、可维护、可扩展的搜索方案。
在 Laravel 开发中,实现搜索功能时,常见误区是先执行原生 SQL 查询获取数组结果,再试图用集合(Collection)方法(如 where()、filter())进行二次筛选——这不仅性能低下,更易引发类型错误。原始代码中 $users = DB::select(...) 返回的是 PHP 原生数组,而 collect($users)->where(...) 中的 where() 是 Collection 方法,仅支持键值对匹配(如 where('name', 'John')),不接受闭包回调,因此调用 $collection->where(function () {}) 会直接报错:explode() expects parameter 2 to be string, object given(因底层尝试将闭包转为字符串解析)。
✅ 正确做法是:将搜索逻辑下推至数据库层,使用 Eloquent Query Builder 构建动态 WHERE 条件,让 MySQL 承担过滤职责,既高效又安全。以下是优化后的标准实践:
✅ 推荐方案:使用 Eloquent 模型 + 动态查询构建
首先,确保你已定义对应数据表的 Eloquent 模型(如 Pengguna),并正确配置关联关系:
// app/Models/Pengguna.php
class Pengguna extends Model
{
protected $table = 'pengguna';
protected $guarded = [];
// 示例关联(按实际结构调整)
public function effectiveRank()
{
return $this->belongsTo(PenggunaRank::class, 'effective_rank', 'id');
}
public function appointedRank()
{
return $this->belongsTo(PenggunaRank::class, 'appointed_rank', 'id');
}
public function hirarki()
{
return $this->belongsTo(Hirarki::class, 'userrank', 'id');
}
public function placementUser()
{
return $this->belongsTo(Pengguna::class, 'placement', 'id');
}
}然后,在控制器中重构 index 方法:
use App\Models\Pengguna;
use Illuminate\Http\Request;
public function index(Request $request, $mid, $payload)
{
// 验证并提取搜索关键词
$search = $payload['search'] ?? '';
// 构建基础查询:排除 akses = -1,限定 mid
$query = Pengguna::where('mid', $mid)
->where('akses', '!=', -1);
// 动态添加搜索条件(仅当 search 非空时)
if (!empty($search)) {
$query->where(function ($q) use ($search) {
$q->where('alternate_id', 'LIKE', "%{$search}%")
->orWhere('nama', 'LIKE', "%{$search}%")
->orWhere('mykad', 'LIKE', "%{$search}%")
->orWhere('notel', 'LIKE', "%{$search}%")
->orWhere('email', 'LIKE', "%{$search}%");
});
}
// 执行查询并关联所需数据(替代冗长 JOIN)
$users = $query->with([
'effectiveRank' => fn($q) => $q->select('id', 'ranktitle'),
'appointedRank' => fn($q) => $q->select('id', 'ranktitle'),
'hirarki' => fn($q) => $q->select('id', 'nama'),
'placementUser' => fn($q) => $q->select('id', 'alternate_id', 'nama'),
'hirarkiMid' => fn($q) => $q->where('mid', $mid)->select('hirarki', 'display'),
])
->select(
'a.id', 'a.alternate_id', 'a.setujuterma', 'a.mykad', 'a.nama',
'a.email', 'a.notel', 'a.etunai', 'a.akses', 'a.suspendreason',
'a.regstamp', 'a.matagajet',
DB::raw('IF(a.mykadverify = "3","1","0") as mykadverifydecode')
)
->get();
// 排序(注意:orderBy 应在数据库层执行,而非 collection)
$users = $users->sortByDesc('alternate_id')->values();
$count = $users->count();
// ⚠️ 注意:原始返回中 $user 未定义,应为 $users
return [
'data' => $users,
'count' => $count,
];
}? 关键改进点说明:
- 避免 N+1 查询:使用 with() 预加载关联,而非手动 LEFT JOIN;
- SQL 注入防护:所有参数均通过 Query Builder 绑定,自动转义,杜绝拼接 SQL;
- 性能优化:搜索和排序均在数据库执行,非内存中处理大数组;
- 类型安全:返回 Collection 实例,可链式调用 map()、filter() 等方法;
- 可维护性:逻辑清晰,便于后续扩展字段或添加分页(如 ->paginate(15))。
⚠️ 注意事项:
- 原始代码中 $user 变量未定义,返回时需确认变量名一致性;
- 若必须使用原生 SQL(如复杂视图),请改用 DB::table()->where(...)->get() 保持 Query Builder 链式调用;
- 搜索字段建议添加数据库索引(如 ALTER TABLE pengguna ADD INDEX idx_search (alternate_id, nama, mykad);)以提升响应速度。
遵循此模式,即可彻底规避集合误用错误,构建健壮、可扩展的 Laravel 搜索功能。


















