Doctrine 事件
Doctrine,Symfony 使用的一组 PHP 库,用于操作数据库,提供了一个轻量级的事件系统,用于在应用程序执行期间更新实体。这些事件,称为生命周期事件,允许执行诸如“在此类型的实体持久化之前自动更新 createdAt 属性”之类的任务。
Doctrine 在执行最常见的实体操作(例如 prePersist/postPersist
, preUpdate/postUpdate
)之前/之后触发事件,并在其他常见任务(例如 loadClassMetadata
, onClear
)上触发事件。
有不同的方法来监听这些 Doctrine 事件
- 生命周期回调,它们在实体类上定义为公共方法。它们不能使用服务,因此它们旨在用于与单个实体相关的非常简单的逻辑;
- 实体监听器,它们被定义为具有你想要响应的事件的回调方法的类。它们可以使用服务,但仅针对特定类的实体调用,因此它们非常适合用于与单个实体相关的复杂事件逻辑;
- 生命周期监听器,它们与实体监听器类似,但它们的事件方法是为所有实体调用的,而不仅仅是特定类型的实体。它们非常适合用于在实体之间共享事件逻辑。
每种类型的监听器的性能取决于它应用于多少个实体:生命周期回调比实体监听器更快,而实体监听器又比生命周期监听器更快。
本文仅解释在 Symfony 应用程序内部使用 Doctrine 事件时的基本知识。阅读关于 Doctrine 事件的官方文档,以了解有关它们的全部信息。
另请参阅
本文涵盖了 Doctrine ORM 的监听器。如果你正在使用 ODM for MongoDB,请阅读DoctrineMongoDBBundle 文档。
Doctrine 生命周期回调
生命周期回调被定义为你想要修改的实体内部的公共方法。例如,假设你想要将 createdAt
日期列设置为当前日期,但仅当实体首次持久化时(即插入时)。为此,为 prePersist
Doctrine 事件定义一个回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// src/Entity/Product.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
// When using attributes, don't forget to add #[ORM\HasLifecycleCallbacks]
// to the class of the entity where you define the callback
#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
class Product
{
// ...
#[ORM\PrePersist]
public function setCreatedAtValue(): void
{
$this->createdAt = new \DateTimeImmutable();
}
}
注意
一些生命周期回调接收一个参数,该参数提供对有用信息的访问,例如当前实体管理器(例如,preUpdate
回调接收一个 PreUpdateEventArgs $event
参数)。
Doctrine 实体监听器
实体监听器被定义为 PHP 类,这些类监听单个实体类上的单个 Doctrine 事件。例如,假设你想要在数据库中修改 User
实体时发送一些通知。
首先,定义一个 PHP 类来处理 postUpdate
Doctrine 事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// src/EventListener/UserChangedNotifier.php
namespace App\EventListener;
use App\Entity\User;
use Doctrine\ORM\Event\PostUpdateEventArgs;
class UserChangedNotifier
{
// the entity listener methods receive two arguments:
// the entity instance and the lifecycle event
public function postUpdate(User $user, PostUpdateEventArgs $event): void
{
// ... do something to notify the changes
}
}
然后,将 #[AsEntityListener]
属性添加到类中,以在你的应用程序中将其启用为 Doctrine 实体监听器
1 2 3 4 5 6 7 8 9 10 11 12 13
// src/EventListener/UserChangedNotifier.php
namespace App\EventListener;
// ...
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener;
use Doctrine\ORM\Events;
#[AsEntityListener(event: Events::postUpdate, method: 'postUpdate', entity: User::class)]
class UserChangedNotifier
{
// ...
}
或者,如果你不想使用 PHP 属性,则必须为实体监听器配置一个服务,并使用 doctrine.orm.entity_listener
标签标记它,如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# config/services.yaml
services:
# ...
App\EventListener\UserChangedNotifier:
tags:
-
# these are the options required to define the entity listener
name: 'doctrine.orm.entity_listener'
event: 'postUpdate'
entity: 'App\Entity\User'
# these are other options that you may define if needed
# set the 'lazy' option to TRUE to only instantiate listeners when they are used
# lazy: true
# set the 'entity_manager' option if the listener is not associated to the default manager
# entity_manager: 'custom'
# by default, Symfony looks for a method called after the event (e.g. postUpdate())
# if it doesn't exist, it tries to execute the '__invoke()' method, but you can
# configure a custom method name with the 'method' option
# method: 'checkUserChanges'
Doctrine 生命周期监听器
生命周期监听器被定义为 PHP 类,这些类监听应用程序中所有实体上的单个 Doctrine 事件。例如,假设你想要在数据库中持久化新实体时更新一些搜索索引。为此,为 postPersist
Doctrine 事件定义一个监听器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// src/EventListener/SearchIndexer.php
namespace App\EventListener;
use App\Entity\Product;
use Doctrine\ORM\Event\PostPersistEventArgs;
class SearchIndexer
{
// the listener methods receive an argument which gives you access to
// both the entity object of the event and the entity manager itself
public function postPersist(PostPersistEventArgs $args): void
{
$entity = $args->getObject();
// if this listener only applies to certain entity types,
// add some code to check the entity type as early as possible
if (!$entity instanceof Product) {
return;
}
$entityManager = $args->getObjectManager();
// ... do something with the Product entity
}
}
注意
在之前的 Doctrine 版本中,你需要使用 LifecycleEventArgs
而不是 PostPersistEventArgs
,后者在 Doctrine ORM 2.14 中已弃用。
然后,将 #[AsDoctrineListener]
属性添加到类中,以在你的应用程序中将其启用为 Doctrine 监听器
1 2 3 4 5 6 7 8 9 10 11
// src/EventListener/SearchIndexer.php
namespace App\EventListener;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Events;
#[AsDoctrineListener(event: Events::postPersist, priority: 500, connection: 'default')]
class SearchIndexer
{
// ...
}
或者,如果你不想使用 PHP 属性,则必须通过为其创建一个新服务并使用 doctrine.event_listener
标签标记它,在 Symfony 应用程序中启用监听器
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/EventListener/SearchIndexer.php
namespace App\EventListener;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Event\PostPersistEventArgs;
#[AsDoctrineListener('postPersist'/*, 500, 'default'*/)]
class SearchIndexer
{
public function postPersist(PostPersistEventArgs $event): void
{
// ...
}
}
2.8.0
AsDoctrineListener 属性是在 DoctrineBundle 2.8.0 中引入的。
提示
connection
选项的值也可以是配置参数。