关于Shopware中api.order.search控制器路由定义及自定义扩展控制器的技术咨询
嘿,我来帮你理清楚这个问题~
首先你疑惑的点很关键:原api.order.search路由根本不是用控制器注解定义的,Shopware的这类通用API路由是通过动态代码注册的,不是依赖Symfony的注解路由机制,所以你在原ApiController上找不到对应的@Route注解很正常!
先搞懂原路由的来历
你贴的路由表信息显示这是一个Symfony\Component\Routing\Route实例,它是Shopware框架在启动时,通过专门的路由加载器(比如Shopware\Core\Framework\Api\ApiRouteLoader)动态生成的——框架会遍历所有注册的实体(比如order、product),自动为每个实体生成对应的搜索、详情、更新等通用API路由,然后直接绑定到ApiController的对应方法,通过路由defaults里的entityName参数来区分不同实体。
接下来实现你的自定义路由/api/custom/search/order
最直接的方式是手动注册自定义路由,不用依赖动态生成,步骤如下:
1. 在你的插件里注册路由
如果是Shopware 6插件,在插件目录的src/Resources/config/下创建routes.xml,内容如下:
<?xml version="1.0" encoding="UTF-8" ?> <routes xmlns="http://symfony.com/schema/routing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/routing https://symfony.com/schema/routing/routing-1.0.xsd"> <route id="api.custom.order.search" path="/api/custom/search/order{path}"> <default key="_controller">YourPluginNamespace\Controller\OrderActionController::search</default> <default key="_routeScope">['api']</default> <default key="entityName">order</default> <requirement key="path">(\/[0-9a-f]{32}\/(extensions\/)?[a-zA-Z-]+)*\/?</requirement> <requirement key="version">\d+</requirement> <method>POST</method> </route> </routes>
把YourPluginNamespace换成你实际的插件命名空间就行。
2. 编写你的自定义控制器
继承ApiController后,你可以复用父类的核心逻辑,然后修改响应格式来适配另一个系统:
<?php namespace YourPluginNamespace\Controller; use Shopware\Core\Framework\Api\Controller\ApiController; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\EntitySearchResult; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; /** * @Route(defaults={"_routeScope"={"api"}}) */ class OrderActionController extends ApiController { public function search(Request $request, Context $context, string $entityName, string $path): Response { // 复用父类的搜索逻辑,拿到查询条件和仓库 [$criteria, $repository] = $this->resolveSearch($request, $context, $entityName, $path); // 执行搜索 $result = $context->scope(Context::CRUD_API_SCOPE, function (Context $context) use ($repository, $criteria): EntitySearchResult { return $repository->search($criteria, $context); }); // 这里就是你自定义响应格式的地方! // 不用父类的responseFactory,自己构建适配另一个系统的结构 $customResponseData = [ 'total' => $result->getTotal(), 'orders' => array_map(function($order) { // 按需转换字段,比如只返回需要的字段,或者调整结构 return [ 'id' => $order->getId(), 'orderNumber' => $order->getOrderNumber(), 'totalAmount' => $order->getTotalPrice() // 其他你需要的字段 ]; }, $result->getElements()), // 其他自定义响应字段 ]; return $this->json($customResponseData); } }
3. 验证路由是否生效
运行Shopware的控制台命令:
bin/console debug:router api.custom.order.search
如果能看到路由的详细信息,说明注册成功了,接下来就可以测试POST请求到/api/custom/search/order,就能拿到你自定义格式的响应啦~
补充说明
- 如果你想批量为多个实体生成这类自定义路由,才需要考虑继承Shopware的路由加载器来动态注册,但你只需要order的话,手动注册路由是最简洁的方案。
- 原控制器没有注解是因为路由是直接绑定到方法的,和注解路由机制完全无关,所以不用纠结“动态注解”的问题哦!
备注:内容来源于stack exchange,提问作者Azngeek

