简体   繁体   English

如何在Symfony中继承自定义Doctrine类注释?

[英]How to inherit custom Doctrine class annotation in Symfony?

I have created a custom @TimestampAware annotation which can be used to automatically update a timestamp property when persisting or updating my entities (see code below).我创建了一个自定义@TimestampAware注释,可用于在持久化或更新我的实体时自动更新时间戳属性(请参阅下面的代码)。

When using this annotation directly on an entity class everything works fine.当直接在实体类上使用此注释时,一切正常。 However, when using the annotation on a base class, it is not recognized on the inherited sub-classes.但是,在基类上使用注释时,在继承的子类上无法识别。

/**
 * @TimestampAware
 */
class SomeEntity { ... }  // works fine

 /**
 * @TimestampAware
 */
class BaseEntity { ... }

class SubEntity extends BaseEntity { ... } // Annotation is not recognized

Is it the intended behavior of Doctrine annotations and the Annotation Reader class to only look for annotation directly on the current class and no include its parent classes? Doctrine 注释和 Annotation Reader 类的预期行为是直接在当​​前类上查找注释而不包括其父类吗? Or is there something wrong with my implementation?还是我的实现有问题?

My annotation:我的注释:

use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Reader;

/**
 * @Annotation
 * @Target("CLASS")
 */
final class TimestampAware { }

The annotation listener:注释侦听器:

use Doctrine\Common\EventSubscriber;

class TimestampAwareSubscriber implements EventSubscriber {
    protected $reader;
    protected $logger;

    public function __construct(Reader $reader, LoggerInterface $logger) {
        $this->reader = $reader;
        $this->logger = $logger;
    }

    public function getSubscribedEvents() {
        return [
            Events::prePersist,
            Events::preUpdate,
        ];
    }

    public function prePersist(LifecycleEventArgs $args) {
        $this->onPersistOrUpdate($args);
    }    

    public function preUpdate(LifecycleEventArgs $args) {
        $this->onPersistOrUpdate($args);
    }    

    protected function onPersistOrUpdate(LifecycleEventArgs $args) {
        $this->logger->info("Reader: ".get_class($this->reader));
 
        $entity = $args->getEntity();
        $reflection = new \ReflectionClass($entity);
    
        $timestampAware = $this->reader->getClassAnnotation(
            $reflection,
            TimestampAware::class
        );
    
        if (!$timestampAware) {
            return;
        }

        // update timestamp...
    }
}

The Annotation Reader inspects only the relevant class, it does not read the annotations of the parent class. Annotation Reader 只检查相关类,它不读取父类的注释。 This can easily be checked with code like this:这可以使用如下代码轻松检查:

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;

AnnotationRegistry::registerLoader('class_exists');

/**
 * @Annotation
 * @Target("CLASS")
 */
class Annotated {}

/**
 * @Annotated
 **/
class ParentFoo {}

class ChildFoo extends ParentFoo {}

$reader = new AnnotationReader();

$parentAnnotated = $reader->getClassAnnotation(
    new ReflectionClass(ParentFoo::class),
    Annotated::class
);

var_dump($parentAnnotated);
// Outputs `object(Annotated)#10 (0) {}`

$childAnnotated = $reader->getClassAnnotation(
    new ReflectionClass(ChildFoo::class),
    Annotated::class
);

var_dump($childAnnotated);

// outputs `null`

If you want to check parent classes, you'll have to do it yourself.如果你想检查父类,你必须自己做。 ReflectionClass provides the getParentClass() method which you could do to check the class hierarchy. ReflectionClass提供了getParentClass()方法,您可以用它来检查类层次结构。

Tangentially, I've found this package that claims to extend annotations so that they are usable with inheritance directly.顺便说一句,我发现这个包声称可以扩展注释,以便它们可以直接与继承一起使用。 Haven't checked if it's any good.没看好不好

In addition to the great answer by @yivi I would like to share the code I used to solve the problem.除了@yivi 的精彩回答之外,我还想分享我用来解决问题的代码。 Maybe this helps others how encounter the same problem:也许这有助于其他人如何遇到同样的问题:

protected function onPersistOrUpdate(LifecycleEventArgs $args) {
    $this->logger->info("Reader: ".get_class($this->reader));

    $entity = $args->getEntity();
    $reflection = new \ReflectionClass($entity);

    $timestampAware = $this->reader->getClassAnnotation(
        $reflection,
        TimestampAware::class
    );
    
    while (!$timestampAware && $reflection = $reflection->getParentClass()) {
        $timestampAware = $this->reader->getClassAnnotation(
            $reflection,
            TimestampLogAware::class
        );
    }

    if (!$timestampAware) {
        return;
    }

    // update timestamp...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM