跳到内容

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 选项的值也可以是配置参数

这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可证获得许可。
目录
    版本