Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I do post persist/update actions in doctrine 2.1, that involves re-saving to the db?

Using doctrine 2.1 (and zend framework 1.11, not that it matters for this matter), how can I do post persist and post update actions, that involves re-saving to the db?

For example, creating a unique token based on the just generated primary key' id, or generating a thumbnail for an uploaded image (which actually doesn't require re-saving to the db, but still) ?


EDIT - let's explain, shall we ?

The above is actually a question regarding two scenarios. Both scenarios relate to the following state:

Let's say I have a User entity. When the object is flushed after it has been marked to be persisted, it'll have the normal auto-generated id of mysql - meaning running numbers normally beginning at 1, 2, 3, etc..
Each user can upload an image - which he will be able to use in the application - which will have a record in the db as well. So I have another entity called Image. Each Image entity also has an auto-generated id - same methodology as the user id.

Now - here is the scenarios:

  1. When a user uploads an image, I want to generate a thumbnail for that image right after it is saved to the db. This should happen for every new or updated image.
    Since we're trying to stay smart, I don't want the code to generate the thumbnail to be written like this:

    $image = new Image();
    ...
    $entityManager->persist($image);
    $entityManager->flush();
    callToFunctionThatGeneratesThumbnailOnImage($image);

    but rather I want it to occur automatically on the persisting of the object (well, flush of the persisted object), like the prePersist or preUpdate methods.

  2. Since the user uploaded an image, he get's a link to it. It will probably look something like: http://www.mysite.com/showImage?id=[IMAGEID].
    This allows anyone to just change the imageid in this link, and see other user's images.
    So in order to prevent such a thing, I want to generate a unique token for every image. Since it doesn't really need to be sophisticated, I thought about using the md5 value of the image id, with some salt.
    But for that, I need to have the id of that image - which I'll only have after flushing the persisted object - then generate the md5, and then saving it again to the db.

Understand that the links for the images are supposed to be publicly accessible so I can't just allow an authenticated user to view them by some kind of permission rules.

like image 665
Doron Avatar asked Sep 12 '11 14:09

Doron


2 Answers

You probably know already about Doctrine events. What you could do:

Use the postPersist event handler. That one occurs after the DB insert, so the auto generated ids are available.

The EventManager class can help you with this:

class MyEventListener
{
    public function postPersist(LifecycleEventArgs $eventArgs)
    {
        // in a listener you have the entity instance and the 
        // EntityManager available via the event arguments
        $entity = $eventArgs->getEntity();
        $em = $eventArgs->getEntityManager();

        if ($entity instanceof User) {
            // do some stuff
        }

    }
}

$eventManager = $em->getEventManager():
$eventManager->addEventListener(Events::postPersist, new MyEventListener());

Be sure to check e. g. if the User already has an Image, otherwise if you call flush in the event listener, you might be caught in an endless loop.

Of course you could also make your User class aware of that image creation operation with an inline postPersist eventHandler and add @HasLifecycleCallbacks in your mapping and then always flush at the end of the request e. g. in a shutdown function, but in my opinion this kind of stuff belongs in a separate listener. YMMV.

If you need the entity id before flushing, just after creating the object, another approach is to generate the ids for the entities within your application, e. g. using uuids.

Now you can do something like:

class Entity {
    public function __construct()
    {
        $this->id = uuid_create();
    }
}

Now you have an id already set when you just do:

$e = new Entity();

And you only need to call EntityManager::flush at the end of the request

like image 112
Max Avatar answered Oct 29 '22 23:10

Max


In the end, I listened to @Arms who commented on the question.
I started using a service layer for doing such things.
So now, I have a method in the service layer which creates the Image entity. After it calls the persist and flush, it calls the method that generates the thumbnail.

The Service Layer pattern is a good solution for such things.

like image 2
Doron Avatar answered Oct 29 '22 23:10

Doron