如何在 Symfony 中继承自定义 Doctrine class 注解?
How to inherit custom Doctrine class annotation in Symfony?
我创建了一个自定义 @TimestampAware
注释,可用于在持久化或更新我的实体时自动更新时间戳 属性(请参阅下面的代码)。
直接在实体上使用此注释时 class 一切正常。但是,当在基础 class 上使用注释时,它在继承的子 class 上无法识别。
/**
* @TimestampAware
*/
class SomeEntity { ... } // works fine
/**
* @TimestampAware
*/
class BaseEntity { ... }
class SubEntity extends BaseEntity { ... } // Annotation is not recognized
Doctrine 注释和注释 Reader class 的预期行为是否仅直接在当前 class 上查找注释而不包括其父 class是吗?还是我的实现有问题?
我的注释:
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Reader;
/**
* @Annotation
* @Target("CLASS")
*/
final class TimestampAware { }
注解监听器:
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...
}
}
Annotation Reader 只检查相关的 class,它不读取父 class 的注释。这可以很容易地用这样的代码来检查:
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`
如果您想检查父 classes,您必须自己做。 ReflectionClass
提供了 getParentClass()
方法,您可以用它来检查 class 层次结构。
切线地,我发现 this package 声称扩展注释以便它们可以直接用于继承。还没看好不好用
除了@yivi 的精彩回答之外,我还想分享一下我用来解决问题的代码。也许这可以帮助其他人如何遇到同样的问题:
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...
}
我创建了一个自定义 @TimestampAware
注释,可用于在持久化或更新我的实体时自动更新时间戳 属性(请参阅下面的代码)。
直接在实体上使用此注释时 class 一切正常。但是,当在基础 class 上使用注释时,它在继承的子 class 上无法识别。
/**
* @TimestampAware
*/
class SomeEntity { ... } // works fine
/**
* @TimestampAware
*/
class BaseEntity { ... }
class SubEntity extends BaseEntity { ... } // Annotation is not recognized
Doctrine 注释和注释 Reader class 的预期行为是否仅直接在当前 class 上查找注释而不包括其父 class是吗?还是我的实现有问题?
我的注释:
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Reader;
/**
* @Annotation
* @Target("CLASS")
*/
final class TimestampAware { }
注解监听器:
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...
}
}
Annotation Reader 只检查相关的 class,它不读取父 class 的注释。这可以很容易地用这样的代码来检查:
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`
如果您想检查父 classes,您必须自己做。 ReflectionClass
提供了 getParentClass()
方法,您可以用它来检查 class 层次结构。
切线地,我发现 this package 声称扩展注释以便它们可以直接用于继承。还没看好不好用
除了@yivi 的精彩回答之外,我还想分享一下我用来解决问题的代码。也许这可以帮助其他人如何遇到同样的问题:
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...
}