如何配置Symfony Validator忽略@OA注解?
Symfony Validator与OpenAPI @OA注解冲突的解决方法
问题描述
同时使用Swagger的OpenAPI @OA注解和Symfony Validator注解时出现冲突,运行代码后抛出注解未导入的错误,但实际已经添加了正确的use语句。
示例代码
use Symfony\Component\Validator\Constraints as Assert; use OpenApi\Annotations as OA; /** * @OA\Schema() */ class CustomerPostBody { /** * @Assert\NotBlank */ public string $id; }
运行错误信息
PHP Fatal error: Uncaught Doctrine\Common\Annotations\AnnotationException: [Semantical Error] The annotation "@Symfony\Component\Validator\Constraints\NotBlank" in property app\Customer::$id was never imported. Did you maybe forget to add a "use" statement for this annotation?
当前环境与尝试
- PHP 7.4(无法更改),Symfony Validator 5.x版本
- 未使用YAML配置
- 尝试添加以下代码仅对
@OA生效,对@OA\Schema无效:
AnnotationReader::addGlobalIgnoredName('OpenApi\Annotations');
完整堆栈跟踪
PHP Fatal error: Uncaught Doctrine\Common\Annotations\AnnotationException: [Semantical Error] The annotation "@Symfony\Component\Validator\Constraints\NotBlank" in property app\Customer::$customer_id was never imported. Did you maybe forget to add a "use" statement for this annotation? in app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php:40 Stack trace: #0 app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php(804): Doctrine\Common\Annotations\AnnotationException::semanticalError() #1 app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php(724): Doctrine\Common\Annotations\DocParser->Annotation() #2 app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php(377): Doctrine\Common\Annotations\DocParser->Annotations() #3 app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php(179): Doctrine\Common\Annotations\DocParser->parse() #4 app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php(155): Doctrine\Common\Annotations\AnnotationReader->getPropertyAnnotations() #5 app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/PsrCachedReader.php(88): Doctrine\Common\Annotations\PsrCachedReader->fetchFromCache() #6 app/vendor/symfony/validator/Mapping/Loader/AnnotationLoader.php(127): Doctrine\Common\Annotations\PsrCachedReader->getPropertyAnnotations() #7 app/vendor/symfony/validator/Mapping/Loader/AnnotationLoader.php(60): Symfony\Component\Validator\Mapping\Loader\ AnnotationLoader->getAnnotations() #8 app/vendor/symfony/validator/Mapping/Factory/LazyLoadingMetadataFactory.php(101): Symfony\Component\Validator\Map ping\Loader\AnnotationLoader->loadClassMetadata() #9 app/vendor/symfony/validator/Validator/RecursiveContextualValidator.php(306): Symfony\Component\Validator\Mapping \Factory\LazyLoadingMetadataFactory->getMetadataFor() #10 app/vendor/symfony/validator/Validator/RecursiveContextualValidator.php(133): Symfony\Component\Validator\Validator\RecursiveContextualValidator->validateObject() #11 app/vendor/symfony/validator/Validator/RecursiveValidator.php(93): Symfony\Component\Validator\Validator\RecursiveContextualValidator->validate() #12 app/testvalidator.php(36): Symfony\Component\Validator\Validator\RecursiveValidator->validate() #13 {main} thrown in app/vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationException.php on line 40
解决方案
冲突根源是Doctrine注解解析器会将@OA\Schema这类子注解当作待处理注解,干扰了Symfony Validator对@Assert注解的解析。以下是三种可行的解决方式:
方法1:逐个添加全局忽略项
直接忽略OA命名空间下的所有子注解:
use Doctrine\Common\Annotations\AnnotationReader; // 忽略所有OA相关注解 AnnotationReader::addGlobalIgnoredName('OA'); AnnotationReader::addGlobalIgnoredName('OA\Schema'); AnnotationReader::addGlobalIgnoredName('OA\Property'); // 按需添加其他你用到的OA子注解,比如OA\Get、OA\Post等
方法2:自定义注解过滤器(彻底解决)
创建只允许加载Assert注解的过滤器,避免解析所有非Validator注解:
use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\Filter\AnnotationFilter; use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; use Symfony\Component\Validator\Validation; // 创建带过滤规则的注解阅读器 $reader = new AnnotationReader(); $reader->addFilter(new class implements AnnotationFilter { public function shouldLoadAnnotation($annotationName): bool { // 仅加载Symfony Validator的Assert注解 return str_starts_with($annotationName, 'Symfony\Component\Validator\Constraints\\'); } }); // 使用自定义阅读器初始化Validator $validator = Validation::createValidatorBuilder() ->setAnnotationLoader(new AnnotationLoader($reader)) ->getValidator();
方法3:类级别添加忽略注解
在单个类上添加@IgnoreAnnotation("OA"),让Doctrine忽略所有以@OA开头的注解:
use Symfony\Component\Validator\Constraints as Assert; use OpenApi\Annotations as OA; use Doctrine\Common\Annotations\IgnoreAnnotation; /** * @IgnoreAnnotation("OA") * @OA\Schema() */ class CustomerPostBody { /** * @Assert\NotBlank */ public string $id; }
该方法适合少量类的场景,批量处理推荐方法1或2。
内容的提问来源于stack exchange,提问作者Olle Härstedt
相关产品推荐
相关产品推荐

