没有不值得去解决的问题,也没有不值得去学习的技术!

在 Laravel 9 中,基于 spatie/laravel-query-builder 查询关联表中的字段时,按需添加 join 语句的实现

调整后的实现如下,在准备好 new Request($criteria) 之后,再判断是否 join ,生成的 SQL 按需关联其他表,符合预期
1、现阶段的实现如下,最终生成的 SQL 永远都需要 join 关联上其他几张表,否则会报错


{
    "filter": {
        "sku_code": [
            "smileying01"
        ]
    },
    "per_page": 100,
    "page": 1
}




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

        $allowedFilters = [
            AllowedFilter::exact('signing_status'),
            AllowedFilter::partial('remark'),
            AllowedFilter::exact('return_type'),
            AllowedFilter::exact('processing_method'),
            AllowedFilter::scope('created_at_gmt_start'),
            AllowedFilter::scope('created_at_gmt_end'),
            AllowedFilter::scope('order_payment_at_gmt_start'),
            AllowedFilter::scope('order_payment_at_gmt_end'),
            AllowedFilter::scope('order_delivery_at_gmt_start'),
            AllowedFilter::scope('order_delivery_at_gmt_end'),
        ];

        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]);
                }
            }
        }

        // 退货原因ID,转换 SQL 查询字段
        if (isset($criteria['filter']['refund_reason_id'])) {
            $criteria['filter']['return_order_refund_reasons.refund_reason_id'] = $criteria['filter']['refund_reason_id'];
            unset($criteria['filter']['refund_reason_id']);
            $allowedFilters[] = AllowedFilter::exact('return_order_refund_reasons.refund_reason_id');
        }

        $builder = QueryBuilder::for(ReturnOrder::class, new Request($criteria))
            ->select('return_orders.*')
            ->leftJoin('return_order_items', 'return_order_items.return_order_id', 'return_orders.id')
            ->leftJoin('return_order_refund_reasons', 'return_order_refund_reasons.return_order_id', 'return_orders.id')
            ->leftJoin('return_order_logistics', 'return_order_logistics.return_order_id', 'return_orders.id')
            ->allowedFilters($allowedFilters)
            ->with('returnOrderItems')
            ->with('returnOrderRefundReasons.refundReason')
            ->with('returnOrderLogistics')
            ->with('resendOrder')
            ->with('order.orderItemLogisticsFeatures')
            ->defaultSort('-id');




select
  count(*) as aggregate
from
  `return_orders`
  left join `return_order_items` on `return_order_items`.`return_order_id` = `return_orders`.`id`
  left join `return_order_refund_reasons` on `return_order_refund_reasons`.`return_order_id` = `return_orders`.`id`
  left join `return_order_logistics` on `return_order_logistics`.`return_order_id` = `return_orders`.`id`
where
  (
    LOWER(`return_order_items`.`sku_code`) LIKE '%smileying01%'
  )


2、调整后的实现如下,在准备好 new Request($criteria) 之后,再判断是否 join ,生成的 SQL 按需关联其他表,符合预期。如图1
调整后的实现如下,在准备好 new Request($criteria) 之后,再判断是否 join ,生成的 SQL 按需关联其他表,符合预期
图1


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

        $allowedFilters = [
            AllowedFilter::exact('signing_status'),
            AllowedFilter::partial('remark'),
            AllowedFilter::exact('return_type'),
            AllowedFilter::exact('processing_method'),
            AllowedFilter::scope('created_at_gmt_start'),
            AllowedFilter::scope('created_at_gmt_end'),
            AllowedFilter::scope('order_payment_at_gmt_start'),
            AllowedFilter::scope('order_payment_at_gmt_end'),
            AllowedFilter::scope('order_delivery_at_gmt_start'),
            AllowedFilter::scope('order_delivery_at_gmt_end'),
        ];

        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]);
                }
            }
        }

        // 退货原因ID,转换 SQL 查询字段
        if (isset($criteria['filter']['refund_reason_id'])) {
            $criteria['filter']['return_order_refund_reasons.refund_reason_id'] = $criteria['filter']['refund_reason_id'];
            unset($criteria['filter']['refund_reason_id']);
            $allowedFilters[] = AllowedFilter::exact('return_order_refund_reasons.refund_reason_id');
        }

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

        // 退货快递单号
        if (isset($criteria['filter']['return_logistics_freight_no'])) {
            $builder->leftJoin('return_order_logistics', 'return_order_logistics.return_order_id', 'return_orders.id');
        }

        // 商品 SKU 编码
        if (isset($criteria['filter']['return_order_items.sku_code'])) {
            $builder->leftJoin('return_order_items', 'return_order_items.return_order_id', 'return_orders.id');
        }

        // 退货原因ID
        if (isset($criteria['filter']['refund_reason_id'])) {
            $builder->leftJoin('return_order_refund_reasons', 'return_order_refund_reasons.return_order_id', 'return_orders.id');
            $allowedFilters[] = AllowedFilter::exact('return_order_refund_reasons.refund_reason_id');
        }

        $builder->allowedFilters($allowedFilters)
            ->with('returnOrderItems')
            ->with('returnOrderRefundReasons.refundReason')
            ->with('returnOrderLogistics')
            ->with('resendOrder')
            ->with('order.orderItemLogisticsFeatures')
            ->defaultSort('-id');





select
  count(*) as aggregate
from
  `return_orders`
  left join `return_order_items` on `return_order_items`.`return_order_id` = `return_orders`.`id`
where
  (
    LOWER(`return_order_items`.`sku_code`) LIKE '%smileying01%'
  )


PHP / Laravel / Yii2 老项目维护与长期技术支持

如果你的 PHP / Laravel / Yii2 项目已经上线,但遇到原开发离职、Bug 长期无人修复、接口不稳定、性能下降、代码难以接手等问题,可以联系我做一次远程技术排查。

适合以下情况:
✅ 老旧 PHP 系统无人维护
✅ Laravel / Yii2 项目 Bug 修复
✅ 后台管理系统小功能迭代
✅ RESTful API 接口排查
✅ MySQL / Redis / Nginx 性能问题
✅ 长期远程兼职维护

可先从一次小问题开始:
✅ 线上报错排查
✅ 接口异常分析
✅ 慢查询与性能瓶颈定位
✅ 代码结构初步评估
✅ 部署环境与日志检查

如需咨询,请联系我,并注明:PHP 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理