Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine postLoad event for associations

I currently have an entity which I would like to modify slightly upon load. This modification will be a one time change which will then be persisted in a new field along with the entity.

To clarify my current objective: The entity is a "Location" and forms part of a nested set. It has a name, lft/rgt values and an Id. One computationally expensive task I was performing with this entity was to fetch a full location path and display it as text. For example, with the location entity "Waterloo" I want to display as "Waterloo|London|United Kingdom". This involves traversing through the entire set (to the root node).

To reduce the cost of this I've created a new field on the Location entity that can be stamped with this value (and updated as/when the location (or any location within the tree) name is modified). Considering my application is in a live state I need to avoid running this as a one off process as it would incur quite an intensive one-time hit on the DB, instead I'd like to apply this update as and when each location (without that value) is loaded. I assumed Doctrine's postLoad event mechanism would be perfect for achieving this, however..

The Location entities are not loaded directly by my application, they will always be the inverse side of a relation. With this is mind, and the fact that doctrine's postLoad event:

  • Doesn't load (allow access to) any associated data
  • Is only fired for owning Entities

I have no way of gently making these modifications.

Anyone have any advice, or experience on this?

like image 976
Lee Davis Avatar asked Jan 24 '13 12:01

Lee Davis


1 Answers

I was able to load the associated Location objects within the postLoad event by using the initializeObject() method on the Entity Manager.

/**
 * Upon loading the object, if the location text isn't set, set it
 * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
 */
public function postLoad(\Doctrine\ORM\Event\LifecycleEventArgs $args)
{
    $this->em = $args->getEntityManager();
    $entity = $args->getEntity();

    if ($entity instanceof \Entities\Location)
    {
        if (is_null($entity->getPathText()))
        {
            $entity->setPathText("new value");
            $this->em->flush($entity);
        }
    } elseif ($entity instanceof {parent Entity})
    {
        $location = $entity->getLocation();
        // This triggers the postLoad event again, but this time with Location as the parent Entity
        $this->em->initializeObject($location);
    }
}
like image 132
Lee Davis Avatar answered Nov 16 '22 12:11

Lee Davis