Как добавить обработчик событий (event listener) для моделей OroCRM (Oro Platform)?

В некоторых случаях, вам нужно обновить поле перед сохранением или перед обновлением объекта. Использование обработчика доктрины идеальный способ для этого работающий в Oro Platform и соответственно в OroCRM.

*модель — entity.

Настройка обработчика

Предположим, что вы уже расширили бандл Оро как OroCRMContactBundle (вы можете найти более подробную информацию на этой странице: Как расширить имеющийся бандл для OroCRM (Oro Platform)?). Например вы хотели бы дополнить социальную информацию о контакте с некоторыми внешними данными API.

Первым делом добавим обработчик к бандлу в файле services.yml.

# src/Acme/Bundle/ContactBundle/Resources/config/services.yml
services:  
    contact.listener:
        class: Acme\Bundle\ContactBundle\Listener\SocialFields
        tags:
            - { name: doctrine.event_listener, event: onFlush }

Создание класса обработчика

В предыдущей части мы создали contact.listener, который срабатывает при обращению к модели. На самом деле событие будет срабатывать при каждом обращении к объектам бандла, так что необходимо проверять тип класса текущей модели.

<?php  
// src/Acme/Bundle/ContactBundle/Listener/SocialFields.php
namespace Acme\Bundle\ContactBundle\Listener;

use Doctrine\ORM\Event\OnFlushEventArgs;  
use OroCRM\Bundle\ContactBundle\Entity\Contact;  
use OroCRM\Bundle\ContactBundle\Entity\ContactEmail;

class SocialFields  
{
    public function onFlush(OnFlushEventArgs $args)
    {
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        // мы будем обрабатывать во время вставки и обновления
        $entities = array_merge(
            $uow->getScheduledEntityInsertions(),
            $uow->getScheduledEntityUpdates()
        )

        foreach ($entities as $entity) {
            // всегда, когда мы обновляем или вставляем новую строку в модель ContactEmail событие выполняется
            if (!$entity instanceof ContactEmail) {
                continue;
            }

            // проверяем первичный ключ (is primary) email
            if ($entity->isPrimary()) {
                $owner = $entity->getOwner();

                // ... обновление социальной информации пользователя с первичным email

                // принудительное сохранение
                $em->persist($owner);
                $md = $em->getClassMetadata(get_class($owner));
                $uow->computeChangeSet($md, $owner);
            }
        }
    }
}

В случае обновления нам необходимо подготовить модель и принудительно обновить при помощи «computeChangeSet». Все модели связанные с текущей будут обновлены как только вы измените любые свойства или значения. Если вы этого не сделаете, новое значение в связанных объектах не обновится.