Search code examples
phpsymfonypost-update

Symfony 2 postUpdate executed before data is stored


I am stuck for about a day now on the following

I created a listener on my account entity, It listens to prePersist, preUpdate, postPersist and postUpdate. I thought postUpdate was executed after the data has been store in the database, but now i doubt it.

The listener

/**
 * Account listener
 */
class AccountListener
{

    private $container;

    /**
     * Constructor
     *
     * @param ContainerInterface $container
     */
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Pre persist
     *
     * @param LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Accounts) {
            $this->checkIfApiCallIsNeeded($entity, $args);
        }
    }

    /**
     * pre update
     *
     * @param LifecycleEventArgs $args
     */
    public function preUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Accounts) {
            $this->checkIfApiCallIsNeeded($entity, $args);
        }
    }

    /**
     * Post persist
     *
     * @param LifecycleEventArgs $args
     */
    public function postPersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Accounts) {
            $this->callApi($entity, $args);
        }
    }

    /**
     * Post update
     *
     * @param LifecycleEventArgs $args
     */
    public function postUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Accounts) {
            $this->callApi($entity, $args);
        }
    }

    /**
     * Checks if a update should be send to the api and store the result in db
     * 
     * @param  Accounts           $account
     * @param  LifecycleEventArgs $args 
     */
    private function checkIfApiCallIsNeeded(Accounts $account, LifecycleEventArgs $args)
    {

        $importantProperties = array(
            'contactName',
            'address',
            'zipPostal',
            'city',
            'stateProvince',
            'country'
        );

        $callApi = 0;

        $uow = $args->getEntityManager()->getUnitOfWork();
        $changeset = $uow->getEntityChangeSet($account);

    /**
     * Check if one of the important properties has been changed 
     */
        foreach ($importantProperties as $property) {
            if (array_key_exists($property, $changeset)) {
                $callApi = 1;
            }
        }

        /**
         * Store in database
         */
        $account->setNeedUpdate($callApi);
    }

    /**
     * Update account to api
     *
     * @param Accounts $account
     */
    private function callApi(Accounts $account, LifecycleEventArgs $args)
    {
        $callApi = $account->getNeedUpdate();
        $accountId = $account->getId();

        if ($callApi === 1) {
            // Call the API
        }
    }
}

The listener should check if one of the important fields has been changed, if so it should send an API request (after the account is updated). However when I update my account it looks like the action inside my API still gets the old account.

Then I tried to die(var_dump($account)); inside the callApi function. And the result was that the var $account gave me the updated entity just like I expected. BUT inside the function callApi() the data has not been stored into the database yet! (I know this because the values from die(var_dump($account)); are not equal with the values in the database). So in that case its normal that my API still gets the old account from the database.

I don't know why this happens, but to me it looks like the data gets stored after the postUpdate function has been completely executed.

I would like to know why this happens and if this is normal behavior. I also would like to know how I can make sure the API is called after the data has been stored into the database.


Solution

  • The postUpdate event is not called after the flush() but inside the flush. This is why a postFlush event exists (even if it's not a lifecycle callback).

    Check for more information the official Doctrine 2 documentation chapter 9. Events.