1
votes

The documentation says: https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/events.html#postupdate-postremove-postpersist

The 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.

So let's imagine I have an Image entity:

<?php
/**
 * @ORM\Entity
 */
class Image
{
    /**
     * @var int|null
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

    /**
     * @var string
     * @ORM\Column(type="string")
     */
    private string $path;

    /**
     * @var string
     * @ORM\Column(type="string")
     */
    private string $status = 'RECEIVED';
}

Once I flush my Image entity I want to upload the corresponding file on a FTP server, so I do it in the postPersist event.

But if the upload on FTP fail I want to change the status of my Image to FTP_ERROR.

<?php
public function postPersist(Image $image, LifecycleEventArgs $event)
{
    $em = $event->getEntityManager();
    try {
        $this->someService->uploadToFtp($image);
    } catch (Exception $e) {
        $image->setStatus('FTP_ERROR');
        $em->persist($image);
        $em->flush();
    }
}

And it works, but as documentation says it's not a good way to do it.

I have seen this post: Flushing in postPersist possible or not? which says:

@iiirxs:

It is ok to call flush() on a PostPersist lifecycle callback in order to change a mapped property of your entity.

So how to do so? @iiirxs and the documentation say 2 different things.

1
postPersist is only triggered after the entity is saved first (sql insert), flushing after that will only trigger an sql update (maybe replace idk), so you won't get infinite loops; so firstly you should remove the persist() call from the postPersit eventhandler. you might not get loops, because the entityManager finds the entity and only updates it, but surely you are making it do extra things. Once the entity is persisted, no more postPersist events should trigger on that entity, only postUpdates. So your solution should be fine - zedling
Hi @zedling I know that it works, I have done it many times. The problem is that Doctrine tell you to don't do it : >Changes in here are not relevant to the persistence in the database - Alexandre97122

1 Answers

3
votes

The best way to download something on such event as postPersist is using https://symfony.com/doc/current/components/messenger.html

so, you can create asynchronous task for file uploading and Symfony Messenger will be able to handle errors and retry it automatically on fail, also you will be able to update it, status and etc in separate process and it will not depend on specific doctrine cases like case in your question.