9. Events

Doctrine ORM features a lightweight event system that is part of the Common package. Doctrine uses it to dispatch system events, mainly lifecycle events. You can also use it for your own custom events.

Doctrine ORM は、Common パッケージの一部である軽量のイベント システムを備えています。 Doctrine はこれを使用して、システム イベント、主にライフサイクル イベントをディスパッチします。独自のカスタム イベントにも使用できます。

9.1. The Event System

The event system is controlled by the EventManager. It is the central point of Doctrine’s event listener system. Listeners are registered on the manager and events are dispatched through the manager.

イベント システムは、EventManager によって制御されます。 Doctrine のイベントリスナーシステムの中心点です。リスナーはマネージャーに登録され、イベントはマネージャーを介してディスパッチされます。

<?php
$evm = new EventManager();

Now we can add some event listeners to the $evm. Let’s create a TestEvent class to play around with.

これで、いくつかのイベント リスナーを $evm に追加できます。試してみる TestEvent クラスを作成しましょう。

<?php
class TestEvent
{
    const preFoo = 'preFoo';
    const postFoo = 'postFoo';

    private $_evm;

    public $preFooInvoked = false;
    public $postFooInvoked = false;

    public function __construct($evm)
    {
        $evm->addEventListener(array(self::preFoo, self::postFoo), $this);
    }

    public function preFoo(EventArgs $e)
    {
        $this->preFooInvoked = true;
    }

    public function postFoo(EventArgs $e)
    {
        $this->postFooInvoked = true;
    }
}

// Create a new instance
$test = new TestEvent($evm);

Events can be dispatched by using the dispatchEvent() method.

イベントは、dispatchEvent() メソッドを使用してディスパッチできます。

<?php
$evm->dispatchEvent(TestEvent::preFoo);
$evm->dispatchEvent(TestEvent::postFoo);

You can easily remove a listener with the removeEventListener() method.

removeEventListener() メソッドを使用すると、リスナーを簡単に削除できます。

<?php
$evm->removeEventListener(array(self::preFoo, self::postFoo), $this);

The Doctrine ORM event system also has a simple concept of event subscribers. We can define a simple TestEventSubscriber class which implements the \Doctrine\Common\EventSubscriber interface and implements a getSubscribedEvents() method which returns an array of events it should be subscribed to.

Doctrine ORM イベント システムには、eventsubscriber という単純な概念もあります。 \Doctrine\Common\EventSubscriber インターフェイスを実装し、サブスクライブするイベントの配列を返す getSubscribeEvents() メソッドを実装する単純な TestEventSubscriber クラスを定義できます。

<?php
use Doctrine\Common\EventSubscriber;

class TestEventSubscriber implements EventSubscriber
{
    public $preFooInvoked = false;

    public function preFoo()
    {
        $this->preFooInvoked = true;
    }

    public function getSubscribedEvents()
    {
        return array(TestEvent::preFoo);
    }
}

$eventSubscriber = new TestEventSubscriber();
$evm->addEventSubscriber($eventSubscriber);

Note

ノート

The array to return in the getSubscribedEvents method is a simple array with the values being the event names. The subscriber must have a method that is named exactly like the event.

getSubscribeEvents メソッドで返される配列は、値がイベント名である単純な配列です。サブスクライバーには、イベントとまったく同じ名前のメソッドが必要です。

Now when you dispatch an event, any event subscribers will be notified for that event.

これで、イベントをディスパッチすると、すべてのイベント サブスクライバーにそのイベントが通知されます。

<?php
$evm->dispatchEvent(TestEvent::preFoo);

Now you can test the $eventSubscriber instance to see if the preFoo() method was invoked.

これで、$eventSubscriber インスタンスをテストして、preFoo() メソッドが呼び出されたかどうかを確認できます。

<?php
if ($eventSubscriber->preFooInvoked) {
    echo 'pre foo invoked!';
}

9.1.1. Registering Event Handlers

There are two ways to set up an event handler:

イベント ハンドラーを設定するには、次の 2 つの方法があります。

  • For all events you can create a Lifecycle Event Listener or Subscriber class and register

    すべてのイベントについて、Lifecycle Event Listener または Subscriber クラスを作成して登録できます

it by calling $eventManager->addEventListener() or eventManager->addEventSubscriber(), see Listening and subscribing to Lifecycle Events * For some events (see table below), you can create a Lifecycle Callback method in the entity, see Lifecycle Callbacks.

$eventManager->addEventListener() または eventManager->addEventSubscriber() を呼び出して、ライフサイクル イベントのリッスンとサブスクライブを参照してください* 一部のイベント (下の表を参照) については、エンティティでライフサイクル コールバック メソッドを作成できます。ライフサイクル コールバックを参照してください。

9.2. Events Overview

Event

イベント

Dispatched by

発送元

Lifecycle Callback

LifecycleCallback

Passed Argument

渡された引数

preRemove

preRemove

$em->remove()

$em->remove()

Yes

はい

PreRemoveEventArgs

PreRemoveEventArgs

postRemove

ポスト削除

$em->flush()

$em->flush()

Yes

はい

PostRemoveEventArgs

PostRemoveEventArgs

prePersist

prePersist

$em->persist() on initial persist

$em->persist() on 初期持続

Yes

はい

PrePersistEventArgs

PrePersistEventArgs

postPersist

postPersist

$em->flush()

$em->flush()

Yes

はい

PostPersistEventArgs

PostPersistEventArgs

preUpdate

preUpdate

$em->flush()

$em->flush()

Yes

はい

PreUpdateEventArgs

PreUpdateEventArgs

postUpdate

postUpdate

$em->flush()

$em->flush()

Yes

はい

PostUpdateEventArgs

PostUpdateEventArgs

postLoad

postLoad

Loading from database

データベースから読み込み中

Yes

はい

PostLoadEventArgs

PostLoadEventArgs

loadClassMetadata

loadClassMetadata

Loading of mapping metadata

マッピングメタデータの読み込み

No

いいえ

LoadClassMetadataEventArgs

LoadClassMetadataEventArgs

onClassMetadataNotFound

onClassMetadataNotFound

MappingException

マッピング例外

No

いいえ

OnClassMetadataNotFoundEventArgs

OnClassMetadataNotFoundEventArgs

preFlush

プレフラッシュ

$em->flush()

$em->flush()

Yes

はい

PreFlushEventArgs

PreFlushEventArgs

onFlush

オンフラッシュ

$em->flush()

$em->flush()

No

いいえ

OnFlushEventArgs

OnFlushEventArgs

postFlush

ポストフラッシュ

$em->flush()

$em->flush()

No

いいえ

PostFlushEventArgs

PostFlushEventArgs

onClear

onClear

$em->clear()

$em->clear()

No

いいえ

OnClearEventArgs

OnClearEventArgs

9.2.1. Naming convention

Events being used with the Doctrine ORM EventManager are best named with camelcase and the value of the corresponding constant should be the name of the constant itself, even with spelling. This has several reasons:

Doctrine ORM EventManager で使用されるイベントは、キャメルケースで名前を付けるのが最適であり、対応する定数の値は、つづりがあっても、定数自体の名前にする必要があります。これにはいくつかの理由があります。

  • It is easy to read.

    読みやすいです。

  • Simplicity.

    シンプルさ。

  • Each method within an EventSubscriber is named after the corresponding constant’s value. If the constant’s name and value differ it contradicts the intention of using the constant and makes your code harder to maintain.

    EventSubscriber 内の各メソッドは、対応する定数の値にちなんで名付けられています。定数の名前と値が異なる場合、定数を使用する意図に反し、コードの保守が難しくなります。

An example for a correct notation can be found in the example TestEvent above.

正しい表記の例は、上記の exampleTestEvent にあります。

9.3. Lifecycle Callbacks

Lifecycle Callbacks are defined on an entity class. They allow you to trigger callbacks whenever an instance of that entity class experiences a relevant lifecycle event. More than one callback can be defined for each lifecycle event. Lifecycle Callbacks are best used for simple operations specific to a particular entity class’s lifecycle.

ライフサイクル コールバックは、エンティティ クラスで定義されます。そのエンティティ クラスのインスタンスが関連するライフサイクル イベントを経験するたびに、コールバックをトリガーすることができます。各ライフサイクル イベントに対して複数のコールバックを定義できます。ライフサイクル コールバックは、特定のエンティティ クラスのライフサイクルに固有の単純な操作に最適です。

Note

ノート

Lifecycle Callbacks are not supported for Embeddables.

Embeddables ではライフサイクル コールバックはサポートされていません。

9.4. Lifecycle Callbacks Event Argument

The triggered event is also given to the lifecycle-callback.

トリガーされたイベントは、lifecycle-callback にも渡されます。

With the additional argument you have access to the EntityManager and UnitOfWork APIs inside these callback methods.

追加の引数を使用すると、これらのコールバック メソッド内の EntityManager および UnitOfWork API にアクセスできます。

<?php
// ...

class User
{
    public function preUpdate(PreUpdateEventArgs $event)
    {
        if ($event->hasChangedField('username')) {
            // Do something when the username is changed.
        }
    }
}

9.5. Listening and subscribing to Lifecycle Events

Lifecycle event listeners are much more powerful than the simple lifecycle callbacks that are defined on the entity classes. They sit at a level above the entities and allow you to implement re-usable behaviors across different entity classes.

ライフサイクル イベント リスナーは、エンティティ クラスで定義されている単純なライフサイクル コールバックよりもはるかに強力です。それらはエンティティの上位レベルにあり、さまざまなエンティティ クラス間で再利用可能な動作を実装できます。

Note that they require much more detailed knowledge about the inner workings of the EntityManager and UnitOfWork classes. Please read the Implementing Event Listeners section carefully if you are trying to write your own listener.

EntityManager および UnitOfWork クラスの内部構造に関するより詳細な知識が必要であることに注意してください。独自のリスナーを作成しようとしている場合は、「イベント リスナーの実装」セクションを注意深く読んでください。

For event subscribers, there are no surprises. They declare the lifecycle events in their getSubscribedEvents method and provide public methods that expect the relevant arguments.

イベントのサブスクライバーにとって、驚きはありません。 getSubscribeEvents メソッドでライフサイクル イベントを宣言し、関連する引数を期待するパブリック メソッドを提供します。

A lifecycle event listener looks like the following:

ライフサイクル イベント リスナーは次のようになります。

<?php
use Doctrine\ORM\Event\PreUpdateEventArgs;

class MyEventListener
{
    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getObject();
        $entityManager = $args->getObjectManager();

        // perhaps you only want to act on some "Product" entity
        if ($entity instanceof Product) {
            // do something with the Product
        }
    }
}

A lifecycle event subscriber may look like this:

ライフサイクル イベント サブスクライバーは次のようになります。

<?php
use Doctrine\ORM\Event\PostUpdateEventArgs;
use Doctrine\ORM\Events;
use Doctrine\EventSubscriber;

class MyEventSubscriber implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(
            Events::postUpdate,
        );
    }

    public function postUpdate(PostUpdateEventArgs $args)
    {
        $entity = $args->getObject();
        $entityManager = $args->getObjectManager();

        // perhaps you only want to act on some "Product" entity
        if ($entity instanceof Product) {
            // do something with the Product
        }
    }

Note

ノート

Lifecycle events are triggered for all entities. It is the responsibility of the listeners and subscribers to check if the entity is of a type it wants to handle.

ライフサイクル イベントは、すべてのエンティティに対してトリガーされます。エンティティが処理したいタイプであるかどうかを確認するのは、リスナーとサブスクライバーの責任です。

To register an event listener or subscriber, you have to hook it into the EventManager that is passed to the EntityManager factory:

イベント リスナーまたはサブスクライバーを登録するには、EntityManager ファクトリに渡される theEventManager にフックする必要があります。

<?php
use Doctrine\ORM\Events;

$eventManager = new EventManager();
$eventManager->addEventListener([Events::preUpdate], new MyEventListener());
$eventManager->addEventSubscriber(new MyEventSubscriber());

$entityManager = new EntityManager($connection, $config, $eventManager);

You can also retrieve the event manager instance after the EntityManager was created:

EntityManager が作成された後、イベント マネージャー インスタンスを取得することもできます。

<?php
use Doctrine\ORM\Events;

$entityManager->getEventManager()->addEventListener([Events::preUpdate], new MyEventListener());
$entityManager->getEventManager()->addEventSubscriber(new MyEventSubscriber());

9.6. Implementing Event Listeners

This section explains what is and what is not allowed during specific lifecycle events of the UnitOfWork class. Although you get passed the EntityManager instance in all of these events, you have to follow these restrictions very carefully since operations in the wrong event may produce lots of different errors, such as inconsistent data and lost updates/persists/removes.

このセクションでは、UnitOfWork クラスの特定のライフサイクル イベント中に許可されるものと許可されないものについて説明します。これらすべてのイベントで EntityManager インスタンスが渡されますが、間違ったイベントで操作を行うと、一貫性のないデータや失われた更新/永続化/削除など、さまざまなエラーが発生する可能性があるため、これらの制限には非常に注意して従う必要があります。

For the described events that are also lifecycle callback events the restrictions apply as well, with the additional restriction that (prior to version 2.4) you do not have access to the EntityManager or UnitOfWork APIs inside these events.

ライフサイクル コールバック イベントでもある前述のイベントについても制限が適用され、(バージョン 2.4 より前のバージョンでは) これらのイベント内の EntityManager または UnitOfWork API にアクセスできないという追加の制限があります。

9.6.1. prePersist

There are two ways for the prePersist event to be triggered:

prePersist イベントがトリガーされる方法は 2 つあります。

  • One is obviously when you call EntityManager::persist(). The

    1 つは明らかに EntityManager::persist() を呼び出すときです。の

event is also called for all cascaded associations. - The other is inside the flush() method when changes to associations are computed and this association is marked as cascade: persist. Any new entity found during this operation is also persisted and prePersist called on it. This is called persistence by reachability.

このイベントは、すべてのカスケードされた関連付けに対しても呼び出されます。- もう 1 つは、関連付けへの変更が計算され、この関連付けがカスケード: 永続化としてマークされるときに、flush() メソッド内にあります。この操作中に見つかった新しいエンティティも永続化され、prePersist が呼び出されます。これは、到達可能性による持続性と呼ばれます。

In both cases you get passed a PrePersistEventArgs instance which has access to the entity and the entity manager.

どちらの場合も、エンティティとエンティティ マネージャにアクセスできる PrePersistEventArgs インスタンスが渡されます。

This event is only triggered on initial persist of an entity (i.e. it does not trigger on future updates).

このイベントは、エンティティの最初の永続化でのみトリガーされます (つまり、将来の更新ではトリガーされません)。

The following restrictions apply to prePersist:

以下の制限が prePersist に適用されます。

  • If you are using a PrePersist Identity Generator such as sequences the ID value will NOT be available within any PrePersist events.

    シーケンスなどの PrePersist Identity Generator を使用している場合、ID 値は PrePersist イベント内では使用できません。

  • Doctrine will not recognize changes made to relations in a prePersist event. This includes modifications to collections such as additions, removals or replacement.

    Doctrine は prePersistevent でリレーションに加えられた変更を認識しません。これには、追加、削除、置換などのコレクションへの変更が含まれます。

9.6.2. preRemove

The preRemove event is called on every entity immediately when it is passed to the EntityManager::remove() method. It is cascaded for all associations that are marked as cascade: remove

preRemove イベントは、EntityManager::remove() メソッドに渡されるとすぐにすべてのエンティティで呼び出されます。カスケードとしてマークされているすべての関連付けに対してカスケードされます: 削除

It is not called for a DQL DELETE statement.

DQL DELETE ステートメントでは呼び出されません。

There are no restrictions to what methods can be called inside the preRemove event, except when the remove method itself was called during a flush operation.

フラッシュ操作中に remove メソッド自体が呼び出された場合を除き、preRemove イベント内で呼び出すことができるメソッドに制限はありません。

9.6.3. preFlush

preFlush is called inside EntityManager::flush() before anything else. EntityManager::flush() must not be called inside its listeners, since it would fire the preFlush event again, which would result in an infinite loop.

preFlush は、EntityManager::flush() 内で他の何よりも先に呼び出されます。 EntityManager::flush() をそのリスナー内で呼び出してはなりません。これは、preFlush イベントが再び発生し、無限ループが発生するためです。

<?php
use Doctrine\ORM\Event\PreFlushEventArgs;

class PreFlushExampleListener
{
    public function preFlush(PreFlushEventArgs $args)
    {
        // ...
    }
}

9.6.4. onFlush

onFlush is a very powerful event. It is called inside EntityManager::flush() after the changes to all the managed entities and their associations have been computed. This means, the onFlush event has access to the sets of:

onFlush は非常に強力なイベントです。すべての管理対象エンティティとその関連付けへの変更が計算された後、insideEntityManager::flush() が呼び出されます。これは、onFlush イベントが次のセットにアクセスできることを意味します。

  • Entities scheduled for insert

    挿入予定のエンティティ

  • Entities scheduled for update

    更新予定のエンティティ

  • Entities scheduled for removal

    削除予定のエンティティ

  • Collections scheduled for update

    更新予定のコレクション

  • Collections scheduled for removal

    削除予定のコレクション

To make use of the onFlush event you have to be familiar with the internal UnitOfWork API, which grants you access to the previously mentioned sets. See this example:

onFlush イベントを利用するには、前述のセットへのアクセスを許可する内部 UnitOfWork API に精通している必要があります。次の例を参照してください。

<?php
class FlushExampleListener
{
    public function onFlush(OnFlushEventArgs $eventArgs)
    {
        $em = $eventArgs->getObjectManager();
        $uow = $em->getUnitOfWork();

        foreach ($uow->getScheduledEntityInsertions() as $entity) {

        }

        foreach ($uow->getScheduledEntityUpdates() as $entity) {

        }

        foreach ($uow->getScheduledEntityDeletions() as $entity) {

        }

        foreach ($uow->getScheduledCollectionDeletions() as $col) {

        }

        foreach ($uow->getScheduledCollectionUpdates() as $col) {

        }
    }
}

The following restrictions apply to the onFlush event:

onFlush イベントには次の制限が適用されます。

  • If you create and persist a new entity in onFlush, then calling EntityManager::persist() is not enough. You have to execute an additional call to $unitOfWork->computeChangeSet($classMetadata, $entity).

    onFlush で新しいエンティティを作成して永続化する場合、EntityManager::persist() を呼び出すだけでは不十分です。$unitOfWork->computeChangeSet($classMetadata, $entity) への追加の呼び出しを実行する必要があります。

  • Changing primitive fields or associations requires you to explicitly trigger a re-computation of the changeset of the affected entity. This can be done by calling $unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity).

    プリミティブ フィールドまたは関連付けを変更するには、影響を受けるエンティティの変更セットの再計算を明示的にトリガーする必要があります。これは、$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity) を呼び出すことで実行できます。

9.6.5. postFlush

postFlush is called at the end of EntityManager::flush(). EntityManager::flush() can NOT be called safely inside its listeners. This event is not a lifecycle callback.

postFlush は EntityManager::flush() の最後に呼び出されます。EntityManager::flush() はリスナー内で安全に呼び出すことはできません。このイベントはライフサイクル コールバックではありません。

<?php
use Doctrine\ORM\Event\PostFlushEventArgs;

class PostFlushExampleListener
{
    public function postFlush(PostFlushEventArgs $args)
    {
        // ...
    }
}

9.6.6. preUpdate

PreUpdate is called inside the EntityManager::flush() method, right before an SQL UPDATE statement. This event is not triggered when the computed changeset is empty, nor for a DQL

PreUpdate は、EntityManager::flush() メソッド内で、SQL UPDATE ステートメントの直前に呼び出されます。このイベントは、計算された変更セットが空の場合や、DQL の場合にはトリガーされません。

UPDATE statement.

UPDATE ステートメント。

Changes to associations of the updated entity are never allowed in this event, since Doctrine cannot guarantee to correctly handle referential integrity at this point of the flush operation. This event has a powerful feature however, it is executed with a PreUpdateEventArgs instance, which contains a reference to the computed change-set of this entity.

Doctrine はフラッシュ操作のこの時点で参照整合性を正しく処理することを保証できないため、更新されたエンティティの関連付けへの変更はこのイベントでは許可されません。このイベントには強力な機能がありますが、このエンティティの計算された変更セットへの参照を含む PreUpdateEventArgs インスタンスで実行されます。

This means you have access to all the fields that have changed for this entity with their old and new value. The following methods are available on the PreUpdateEventArgs:

これは、このエンティティに対して変更されたすべてのフィールドに、古い値と新しい値でアクセスできることを意味します。 PreUpdateEventArgs では次のメソッドを使用できます。

  • getEntity() to get access to the actual entity.

    getEntity() を使用して、実際のエンティティにアクセスできます。

  • getEntityChangeSet() to get a copy of the changeset array. Changes to this returned array do not affect updating.

    getEntityChangeSet() を使用して変更セット配列のコピーを取得します。この返された配列を変更しても、更新には影響しません。

  • hasChangedField($fieldName) to check if the given field name of the current entity changed.

    hasChangedField($fieldName) を使用して、現在のエンティティの指定されたフィールド名が変更されたかどうかを確認します。

  • getOldValue($fieldName) and getNewValue($fieldName) to access the values of a field.

    フィールドの値にアクセスするには、getOldValue($fieldName) および getNewValue($fieldName) を使用します。

  • setNewValue($fieldName, $value) to change the value of a field to be updated.

    setNewValue($fieldName, $value) を使用して、更新するフィールドの値を変更します。

A simple example for this event looks like:

このイベントの簡単な例は次のようになります。

<?php
use Doctrine\ORM\Event\PreUpdateEventArgs;

class NeverAliceOnlyBobListener
{
    public function preUpdate(PreUpdateEventArgs $eventArgs)
    {
        if ($eventArgs->getEntity() instanceof User) {
            if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
                $eventArgs->setNewValue('name', 'Bob');
                // The following will only work if `status` is already present in the computed changeset.
                // Otherwise it will throw an InvalidArgumentException:
                $eventArgs->setNewValue('status', 'active');
            }
        }
    }
}

You could also use this listener to implement validation of all the fields that have changed. This is more efficient than using a lifecycle callback when there are expensive validations to call:

このリスナーを使用して、変更されたすべてのフィールドの検証を実装することもできます。これは、呼び出しにコストのかかる検証がある場合に alifecycle コールバックを使用するよりも効率的です。

<?php
use Doctrine\ORM\Event\PreUpdateEventArgs;

class ValidCreditCardListener
{
    public function preUpdate(PreUpdateEventArgs $eventArgs)
    {
        if ($eventArgs->getEntity() instanceof Account) {
            if ($eventArgs->hasChangedField('creditCard')) {
                $this->validateCreditCard($eventArgs->getNewValue('creditCard'));
            }
        }
    }

    private function validateCreditCard($no)
    {
        // throw an exception to interrupt flush event. Transaction will be rolled back.
    }
}

Restrictions for this event:

このイベントの制限:

  • Changes to associations of the passed entities are not recognized by the flush operation anymore.

    渡されたエンティティの関連付けに対する変更は、フラッシュ操作によって認識されなくなりました。

  • Changes to fields of the passed entities are not recognized by the flush operation anymore, use the computed change-set passed to the event to modify primitive field values, e.g. use $eventArgs->setNewValue($field, $value); as in the Alice to Bob example above.

    渡されたエンティティのフィールドへの変更は、フラッシュ操作によって認識されなくなりました。イベントに渡された計算された変更セットを使用して、プリミティブ フィールド値を変更します。 use$eventArgs->setNewValue($field, $value);上記のアリスからボブへの例のように。

  • Any calls to EntityManager::persist() or EntityManager::remove(), even in combination with the UnitOfWork API are strongly discouraged and don’t work as expected outside the flush operation.

    EntityManager::persist() または EntityManager::remove() への呼び出しは、UnitOfWorkAPI と組み合わせた場合でも、強くお勧めできません。フラッシュ操作以外では期待どおりに動作しません。

9.6.7. postUpdate, postRemove, postPersist

These three post* events are called inside EntityManager::flush(). Changes in here are not relevant to the persistence in the database, but you can use these events to alter non-persistable items, like non-mapped fields, logging or even associated classes that are not directly mapped by Doctrine.

これら 3 つの post* イベントは EntityManager::flush() 内で呼び出されます。ここでの変更は、データベース内の永続性とは関係ありませんが、これらのイベントを使用して、マップされていないフィールド、ロギング、さらには関連付けなど、永続化できないアイテムを変更できます。 Doctrine によって直接マップされないクラス。

  • The postUpdate event occurs after the database update operations to entity data. It is not called for a DQL UPDATE statement.

    postUpdate イベントは、エンティティ データに対する databaseupdate 操作の後に発生します。 DQLUPDATE ステートメントでは呼び出されません。

  • The postPersist event occurs for an entity after the entity has been made persistent. It will be invoked after the database insert operations. Generated primary key values are available in the postPersist event.

    postPersist イベントは、エンティティが永続化された後にエンティティに対して発生します。これは、データベースの挿入操作の後に呼び出されます。生成された主キーの値は、postPersist イベントで使用できます。

  • The postRemove event occurs for an entity after the entity has been deleted. It will be invoked after the database delete operations. It is not called for a DQL DELETE statement.

    postRemove イベントは、エンティティが削除された後にエンティティに対して発生します。これは、databasedelete 操作の後に呼び出されます。 DQL DELETE ステートメントでは呼び出されません。

Warning

警告

The postRemove event or any events triggered after an entity removal can receive an uninitializable proxy in case you have configured an entity to cascade remove relations. In this case, you should load yourself the proxy in the associated pre* event.

postRemove イベントまたはエンティティの削除後にトリガーされるすべてのイベントは、削除関係をカスケードするようにエンティティを構成した場合、初期化できないプロキシを受け取ることができます。この場合、関連付けられた pre* イベントでプロキシをロードする必要があります。

9.6.8. postLoad

The postLoad event occurs after the entity has been loaded into the current EntityManager from the database or after refresh() has been applied to it.

postLoad イベントは、エンティティがデータベースから currentEntityManager にロードされた後、または refresh() がエンティティに適用された後に発生します。

Warning

警告

When using Doctrine\ORM\AbstractQuery::toIterable(), postLoad events will be executed immediately after objects are being hydrated, and therefore associations are not guaranteed to be initialized. It is not safe to combine usage of Doctrine\ORM\AbstractQuery::toIterable() and postLoad event handlers.

Doctrine\ORM\AbstractQuery::toIterable() を使用する場合、オブジェクトがハイドレートされた直後に postLoadevents が実行されるため、関連付けが初期化される保証はありません。 Doctrine\ORM\AbstractQuery::toIterable() と postLoad イベントハンドラを組み合わせて使用​​するのは安全ではありません。

9.6.9. onClear

The onClear event occurs when the EntityManager::clear() operation is invoked, after all references to entities have been removed from the unit of work. This event is not a lifecycle callback.

onClear イベントは、エンティティへのすべての参照が作業単位から削除された後に、EntityManager::clear() 操作が呼び出されたときに発生します。このイベントは、ライフサイクル コールバックではありません。

9.7. Entity listeners

An entity listener is a lifecycle listener class used for an entity.

エンティティ リスナーは、エンティティに使用されるライフサイクル リスナー クラスです。

  • The entity listener’s mapping may be applied to an entity class or mapped superclass.

    エンティティ リスナーのマッピングは、エンティティ クラスまたはマップされたスーパークラスに適用できます。

  • An entity listener is defined by mapping the entity class with the corresponding mapping.

    エンティティ リスナーは、エンティティ クラスを対応するマッピングでマッピングすることによって定義されます。

9.7.1. Entity listeners class

An Entity Listener could be any class, by default it should be a class with a no-arg constructor.

Entity Listener は任意のクラスにすることができます。デフォルトでは、引数なしのコンストラクタを持つクラスにする必要があります。

  • Different from Implementing Event Listeners an Entity Listener is invoked just to the specified entity

    イベント リスナーの実装とは異なり、エンティティ リスナーは指定されたエンティティに対してのみ呼び出されます。

  • An entity listener method receives two arguments, the entity instance and the lifecycle event.

    エンティティ リスナー メソッドは、エンティティ インスタンスとライフサイクル イベントの 2 つの引数を受け取ります。

  • The callback method can be defined by naming convention or specifying a method mapping.

    コールバック メソッドは、命名規則またはメソッド マッピングの指定によって定義できます。

  • When a listener mapping is not given the parser will use the naming convention to look for a matching method, e.g. it will look for a public preUpdate() method if you are listening to the preUpdate event.

    リスナーのマッピングが指定されていない場合、パーサーは命名規則を使用して一致するメソッドを探します。 preUpdate イベントをリッスンしている場合は、パブリックな preUpdate() メソッドを探します。

  • When a listener mapping is given the parser will not look for any methods using the naming convention.

    リスナー マッピングが指定されている場合、パーサーは命名規則を使用してメソッドを検索しません。

<?php
use Doctrine\ORM\Event\PreUpdateEventArgs;

class UserListener
{
    public function preUpdate(User $user, PreUpdateEventArgs $event)
    {
        // Do something on pre update.
    }
}

To define a specific event listener method (one that does not follow the naming convention) you need to map the listener method using the event type mapping:

特定のイベント リスナー メソッド (命名規則に従わないもの) を定義するには、イベント タイプ マッピングを使用してリスナー メソッドをマップする必要があります。

Note

ノート

The order of execution of multiple methods for the same event (e.g. multiple @PrePersist) is not guaranteed.

同じイベントに対する複数のメソッド (複数の @PrePersist など) の実行順序は保証されません。

9.7.2. Entity listeners resolver

Doctrine invokes the listener resolver to get the listener instance.

Doctrine はリスナーリゾルバーを呼び出してリスナーインスタンスを取得します。

  • A resolver allows you register a specific entity listener instance.

    リゾルバーを使用すると、特定のエンティティ リスナー インスタンスを登録できます。

  • You can also implement your own resolver by extending Doctrine\ORM\Mapping\DefaultEntityListenerResolver or implementing Doctrine\ORM\Mapping\EntityListenerResolver

    Doctrine\ORM\Mapping\DefaultEntityListenerResolver を拡張するか、Doctrine\ORM\Mapping\EntityListenerResolver を実装することで、独自のリゾルバーを実装することもできます。

Specifying an entity listener instance :

エンティティ リスナー インスタンスの指定:

<?php
use Doctrine\ORM\Event\PreUpdateEventArgs;

// User.php

/** @Entity @EntityListeners({"UserListener"}) */
class User
{
    // ....
}

// UserListener.php
class UserListener
{
    public function __construct(MyService $service)
    {
        $this->service = $service;
    }

    public function preUpdate(User $user, PreUpdateEventArgs $event)
    {
        $this->service->doSomething($user);
    }
}

// register a entity listener.
$listener = $container->get('user_listener');
$em->getConfiguration()->getEntityListenerResolver()->register($listener);

Implementing your own resolver:

独自のリゾルバーを実装する:

<?php
use Doctrine\ORM\Mapping\DefaultEntityListenerResolver;

class MyEntityListenerResolver extends DefaultEntityListenerResolver
{
    public function __construct($container)
    {
        $this->container = $container;
    }

    public function resolve($className)
    {
        // resolve the service id by the given class name;
        $id = 'user_listener';

        return $this->container->get($id);
    }
}

// Configure the listener resolver only before instantiating the EntityManager
$configurations->setEntityListenerResolver(new MyEntityListenerResolver);
$entityManager = new EntityManager(.., $configurations, ..);

9.8. Load ClassMetadata Event

loadClassMetadata - The loadClassMetadata event occurs after the mapping metadata for a class has been loaded from a mapping source (attributes/annotations/xml/yaml) in to a Doctrine\ORM\Mapping\ClassMetadata instance. You can hook in to this process and manipulate the instance. This event is not a lifecycle callback.

loadClassMetadata - loadClassMetadata イベントは、クラスのマッピング メタデータがマッピング ソース (attributes/annotations/xml/yaml) から Doctrine\ORM\Mapping\ClassMetadata インスタンスにロードされた後に発生します。このプロセスにフックして、インスタンス。このイベントはライフサイクル コールバックではありません。

<?php
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;

$test = new TestEventListener();
$evm = $em->getEventManager();
$evm->addEventListener(Doctrine\ORM\Events::loadClassMetadata, $test);

class TestEventListener
{
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        $fieldMapping = array(
            'fieldName' => 'about',
            'type' => 'string',
            'length' => 255
        );
        $classMetadata->mapField($fieldMapping);
    }
}

If not class metadata can be found, an onClassMetadataNotFound event is dispatched. Manipulating the given event args instance allows providing fallback metadata even when no actual metadata exists or could be found. This event is not a lifecycle callback.

クラス メタデータが見つからない場合は、onClassMetadataNotFound イベントが送出されます。指定されたイベント引数インスタンスを操作すると、実際のメタデータが存在しないか見つからない場合でも、フォールバック メタデータを提供できます。このイベントはライフサイクル コールバックではありません。

9.9. SchemaTool Events

It is possible to access the schema metadata during schema changes that are happening in Doctrine\ORM\Tools\SchemaTool. There are two different events where you can hook in.

Doctrine\ORM\Tools\SchemaTool で発生しているスキーマ変更中にスキーマ メタデータにアクセスすることができます。フックできるイベントが 2 つあります。

9.9.1. postGenerateSchemaTable

This event is fired for each Doctrine\DBAL\Schema\Table instance, after one was created and built up with the current class metadata of an entity. It is possible to access to the current state of Doctrine\DBAL\Schema\Schema, the current table schema instance and class metadata.

このイベントは、Doctrine\DBAL\Schema\Table インスタンスごとに発生します。インスタンスが作成され、エンティティの現在のクラス メタデータで構築された後です。 Doctrine\DBAL\Schema\Schema の現在の状態、現在のテーブル schemainstance およびクラス メタデータにアクセスできます。

<?php
use Doctrine\ORM\Tools\ToolEvents;
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;

$test = new TestEventListener();
$evm = $em->getEventManager();
$evm->addEventListener(ToolEvents::postGenerateSchemaTable, $test);

class TestEventListener
{
    public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        $schema = $eventArgs->getSchema();
        $table = $eventArgs->getClassTable();
    }
}

9.9.2. postGenerateSchema

This event is fired after the schema instance was successfully built and before SQL queries are generated from the schema information of Doctrine\DBAL\Schema\Schema. It allows to access the full object representation of the database schema and the EntityManager.

このイベントは、スキーマ インスタンスが正常に構築された後、Doctrine\DBAL\Schema\Schema のスキーマ情報から SQL クエリが生成される前に発生します。これにより、データベース スキーマと EntityManager の完全なオブジェクト表現にアクセスできます。

<?php
use Doctrine\ORM\Tools\ToolEvents;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;

$test = new TestEventListener();
$evm = $em->getEventManager();
$evm->addEventListener(ToolEvents::postGenerateSchema, $test);

class TestEventListener
{
    public function postGenerateSchema(GenerateSchemaEventArgs $eventArgs)
    {
        $schema = $eventArgs->getSchema();
        $em = $eventArgs->getEntityManager();
    }
}

Table Of Contents

Previous topic

8. Working with Associations

8. 関連付けの操作

Next topic

10. Doctrine Internals explained

10. Doctrine Internals の説明

This Page

Fork me on GitHub