在开发 Web 应用过程中,条件搜索是一个不可避免的话题。 特别是在后台的开发中,会有很多根据条件来选筛选列表的场景。比如说用户手机号、昵称,产品的类别价格范围等等,常规方法中,我们都是根据前台不同的条件,然后进行相应的代码搜索。但是这样的扩展性很一般,特别在增加新条件的时候,需要去侵入业务代码,我们来看看传统的代码中是怎么实现的:
public function filter(Request $request, User $user) {
$user = (new User())->newQuery();
if ($request->has('name')) {
return$user->where('name', $request->input('name'))->get();
}
if ($request->has('company')) {
return$user->where('company', $request->input('company'));
}
return$user->get();
}
class UserSearch {
public static function apply(Request $filters) {
//TODO filter
}
}
然后就可以在控制器中这样来使用:
class SearchController extends Controller {
public function filter(Request $request) {
return UserSearch::apply($request);
}
}
虽然我们只是把搜索的代码移到一个单独的类中了,但是已经比之前看起来好多了。然后再进一步抽象:
public static function apply(Request $filters){
$query = (new User)->newQuery();
$query = static::applyFiltersToQuery($filters, $query);
return$query->get();
}
但是这样还是需要判断很多的条件,我们可以把筛选条件抽象成接口:
interface Filter{
public static function apply(Builder $builder, $value);
}
然后定义一系列的搜索规则:
class Name implements Filter{
public static function apply(Builder $builder, $value)
{
return$builder->where('name', $value);
}
}
class City implements Filter
{
public static function apply(Builder $builder, $value)
{
return$builder->where('city', $value);
}
}