События в Doctrine2
Речь пойдет о событиях которые можно лицезреть в классе Doctrine\ORM\Events.
prePersist
Возникает при:
- $entityManager->persist($entity)
- $entityManager->flush() для новых сущностей в связях при cascade= {"persist"}
- $entityManager->merge($entity)
- $unitOfWork->computeChangeSet($classMetadata, $entity) для новых сущностей в связях при cascade={"persist"}
Нюансы:
- Возникает для каждой сущности отдельно (нет доступа к методам $uow->getScheduled...() )
- На этом этапе в сущности нет идентификатора
- Возникает для связей c cascade={"persist"}
- Изменения связей в подписчике не учитываются
preRemove
Возникает при:
- $entityManager->remove($entity)
Нюансы:
- возникает для связей с cascade={"remove"}
- Изменения полей сущности в подписчике не учитываются
- если не указать cascade={"remove"}, то событие не возникает, даже если указано @ORM\JoinColumn(onDelete="CASCADE") ведь ответственность ложится на базу, а не на доктрину
preFlush
Возникает при:
- $entityManager->flush()
- $unitOfWork->computeChangeSet($classMetadata, $entity)
Нюансы:
- При возникновении этого события можно безопасно вызывать $entityManager- >flush() без ограничений
- Если в связях используется cascade= {"persist"}, то методы $uow->getScheduled...() еще не знают про автоматический persist для связей (читай методы $uow->getScheduled...() не знают, что к заперсистенному объекту добавлены другие объекты в результате которых будет выполнен INSERT в связанные таблицы)
onFlush
Возникает при:
- $entityManager->flush() после вычислений changeSet НО перед стартом транзакции
Имеет доступ ко всем изменениям:
- foreach ($uow->getScheduledEntityInsertions() as $entity) {}
- foreach ($uow->getScheduledEntityUpdates() as $entity) {}
- foreach ($uow->getScheduledEntityDeletions() as $entity) {}
- foreach ($uow->getScheduledCollectionDeletions() as $collection) {}
- foreach ($uow->getScheduledCollectionUpdates() as $collection) {
Нюансы:
- Создавать сущности можно только пересчитав их changeSet:
$unitOfWork->computeChangeSet($classMetadata, $entity) - Изменения в связанных сущностях нужно пересчитывать:
$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity) - Событие возникает даже, если changeSet пустой
postFlush
Возникает:
- внутри вызова $entityManager->flush() - после коммита транзакции
Нюансы:
- Событие возникает даже, если changeSet пустой
- В подписчике этого события не рекомендовано вызывать $entityManager->flush() (если это сделать, то придется вручную бороться с цикличностью)
- Чтобы отследить данное событие, нужно отдельно зарегистрировать слушателя:
$em->getEventManager()->addEventListener([\Doctrine\ORM\Events::postFlush], new MyListener());
preUpdate
Возникает:
- Перед обновлением сущности в $entityManager->flush()
Нюансы:
- Событие возникает если changeSet пустой
- Пересчитывать chageSet не нужно - можно менять любые сущности не вызывая:
$unitOfWork->computeChangeSet($classMetadata, $entity)
$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity) - Однако, не разрешается менять скаляры напрямую, только с помощью:
Doctrine\ORM\Event\PreUpdateEventArgs $args->setNewValue('field', 'value')
(еще раз: изменения скаляров напрямую будет проигнорировано) - На этом этапе не рекомендуется вызывать $entityManager->persist($entity) или $entityManager->remove($entity) даже с использованием $unitOfWork может возникнуть unexpected behavior
- Не разрешается менять связанные сущности (потому что для них будет вызван свой Event)
use Doctrine\ORM\Event\PreUpdateEventArgs;
public function preUpdate(PreUpdateEventArgs $event)
{
$entity = $event->getEntity();
$changeSet = $event->getEntityChangeSet();
// Проверяем, изменялось ли конкретное поле "someField"
if (isset($changeSet['someField'])) {
$oldValue = $changeSet['someField'][0];
$newValue = $changeSet['someField'][1];
// Действия при изменении поля
}
// Или можно перебрать все изменённые поля
foreach ($changeSet as $field => $values) {
$oldValue = $values[0];
$newValue = $values[1];
// Обработка изменений
}
}
postPersist, postUpdate, postRemove
Возникает:
- После соответствующих действий
Нюансы:
- Изменения в сущностях не учитываются
- postPersist - возникает после выполнения инструкции INSERT INTO ... но до коммита транзакции
- postUpdate - возникает после выполнения инструкции UPDATE ... но до коммита транзакции
- postRemove - возникает после выполнения инструкции DELETE FROM ... но до коммита транзакции. Если не указать cascade={"remove"}, то событие не возникает, даже если указано @ORM\JoinColumn(onDelete="CASCADE") ведь ответственность ложится на базу, а не на доктрину
onClear
Возникает:
- При вызове $entityManager- >clear()
- После $entityManager- >flush()
Пример использования: чистить кастомные кэши.
postLoad
Возникает:
- При создании новой сущности после гидрации (когда из бд пришла строчка, которая превращается в сущность)
- При очистке гидратора
loadClassMetadata
Возникает:
- После чтения маппингов и создании Doctrine\ORM\Mapping\ClassMetadataInfo на их основании
Пример использования: можно добавить динамические поля (магические поля) и метаданные будут работать
onClassMetadataNotFound
Возникает:
- Если данные для сущности не найдены, можно добавить fallback
Пример использования: добавить метаданные для несуществующего класса (класс не помеченный тегом Entity), например есть сущность, которую мы менеджим сами
Источник: 1
15.02.2011 08:48