在很多情况下,列表数据都需要筛选,比如订单数据列表,可能根据前台传的订单状态,用户邮箱等条件进行筛选,通常我们的代码如下:
$orders_handler = Order::query();
//筛选条件
if ($request->get('status','')) {
$orders_handler->where('status', 'escrow');
}
if ($params['shipment_status']) { #发货方式
switch ($params['shipment_status']) {
case 1 ://订货代购单交期延误
$orders_handler->where('type', '<>', Order::TYPE_IN_STOCK)
->whereIn('payment.status', [Order::PAYMENT_PAID, Order::PAYMENT_PARTIALLY_REFUNDED])
->where('status', '<=', Order::STATUS_VERIFIED)
->where('estimated_shipment_date', '<', time());
break;
case 2 ://现货独立未发货
$orders_handler->where('type', Order::TYPE_IN_STOCK)
->whereIn('payment.status', [Order::PAYMENT_PAID, Order::PAYMENT_PARTIALLY_REFUNDED])
->where('status', '<=', Order::STATUS_DISPATCH)
->where('shipment_type', '<>', Order::SHIPMENT_ACCOUNT_JLC)
->exceptOldOrder();
break;
case 3 ://绑PCB未发货
$orders_handler->whereIn('payment.status', [Order::PAYMENT_PAID, Order::PAYMENT_PARTIALLY_REFUNDED])
->where('status', '<=', Order::STATUS_DISPATCH)
->where('shipment_type', Order::SHIPMENT_ACCOUNT_JLC);
break;
case 4 ://订货代购单未发货
$orders_handler->where('type', '<>', Order::TYPE_IN_STOCK)
->whereIn('payment.status', [Order::PAYMENT_PAID, Order::PAYMENT_PARTIALLY_REFUNDED])
->where('status', '<=', Order::STATUS_DISPATCH)
->exceptOldOrder();
break;
case 5 ://已发货
$orders_handler->where('status', '>=', Order::STATUS_DISPATCH);
break;
}
}
.....
最重要的是这种筛选条件可能根据需求不断的添加...
那么我们是否可以优化这种情况呢…
首先我们先建一个说有过滤条件条件的基类:
基类的位置同学们可以随便放,我是新建目录Filter
BaseQueryFilter:
namespace App\Filter;
use Illuminate\Http\Request;
use Jenssegers\Mongodb\Eloquent\Builder;
abstract class BaseQueryFilter
{
protected $request;
protected $builder;
public function __construct(Request $request)
{
$this->request = $request;
}
public function apply(Builder $builder)
{
$this->builder = $builder;
foreach ($this->filters() as $name => $value) {
if ($value) {
if (strstr($name,'_')){
$name_array = explode('_',$name);
$method = '';
foreach ($name_array as $key => $new_name) {
if ($key != 0) $new_name = ucfirst($new_name);
$method .= $new_name;
}
$name = $method;
}
if (method_exists($this, $name)) {
call_user_func_array([$this, $name], array_filter([$value]));
}
}
}
return $this->builder;
}
public function filters()
{
return $this->request->all();
}
}
apply 过滤了前台传的空值,同时实现如pay_method -> payMethod 的转化,这段同学们可以酌情封装下哦
这次我们主要以过滤订单列表数据作为例子,创建OrderFilter继承BaseQueryFilter
OrderFilter:
/**
* Created by PhpStorm.
* User: SZJLS
* Date: 2019/7/2
* Time: 19:00
*/
namespace App\Filter;
use App\Models\Order;
class OrderFilter extends BaseQueryFilter
{
public function search($search)
{
return $this->builder->where('user.email', 'like', "%{$search}%");
}
public function payMethod($pay_method)
{
$this->builder->where('status', '>=', Order::STATUS_SUBMITTED);
switch ($pay_method) {
case 1 ://escrow
$this->builder->where('payment.method', 'escrow');
break;
case 3 ://transfer
$this->builder->where('payment.method', 'transfer');
break;
case 5 ://paypal
$this->builder->where('payment.method', 'paypal');
break;
case 7 ://stripe
$this->builder->where('payment.method', 'stripe');
break;
case 9 ://paypal express
$this->builder->where('payment.method', 'PayPal Express');
break;
case 10:
$this->builder->where('payment.method', 'Advance Payment Balance');
break;
}
return $this->builder;
}
...
}
接下来就是应用了,在orderModel 里创建查询作用域,注入BaseQueryFilter 进行查询过滤
orderModel:
public function scopeFilter($query,BaseQueryFilter $filter) {
return $filter->apply($query);
}
OrderController:
public function __construct(OrderRepository $repository)
{
$this->repo = $repository;
}
public function index(OrderFilter $filter)
{
$orders = $this->repo->getOrderList($filter);
...
return view('new_admin.order.index', [
'orders' => $orders,
'order_types' => $order_types,
...
]);
}
OrderRepository:
public function getOrderList(OrderFilter $filter)
{
$handle = Order::query();
//默认显示已支付
if (empty($filter->filters())) {
$handle->where('payment.status', '>', Order::PAYMENT_UNPAID);
} else {
$handle->filter($filter);
};
return $handle->orderBy('created_at', 'desc')->paginate();
}
如上我们就应用scope 作用于对多条件查询进行了优化,使代码看起来更优雅
以上实现都是基于mongodb的,所以有些数据看起来不怎么合适