在 Laravel 9 中,基于 Spatie\QueryBuilder\QueryBuilder 来生成查询 SQL,同一字段可支持:partial、exact

1、参考:在 Laravel 9 中,在异步队列中复用 Spatie\QueryBuilder\QueryBuilder 来生成查询 SQL


    /**
     * 查询生成器
     * @param array $criteria
     * @return QueryBuilder
     */    public function QueryBuilder(array $criteria): QueryBuilder
    {
        return QueryBuilder::for(OrderShippingLog::class, new Request($criteria))
            ->allowedFilters([
                AllowedFilter::exact('shop_plat_id'),
                AllowedFilter::exact('shop_id'),
                AllowedFilter::exact('logistic_channel_id'),
                AllowedFilter::exact('logistic_company_id'),
                AllowedFilter::exact('operated_source'),
                AllowedFilter::exact('plat_order_no'),
                AllowedFilter::exact('logistic_freight_no'),
                AllowedFilter::exact('logistic_freight_transfer_no'),
                AllowedFilter::exact('logistic_freight_inner_no'),
                AllowedFilter::exact('logistic_virtual_number'),
                AllowedFilter::exact('shipping_type'),
                AllowedFilter::exact('shipping_status'),
                AllowedFilter::scope('shipping_at_gmt_start'),
                AllowedFilter::scope('shipping_at_gmt_end'),
                AllowedFilter::scope('operated_at_gmt_start'),
                AllowedFilter::scope('operated_at_gmt_end'),
            ])
            ->with('shopPlat:id,title')
            ->with('shop:id,title')
            ->with('order.orderItemLogisticsFeatures')
            ->with('order.urgentType:id,title,color')
            ->with('logisticChannel:id,title')
            ->with('operatorUser:id,name,number')
            ->defaultSort('-id');
    }

2、现在的实现方案,针对某一个字段,只能够使用一种过滤器,或者 partial ,或者 exact。参考:在 Yii 2.0 中,实现过滤器的请求参数形式

{
    "filter": {
        "plat_order_no": [
            "GM20240202055938",
            "GM20240131081251"
        ]
    },
    "sort": "-operated_at_gmt",
    "per_page": 20,
    "page": 1
}
{
    "filter": {
        "plat_order_no": [
   "like": [
    "GM20240202055938",
    "GM20240131081251"
   ]
        ]
    },
    "sort": "-operated_at_gmt",
    "per_page": 20,
    "page": 1
}

3、针对需要 单个模糊检索,多个精确检索 的字段,决定验证其类型为数组,然后判断数组元素的数量,如果大于 1 ,则精确检索,否则,模糊检索。最终实现如下。

$validator = Validator::make(
            $params,
            [
                'filter.plat_order_no' => 'array',
                'filter.plat_order_no.*' => 'max:100',
            ],
            [
                'filter.plat_order_no.array' => '原订单的平台订单号必须是数组',
                'filter.plat_order_no.*.max' => '原订单的平台订单号最大长度是100',
            ]
        );
        if ($validator->stopOnFirstFailure()->fails()) {
            throw new BusinessException(BusinessException::MODULE_ORDER, $validator->getMessageBag()->first());
        }

        return $validator;
        // 单个模糊检索,多个精确检索:订单号、交易号、退货单号、退货快递单号、货运单号、商品SKU
        // 键为请求参数,值为 SQL 查询字段
        $fields = [
            'plat_order_no' => 'plat_order_no',
        ];

        foreach ($fields as $key => $field) {
            if (isset($criteria['filter'][$key])) {
                if (count($criteria['filter'][$key]) > 1) {
                    // 多个精确检索
                    $allowedFilters[] = AllowedFilter::exact($field);
                } else {
                    // 单个模糊检索
                    $allowedFilters[] = AllowedFilter::partial($field);
                }

                if ($key != $field) {
                    $criteria['filter'][$field] = $criteria['filter'][$key];
                    unset($criteria['filter'][$key]);
                }
            }
        }

        $builder = QueryBuilder::for(ReturnOrder::class, new Request($criteria))
            ->select('return_orders.*')
            ->allowedFilters($allowedFilters)
            ->defaultSort('-id');

 

 

永夜