Shopware 6 服务端API错误捕获:处理数据库重复条目报错
在Shopware 6中捕获数据库重复键错误并优化响应
1. 创建异常订阅器
通过监听kernel.exception事件,捕获数据库抛出的唯一约束违反异常,替换为友好的错误信息和正确的HTTP状态码。
代码示例
<?php namespace YourPluginName\Subscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; class ExceptionSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ ExceptionEvent::class => 'onKernelException', ]; } public function onKernelException(ExceptionEvent $event): void { $exception = $event->getThrowable(); // 匹配唯一约束违反异常 if ($exception instanceof UniqueConstraintViolationException) { $errorMsg = '数据已存在,请更换后重试'; // 针对特定字段的重复错误定制信息 if (str_contains($exception->getMessage(), 'my_entity.name')) { $errorMsg = '该名称已被使用,请更换其他名称'; } // 返回标准409冲突状态码的JSON响应 $response = new JsonResponse([ 'errors' => [ [ 'status' => '409', 'title' => '重复条目', 'detail' => $errorMsg, ] ] ], 409); $event->setResponse($response); } } }
2. 注册订阅器
在插件的配置文件中注册上述订阅器,让Shopware识别并启用它。
services.xml 配置示例
<?xml version="1.0" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="YourPluginName\Subscriber\ExceptionSubscriber"> <tag name="kernel.event_subscriber"/> </service> </services> </container>
services.yaml 配置示例(若使用YAML格式)
services: YourPluginName\Subscriber\ExceptionSubscriber: tags: - { name: kernel.event_subscriber }
3. 可选:业务层提前校验(推荐)
在写入数据库前主动检查重复条目,从根源避免抛出数据库异常,同时返回更规范的校验错误。
代码示例
<?php namespace YourPluginName\Service; use Shopware\Core\Framework\Context; use YourPluginName\Repository\MyEntityRepository; use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException; use Symfony\Component\Validator\ConstraintViolation; class MyEntityService { public function __construct(private readonly MyEntityRepository $repository) { } public function createOrUpdate(array $data, Context $context): void { // 检查目标名称是否已存在 $existingItems = $this->repository->search( (new \Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria()) ->addFilter(new \Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter('name', $data['name'])), $context ); if ($existingItems->count() > 0) { throw new ConstraintViolationException( null, [ new ConstraintViolation( '该名称已被使用,请更换其他名称', '', [], '', 'name', $data['name'] ) ] ); } // 执行写入操作 $this->repository->upsert([$data], $context); } }
关键说明
- 使用409 Conflict状态码是HTTP协议中表示资源冲突的标准做法,比默认的500状态码更准确。
- 若需区分不同字段的重复错误,可通过匹配异常消息中的表名和字段名来定制提示内容。
- 业务层提前校验能减少数据库层面的异常触发,性能更优,同时错误信息更符合Shopware的API响应规范。
内容的提问来源于stack exchange,提问作者rammi22
相关产品推荐
相关产品推荐

