跳到主要內容

Doctrine 事件

編輯此頁面

Doctrine 是一組 Symfony 用於操作資料庫的 PHP 函式庫,提供輕量級的事件系統,以便在應用程式執行期間更新實體。這些事件稱為生命週期事件,允許執行諸如「在持久化此類型的實體之前自動更新 createdAt 屬性」之類的任務。

Doctrine 在執行最常見的實體操作(例如 prePersist/postPersistpreUpdate/postUpdate)之前/之後觸發事件,也在其他常見任務(例如 loadClassMetadataonClear)上觸發事件。

有不同的方式來監聽這些 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 實體時傳送一些通知。

首先,定義一個處理 postUpdate Doctrine 事件的 PHP 類別

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 而不是 PostPersistEventArgsLifecycleEventArgs 在 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 屬性,則必須在 Symfony 應用程式中啟用監聽器,方法是為其建立新服務,並使用 doctrine.event_listener 標籤標記它

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 授權條款授權。
目錄
    版本