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

1、在 Laravel 9 中,现在已经实现一个列表的 API,其基于 Spatie\QueryBuilder\QueryBuilder 实现从 API 请求轻松构建 Eloquent 查询。但是,现在需要在列表页面实现一个导出 Excel 的功能,计划在异步队列中实现。那么,要想复用之前的构建 Eloquent 查询的代码,好像只能够将 Request 对象传递至队列中?

2、提示报错:Serialization of ‘Closure’ is not allowed。如图1

图1

{
    "status_code": 500,
    "code": 0,
    "message": "Serialization of 'Closure' is not allowed",
    "trace": {
        "line": 158,
        "file": "E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Queue.php",
        "class": "Exception",
        "trace": [
            "#0 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Queue.php(158): serialize(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob))",
            "#1 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Queue.php(127): Illuminate\\Queue\\Queue->createObjectPayload(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob), 'queues:export_q...')",
            "#2 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\RedisQueue.php(212): Illuminate\\Queue\\Queue->createPayloadArray(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob), 'queues:export_q...', '')",
            "#3 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Queue.php(105): Illuminate\\Queue\\RedisQueue->createPayloadArray(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob), 'queues:export_q...', '')",
            "#4 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\RedisQueue.php(136): Illuminate\\Queue\\Queue->createPayload(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob), 'queues:export_q...', '')",
            "#5 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Queue\\Queue.php(57): Illuminate\\Queue\\RedisQueue->push(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob), '', 'export_queue')",
            "#6 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Bus\\Dispatcher.php(246): Illuminate\\Queue\\Queue->pushOn('export_queue', Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob))",
            "#7 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Bus\\Dispatcher.php(229): Illuminate\\Bus\\Dispatcher->pushCommandToQueue(Object(Illuminate\\Queue\\RedisQueue), Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob))",
            "#8 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Bus\\Dispatcher.php(77): Illuminate\\Bus\\Dispatcher->dispatchToQueue(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob))",
            "#9 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Bus\\PendingDispatch.php(193): Illuminate\\Bus\\Dispatcher->dispatch(Object(Modules\\Order\\Jobs\\OrderShippingLogExportJob))",
            "#10 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Bus\\Dispatchable.php(18): Illuminate\\Foundation\\Bus\\PendingDispatch->__destruct()",
            "#11 E:\\wwwroot\\object\\Modules\\Order\\Services\\OrderShippingLogService.php(205): Modules\\Order\\Jobs\\OrderShippingLogExportJob::dispatch(Object(App\\Models\\JobStatus), Array, Object(Illuminate\\Http\\Request))",
            "#12 E:\\wwwroot\\object\\Modules\\Order\\Http\\Controllers\\Api\\OrderShippingLogController.php(46): Modules\\Order\\Services\\OrderShippingLogService->export(Array, Object(Illuminate\\Http\\Request))",
            "#13 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Controller.php(54): Modules\\Order\\Http\\Controllers\\Api\\OrderShippingLogController->export()",
            "#14 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\ControllerDispatcher.php(43): Illuminate\\Routing\\Controller->callAction('export', Array)",
            "#15 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(259): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(Modules\\Order\\Http\\Controllers\\Api\\OrderShippingLogController), 'export')",
            "#16 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Route.php(204): Illuminate\\Routing\\Route->runController()",
            "#17 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(725): Illuminate\\Routing\\Route->run()",
            "#18 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(141): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))",
            "#19 E:\\wwwroot\\object\\vendor\\spatie\\laravel-permission\\src\\Middlewares\\RoleOrPermissionMiddleware.php(26): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#20 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Spatie\\Permission\\Middlewares\\RoleOrPermissionMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure), 'order_transport...')",
            "#21 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Middleware\\SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#22 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#23 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Auth\\Middleware\\Authenticate.php(44): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#24 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Auth\\Middleware\\Authenticate->handle(Object(Illuminate\\Http\\Request), Object(Closure), 'api')",
            "#25 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#26 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(726): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))",
            "#27 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(703): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))",
            "#28 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(667): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))",
            "#29 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Router.php(656): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))",
            "#30 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(190): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))",
            "#31 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))",
            "#32 E:\\wwwroot\\object\\app\\Http\\Middleware\\QueryListenerMiddleware.php(30): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#33 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): App\\Http\\Middleware\\QueryListenerMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#34 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#35 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#36 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#37 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#38 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#39 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#40 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#41 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\HandleCors.php(62): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#42 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Http\\Middleware\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#43 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Http\\Middleware\\TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#44 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))",
            "#45 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Pipeline\\Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))",
            "#46 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(165): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))",
            "#47 E:\\wwwroot\\object\\vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Http\\Kernel.php(134): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))",
            "#48 E:\\wwwroot\\object\\public\\index.php(52): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))",
            "#49 {main}"
        ]
    }
}

3、尝试先将请求对象转换为数组,然后在异步队列中,再重新转换为请求对象。尝试打印 原生的请求对象 与 转换后的请求对象 的所有请求数据。完全相等,符合预期。

 $params = $this->request->all();
 print_r($params);
 $request = new Request($params);
 print_r($request);
 print_r($request->all());
 exit;
Array
(
    [filter] => Array
        (
            [shop_plat_id] => Array
                (
                    [0] => 1
                    [1] => 2
                )

            [shop_id] => Array
                (
                    [0] => 1
                    [1] => 14
                )

            [logistic_channel_id] => Array
                (
                    [0] => 304872
                    [1] => 474241
                )

            [logistic_company_id] => Array
                (
                    [0] => 10336
                    [1] => 10340
                )

            [operated_source] => Array
                (
                    [0] => 1
                    [1] => 2
                )

            [plat_order_no] => Array
                (
                    [0] => GM20240202055938
                    [1] => GM20240131081251
                )

            [logistic_freight_no] => Array
                (
                    [0] => PH900016739XX
                    [1] => PH900890788XX
                )

            [logistic_freight_transfer_no] => Array
                (
                    [0] => PH900016739XX
                    [1] => PH900890788XX
                )

            [logistic_freight_inner_no] => Array
                (
                    [0] => PH900016739XX
                    [1] => PH900890788XX
                )

            [logistic_virtual_number] => Array
                (
                    [0] => GM20240202055938766
                    [1] => GM20240131081251410
                )

            [shipping_type] => Array
                (
                    [0] => 1
                    [1] => 2
                )

            [shipping_status] => Array
                (
                    [0] => 2
                    [1] => 3
                )

            [shipping_at_gmt_start] => 2024-02-02 05:52:31
            [shipping_at_gmt_end] => 2024-02-04 05:52:31
            [operated_at_gmt_start] => 2024-02-02 05:52:31
            [operated_at_gmt_end] => 2024-02-04 05:52:31
        )

    [per_page] => 20
    [page] => 1
)
Illuminate\Http\Request Object
(
    [attributes] => Symfony\Component\HttpFoundation\ParameterBag Object
        (
            [parameters:protected] => Array
                (
                )

        )

    [request] => Symfony\Component\HttpFoundation\InputBag Object
        (
            [parameters:protected] => Array
                (
                )

        )

    [query] => Symfony\Component\HttpFoundation\InputBag Object
        (
            [parameters:protected] => Array
                (
                    [filter] => Array
                        (
                            [shop_plat_id] => Array
                                (
                                    [0] => 1
                                    [1] => 2
                                )

                            [shop_id] => Array
                                (
                                    [0] => 1
                                    [1] => 14
                                )

                            [logistic_channel_id] => Array
                                (
                                    [0] => 304872
                                    [1] => 474241
                                )

                            [logistic_company_id] => Array
                                (
                                    [0] => 10336
                                    [1] => 10340
                                )

                            [operated_source] => Array
                                (
                                    [0] => 1
                                    [1] => 2
                                )

                            [plat_order_no] => Array
                                (
                                    [0] => GM20240202055938
                                    [1] => GM20240131081251
                                )

                            [logistic_freight_no] => Array
                                (
                                    [0] => PH900016739XX
                                    [1] => PH900890788XX
                                )

                            [logistic_freight_transfer_no] => Array
                                (
                                    [0] => PH900016739XX
                                    [1] => PH900890788XX
                                )

                            [logistic_freight_inner_no] => Array
                                (
                                    [0] => PH900016739XX
                                    [1] => PH900890788XX
                                )

                            [logistic_virtual_number] => Array
                                (
                                    [0] => GM20240202055938766
                                    [1] => GM20240131081251410
                                )

                            [shipping_type] => Array
                                (
                                    [0] => 1
                                    [1] => 2
                                )

                            [shipping_status] => Array
                                (
                                    [0] => 2
                                    [1] => 3
                                )

                            [shipping_at_gmt_start] => 2024-02-02 05:52:31
                            [shipping_at_gmt_end] => 2024-02-04 05:52:31
                            [operated_at_gmt_start] => 2024-02-02 05:52:31
                            [operated_at_gmt_end] => 2024-02-04 05:52:31
                        )

                    [per_page] => 20
                    [page] => 1
                )

        )

    [server] => Symfony\Component\HttpFoundation\ServerBag Object
        (
            [parameters:protected] => Array
                (
                )

        )

    [files] => Symfony\Component\HttpFoundation\FileBag Object
        (
            [parameters:protected] => Array
                (
                )

        )

    [cookies] => Symfony\Component\HttpFoundation\InputBag Object
        (
            [parameters:protected] => Array
                (
                )

        )

    [headers] => Symfony\Component\HttpFoundation\HeaderBag Object
        (
            [headers:protected] => Array
                (
                )

            [cacheControl:protected] => Array
                (
                )

        )

    [content:protected] => 
    [languages:protected] => 
    [charsets:protected] => 
    [encodings:protected] => 
    [acceptableContentTypes:protected] => 
    [pathInfo:protected] => 
    [requestUri:protected] => 
    [baseUrl:protected] => 
    [basePath:protected] => 
    [method:protected] => 
    [format:protected] => 
    [session:protected] => 
    [locale:protected] => 
    [defaultLocale:protected] => en
    [preferredFormat:Symfony\Component\HttpFoundation\Request:private] => 
    [isHostValid:Symfony\Component\HttpFoundation\Request:private] => 1
    [isForwardedValid:Symfony\Component\HttpFoundation\Request:private] => 1
    [json:protected] => 
    [convertedFiles:protected] => 
    [userResolver:protected] => 
    [routeResolver:protected] => 
)
Array
(
    [filter] => Array
        (
            [shop_plat_id] => Array
                (
                    [0] => 1
                    [1] => 2
                )

            [shop_id] => Array
                (
                    [0] => 1
                    [1] => 14
                )

            [logistic_channel_id] => Array
                (
                    [0] => 304872
                    [1] => 474241
                )

            [logistic_company_id] => Array
                (
                    [0] => 10336
                    [1] => 10340
                )

            [operated_source] => Array
                (
                    [0] => 1
                    [1] => 2
                )

            [plat_order_no] => Array
                (
                    [0] => GM20240202055938
                    [1] => GM20240131081251
                )

            [logistic_freight_no] => Array
                (
                    [0] => PH900016739XX
                    [1] => PH900890788XX
                )

            [logistic_freight_transfer_no] => Array
                (
                    [0] => PH900016739XX
                    [1] => PH900890788XX
                )

            [logistic_freight_inner_no] => Array
                (
                    [0] => PH900016739XX
                    [1] => PH900890788XX
                )

            [logistic_virtual_number] => Array
                (
                    [0] => GM20240202055938766
                    [1] => GM20240131081251410
                )

            [shipping_type] => Array
                (
                    [0] => 1
                    [1] => 2
                )

            [shipping_status] => Array
                (
                    [0] => 2
                    [1] => 3
                )

            [shipping_at_gmt_start] => 2024-02-02 05:52:31
            [shipping_at_gmt_end] => 2024-02-04 05:52:31
            [operated_at_gmt_start] => 2024-02-02 05:52:31
            [operated_at_gmt_end] => 2024-02-04 05:52:31
        )

    [per_page] => 20
    [page] => 1
)

4、最终实现如下,符合预期。如图2

图2

        $orderShippingLogQueryBuilder = $this->repository->QueryBuilder($params);
        $orderShippingLogQueryBuilder->chunk(100, function ($orderShippingLogs) {
            foreach ($orderShippingLogs as $orderShippingLog) {
                echo $orderShippingLog->id;
            }
        });

        exit;

    /**
     * 查询生成器
     * @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');
    }
永夜

View Comments