如何将视图加入Doctrine异常处理?解决TRUNCATE视图执行错误
问题背景
运行composer test:prepare时触发Doctrine执行SQL语句TRUNCATE v_my_views CASCADE,但v_my_views是PostgreSQL视图而非表,抛出错误:
SQLSTATE[42809]: Wrong object type: 7 ERROR: "v_my_views" is not a table
同时需要在执行console doctrine:fixtures:load -n --group=main --em=default --purge-with-truncate时,让Doctrine跳过对该视图的截断操作。
解决步骤
1. 标记视图对应的实体为只读/不可操作
明确告知Doctrine该实体对应视图而非可写表,避免自动生成截断逻辑:
如果使用注解配置实体,在对应实体类头部添加如下注解:
/** * @ORM\Entity(readOnly=true) * @ORM\Table(name="v_my_views") * @ORM\ReadOnly() */ class VMyViews { // 实体字段定义... }
@ReadOnly()注解会让Doctrine将该实体视为只读,默认不会对其执行写入、截断等操作。
2. 自定义Truncate Purger过滤视图实体
若--purge-with-truncate模式下默认Purger仍尝试截断视图,需自定义Purger跳过目标实体:
步骤2.1 创建自定义Purger类
继承Doctrine默认的ORMPurger,重写purgeTable方法过滤排除视图实体:
<?php namespace App\Doctrine; use Doctrine\Common\DataFixtures\Purger\ORMPurger; use Doctrine\ORM\Mapping\ClassMetadata; class CustomTruncatePurger extends ORMPurger { // 配置需要跳过的视图实体类 private array $excludedEntities = [ \App\Entity\VMyViews::class, ]; protected function purgeTable(ClassMetadata $metadata): void { // 检查当前实体是否在排除列表,是则跳过截断 if (in_array($metadata->getName(), $this->excludedEntities)) { return; } parent::purgeTable($metadata); } }
步骤2.2 注册自定义Purger服务(以Symfony为例)
在config/services.yaml中注册自定义Purger,添加Doctrine Fixtures Purger标签:
services: App\Doctrine\CustomTruncatePurger: arguments: - '@doctrine.orm.default_entity_manager' tags: - { name: doctrine.fixtures.purger, alias: custom_truncate }
步骤2.3 使用自定义Purger执行Fixtures加载
执行命令时通过--purger参数指定使用自定义Purger:
console doctrine:fixtures:load -n --group=main --em=default --purger=custom_truncate
3. 适配composer test:prepare命令
若composer test:prepare内部调用了Doctrine的purge逻辑,修改composer.json中的test:prepare脚本,将Fixtures加载命令替换为使用自定义Purger的版本即可解决问题。
内容的提问来源于stack exchange,提问作者Bingo

