Symfony学说:向现有阅读器添加新的新注释名称空间

时间:2018-07-14 16:58:22

标签: php symfony doctrine-orm annotations doctrine

我已经实现了自己的Doctrine\Common\EventSubscriber,该订阅了“ onFlush”事件,并将EntityChangeSet与类属性的硬编码列表(例如User->NameEvent->Date)进行比较并记录了更改如有必要。

由于其他类的属性名称可能会发生变化,所以我宁愿使用定制的@Loggable来注释这些属性。

我建立了注释类“ Loggable”,将use MyNamespace\Annotations\Loggable;添加到UserEvent类中,并在EventSubscriber中有一个创建Doctrine\Common\Annotations\AnnotationReader并使用的方法其getPropertyAnnotation($property, 'Loggable')来检查是否为非空值。

现在有问题

正如人们可能会(或不会)期望的那样,这个特定的读者会抛出

[Semantical Error] The annotation "@Id" in property MyNamespace\Entities\User::$id was never imported.

并且不知道我的EntityManager中的读者知道的任何其他ORM注释。

我实际上是否必须将use Doctrine\ORM\Mapping as ORM;添加到每个实体类并为每个 ORM注释加上ORM\ just em>来取悦这个新创建的阅读器,或者是否有办法在我的EntityManager中重用阅读器(如果我理解正确,默认情况下为Doctrine\Common\Annotations\SimpleAnnotationReader?)

我进行了研究,并阅读了与教义和注释有关的大多数答案,但似乎缺少一些概念上的理解。也许有人可以指出我正确的方向?

2 个答案:

答案 0 :(得分:1)

基本上, AnnotationReader 类使用 getClassAnnotations getClassAnnotation (实际上使用 getClassAnnotations )。

>

getClassAnnotations:

public function getClassAnnotations(ReflectionClass $class)
{
    $this->parser->setTarget(Target::TARGET_CLASS);
    $this->parser->setImports($this->getClassImports($class));
    $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class));
    $this->parser->setIgnoredAnnotationNamespaces(self::$globalIgnoredNamespaces);

    return $this->parser->parse($class->getDocComment(), 'class ' . $class->getName());
}

getClassAnnotation:

public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
    $annotations = $this->getClassAnnotations($class);

    foreach ($annotations as $annotation) {
        if ($annotation instanceof $annotationName) {
            return $annotation;
        }
    }

    return null;
}

只需看一下这一行:

$this->parser->setImports($this->getClassImports($class));

注释阅读器收集 use 语句,以检测您使用的任何其他注释。 所以,关于你的问题

  

我真的必须添加使用Doctrine \ ORM \ Mapping作为ORM吗?到每个Entity类,并在每个ORM注释前加上ORM \ [...]?

我应该回答:是的,你愿意。

答案 1 :(得分:0)

由于@Frank Gamess的解释,我终于设法遍历了Doctrine代码库的丛林,找到了一个混乱但有效的解决方案,该解决方案并不涉及每个文件的显式命名空间。

我在创建EntityManager时没有使用更简单的Setup::createAnnotationMetadataConfiguration(),而是更加冗长,自己执行了配置的大多数步骤:

// preloading all of Doctrine's Annotation classes
$rc = new \ReflectionClass(Configuration::class);
$dir = dirname($rc->getFileName());

AnnotationRegistry::registerFile($dir . '/Mapping/Driver/DoctrineAnnotations.php');

// preloading my own classes
$dir = $dir ?? self::BASE_DIR . '/src/Annotations';  // BASE_DIR is my project root directory
// CustomAnnotations.php is built the same way as DoctrineAnnotations.php;
AnnotationRegistry::registerFile($dir . '/CustomAnnotations.php');

$reader = new SimpleAnnotationReader();
$reader->addNamespace('Doctrine\ORM\Mapping');
$reader->addNamespace('MyProject\Annotations');

$mapping_driver = new AnnotationDriver($reader, [self::BASE_DIR . '/src/Entities']);

$config = Setup::createConfiguration();
$config->setMetadataDriverImpl($mapping_driver);
$config->setAutoGenerateProxyClasses(true);

$EM = EntityManager::create($db_params, $config, new EventManager());

// adding the objects to my ORM-objects for later use
$this->annotation_reader = $reader;
$this->EM = $EM;

现在,我可以使用没有任何使用声明或FQCN的注释。也许不干净,但重复性较差。

通过这种方法,我也许可以继续处理更紧急的事情,但是如果有人可以指出重构的可能性,我将不知所措!