Doctrine ORM 2.9使用AnnotationDriver和AttributeDriver来解析实体元数据



最近我们将应用程序升级到PHP8。

由于PHP8引入了属性,而doctrine/orm从版本2.9开始就支持这些属性,因此利用此功能来逐步(即而不是所有实体同时更新(将实体元数据更新为属性格式似乎是个好主意。

为了做到这一点,我需要以某种方式注册DoctrineORMMappingDriverAnnotationDriverDoctrineORMMappingDriverAttributeDriver来解析元数据。

棘手的部分是为一组使用注释或属性装饰的实体注册两个解析器。从DoctrineORMConfiguration的角度来看,我所需要的似乎是不可能的。

我是正确的吗(假设这不能合理地实现(,还是可以用一些不太粗鲁的方式来实现?

条令本身并没有提供这种可能性。但是我们可以实现一个自定义映射驱动程序来实现这一点。

实际的实现可能是这样的:

<?php                                                                           
          
namespace UtilsDoctrine;                                                    
          
use DoctrineORMMappingDriverAnnotationDriver;                               
use DoctrineORMMappingDriverAttributeDriver;                                
use DoctrineORMMappingMappingException;                                      
use DoctrinePersistenceMappingClassMetadata;                                 
use DoctrinePersistenceMappingDriverAnnotationDriver as AbstractAnnotationDriver;
          
class HybridMappingDriver extends AbstractAnnotationDriver                      
{                                                                               
public function __construct(                                                
private AnnotationDriver $annotationDriver,                                
private AttributeDriver $attributeDriver,                                  
) {                                                                            
}                                                                              
          
public function loadMetadataForClass($className, ClassMetadata $metadata): void
{                                                                           
try {                                                                      
$this->attributeDriver->loadMetadataForClass($className, $metadata);
return;                                                             
} catch (MappingException $me) {                                        
// Class X is not a valid entity, so try the other driver            
if (!preg_match('/^Class(.)*$/', $me->getMessage())) {// meh           
throw $me;                                                         
}                                                                      
}                                                                       
$this->annotationDriver->loadMetadataForClass($className, $metadata);   
}                                                                            
           
public function isTransient($className): bool                                     
{                                                                           
return $this->attributeDriver->isTransient($className)                     
|| $this->annotationDriver->isTransient($className);                   
}                                                                              
}

简而言之:

  • 驱动程序首先尝试使用AttributeDriver,然后回退到AnnotationDriver,以防被检查的类未被评估为有效实体
  • 在扩展DoctrinePersistenceMappingDriverAnnotationDriver类之后,为了符合DoctrinePersistenceMappingDriverMappingDriver接口,只需要实现2种方法
  • 从示例实现中可以看出,这两种方法都考虑了元数据映射驱动程序
  • 通过解析消息来区分各种类型的MappingExceptions一点也不优雅,但没有更好的属性可以区分;每个映射错误案例都有不同的异常子类型或一些唯一的代码,这将有助于区分映射错误的各个原因

HybridMappingDriver可以连接到EntityManagerFactory中,如下所示:

<?php
namespace AppServicesDoctrine;
use DoctrineORMToolsSetup;
use DoctrineORMEntityManager;
use DoctrineCommonAnnotationsAnnotationRegistry;
use DoctrineCommonProxyAbstractProxyFactory as APF;
use DoctrinePersistenceMappingDriverMappingDriver;
use UtilsDoctrineNullCache;
class EntityManagerFactory
{
public static function create(
array $params,
MappingDriver $mappingDriver,
bool $devMode,
): EntityManager {
AnnotationRegistry::registerLoader('class_exists');
$config = Setup::createConfiguration(
$devMode,
$params['proxy_dir'],
new NullCache(), // must be an instance of DoctrineCommonCacheCache
);
$config->setMetadataDriverImpl($mappingDriver); // <= this is the actual hook-up
if (!$devMode) {
$config->setAutoGenerateProxyClasses(APF::AUTOGENERATE_FILE_NOT_EXISTS);
}
return EntityManager::create($params['database'], $config);
}
}

我不确定是否可以做到,但你可以看看Rector,一次自动升级所有实体。似乎已经对此进行了配置。

https://github.com/rectorphp/rector

https://github.com/rectorphp/rector-doctrine/blob/4bbeb676e9ec8c146a81617f6362be4cafbdf3b3/config/sets/doctrine-orm-29.php

相关内容

  • 没有找到相关文章

最新更新