An Entity Manager for a Unit of Work in PHP

In this fifth part of a series, I create a simple entity manager class, which can switch over multiple UoWs by using a single method call. The class will inject into its internals a factory responsible for spawning different UoWs on request. This will permit you to decouple object instantiation from application logic.

Although the model provided by many RDBMS vendors is often the most effective approach to take when  performing transactions in several domain objects, it’s possible to replicate (at least partially) this functionality at the application level by using a design pattern called Unit of Work (UoW). Implementing this pattern allows you to queue those objects in memory for further insertion, updating and deletion according to the requirements of client code. It also allows you to execute these operations through a single method call, thus optimizing access to the underlying persistence mechanism.

Of course, as with any other pattern, a UoW is language agnostic. This means that it can be implemented in a plethora of programming languages, including PHP. In earlier parts of this series, I proceeded to build an abstract UoW. I even complemented the development process by adding to the UoW a few additional collaborators, such as a MySQL adapter, an abstract data mapper and a class responsible for handling collections of entities.

While at this point it’s feasible to create a fully-functional UoW using all of the sample classes defined so far, in this case I’d like to create an extra layer capable of swapping multiple UoWs via a very simple API. As you’ll see, the layer will be made up of a basic entity manager class, quite similar to the one present in Doctrine 2.0, but without all its bells and whistles. 

Having outlined the goal of this fifth tutorial of the series, it’s time to continue learning how to implement a UoW with PHP. Let’s jump in!

Review: handling collections of entities

As always, before I start developing the entity manager mentioned above, I’ll review the definition of the class created in the previous tutorial. It was a countable iterator charged with manipulating collections of generic entities.

With that said, here’s the source code corresponding to this entity iterator. Pay attention to it, please:

(CollectionAbstract.php)

<?php

abstract class CollectionAbstract implements Iterator, Countable, ArrayAccess
{
    protected $_entities = array();
   
    /**
     * Get the entities stored in the collection
     */
    public function getEntities()
    {
        return $this->_entities;
    }
   
    /**
     * Clear the collection of entities
     */
    public function clear()
    {
        $this->_entities = array();
    }
   
    /**
     * Reset the collection of entities (implementation required by Iterator Interface)
     */
    public function rewind()
    {
        reset($this->_entities);
    }
   
    /**
     * Get the current entity in the collection (implementation required by Iterator Interface)
     */ 
    public function current()
    {
        return current($this->_entities);
    }
   
    /**
     * Move to the next entity in the collection (implementation required by Iterator Interface)
     */
    public function next()
    {
        next($this->_entities);
    }
   
    /**
     * Get the key of the current entity in the collection (implementation required by Iterator Interface)
     */
    public function key()
    {
        return key($this->_entities);
    }
   
    /**
     * Check if there are more entities in the collection (implementation required by Iterator Interface)
     */
    public function valid()
    {
        return (boolean) $this->current();
    }
   
    /**
     * Count the number of entities in the collection (implementation required by Countable Interface)
     */
    public function count()
    {
        return count($this->_entities);
    }
   
    /**
     * Add an entity to the collection (implementation required by ArrayAccess interface)
     */
    public function offsetSet($key, $entity)
    {
        if ($key === null) {
            if (!in_array($key, $this->_entities, true)) {
                $this->_entities[] = $entity;
                return;
            }
        }
        else if (!array_key_exists($key, $this->_entities)) {
            $this->_entities[$key] = $entity;
        }
    }
   
    /**
     * Remove an entity from the collection (implementation required by ArrayAccess interface)
     */
    public function offsetUnset($key)
    {
        if ($key instanceof EntityAbstract) {
            $entities = array();
            foreach ($this->_entities as $_entity) {
                if ($_entity !== $key) {
                    $entities[] = $_entity;
                }  
            }
            $this->_entities = $entities;
            return;
        }
        if (array_key_exists($key, $this->_entities)) {
            unset($this->_entities[$key]);
        }
    }
   
    /**
     * Get the specified entity from the collection (implementation required by ArrayAccess interface)
     */
    public function offsetGet($key)
    {
        return array_key_exists($key, $this->_entities) ?
               $this->_entities[$key] :
               null;
    } 
   
    /**
     * Check if the specified entity exists in the collection (implementation required by ArrayAccess interface)
     */    
    public function offsetExists($key)
    {
        return array_key_exists($key, $this->_entities);
    }
}

Admittedly, there’s much more that can be said about the class above. All it does is implement the methods declared by the Iterator, Countable and ArrayAccess native PHP interfaces to traverse and manipulate generic entities by using an array-like notation. You might think the construction of this class is pointless at first glance, when I build an example that uses the previous UoW, you’ll see how helpful it’ll be for fetching multiple entities in one go.

But before I reach that point, there are a few things that needs to be done. These include the creation of the entity manager discussed at the beginning. Precisely this topic will be covered in the following segment, so click on the link below and keep reading.

{mospagebreak title=Factoring Units of Work with a factory class}

We need to take one more step before creating the entity manager mentioned in the previous segment. You’re wondering what is it, right? Well, considering that the manager will be able to use multiple UoWs at runtime, it’d be useful to inject into it a factory that creates instances of those UoWs on request.

If my description sounds somewhat confusing to you, just look at the following fragment, which shows the source code of the factory:

(UnitOfWorkFactory.php)

<?php

class UnitOfWorkFactory
{  
    /**
     * Create a Unit of Work with the specified name
     */
    public function create($name)
    {
        $name = ucfirst(strtolower($name));
        $collection = $name . ‘Collection’;
        $dataMapper = $name . ‘Mapper’;
        $unitOfWork = $name . ‘UnitOfWork’;
        return new $unitOfWork(
            new $dataMapper(
                MySQLAdapter::getInstance(), new $collection
            )
        );
    }
}

As you can see above, the previous “UnitOfWorkFactory” class implements a single method, called “create()”, which takes as an incoming argument the name of the UoW that needs to be spawned. Finally, the method uses this argument to instantiate all of the pertinent dependencies, and returns to client code a fully-functional UoW object. Do you understand how the factory does its thing? I bet you do.

Moreover, the definition of this class not only separates object instantiation from application logic, but it shows how to wire together some of the classes discussed in earlier tutorials of the series.

So far, so good. Now that you understand the purpose of building the previous factory class, it’s finally time to define the entity manager. The details of this process will be discussed below.

Building an entity manager class

As I said at the beginning of this tutorial, the entity manager class that I plan to build will act like a simple “switcher” capable of swapping multiple UoWs at runtime. To do this, however, it must use the functionality of the factory defined above, which means that the latter must be injected into the manager like a sort of service locator.

It’s time to stop talking and show the source code of the entity manager, so you can grasp its logic. Here’s the brand new class:  

(EntityManager.php)

<?php

class EntityManager
{
    protected $_unitOfWorkFactory;
    protected $_unitOfWorks = array();
    protected $_currentUnitOfWork;
   
    /**
     * Class constructor
     */
    public function __construct(UnitOfWorkFactory $unitOfWorkFactory)
    {
        $this->_unitOfWorkFactory = $unitOfWorkFactory;
        $this->init();
    }
   
    /**
     * Initialize the entity manager here
     */
    public function init()
    {
        $this->addUnitOfWork(‘user’);
    }
   
    /**
     * Get the Unit of Work factory
     */
    public function getUnitOfWorkFactory()
    {
        return $this->_unitOfWorkFactory;
    }
   
    /**
     * Add a new Unit of Work by specifying its key
     */
    public function addUnitOfWork($key)
    {
        $key = strtolower($key);
        if (!array_key_exists($key, $this->_unitOfWorks)) {
            $unitOfWork = $this->_unitOfWorkFactory->create($key);
            $this->_unitOfWorks[$key] = $unitOfWork;
            $this->setCurrentUnitOfWork($key);
        }
        return $this;
    }
   
    /**
     * Add multiple Units of Work by specifying an array of keys
     */
    public function addUnitOfWorks(array $keys)
    {
        if (!empty($keys)) {
            foreach ($keys as $key) {
                $this->addUnitOfWork($key);
            } 
        }
        return $this;
    }
   
    /**
     * Get all the Units of Work
     */  
    public function getUnitOfWorks()
    {
        return $this->_unitOfWorks;
    }
   
    /**
     * Set the current Unit of Work
     */
    public function setCurrentUnitOfWork($key)
    {
        $key = strtolower($key);
        if (!array_key_exists($key, $this->_unitOfWorks)) {
            throw new EntityManagerException(‘The specified Unit of Work is not valid.’);  
        }
        $this->_currentUnitOfWork = $this->_unitOfWorks[$key];
        return $this;
    }
   
    /**
     * Get the current Unit of Work
     */
    public function getCurrentUnitOfWork()
    {
        if ($this->_currentUnitOfWork === null) {
            throw new EntityManagerException(‘No current Unit of Work has been set yet.’);
        }
        return $this->_currentUnitOfWork;
    }
   
    /**
     * Set the specified entity ‘new’
     */
    public function setNew(EntityAbstract $entity)
    {
        $this->getCurrentUnitOfWork()->setNew($entity);       
    }
   
    /**
     * Set the specified entity ‘clean’
     */
    public function setClean(EntityAbstract $entity)
    {
        $this->getCurrentUnitOfWork()->setClean($entity);       
    }
   
    /**
     * Set the specified entity ‘dirty’
     */
    public function setDirty(EntityAbstract $entity)
    {
        $this->getCurrentUnitOfWork()->setDirty($entity);       
    }
   
    /**
     * Set the specified entity ‘removed’
     */
    public function setRemoved(EntityAbstract $entity)
    {
        $this->getCurrentUnitOfWork()->setRemoved($entity);       
    }
   
    /**
     * Clear the ‘new’ entities stored in the current Unit of Work
     */
    public function clearNew()
    {   
        $this->getCurrentUnitOfWork()->clearNew();
    }
   
    /**
     * Clear the ‘clean’ entities stored in the current Unit of Work
     */
    public function clearClean()
    {   
        $this->getCurrentUnitOfWork()->clearClean();
    }
   
    /**
     * Clear the ‘dirty’ entities stored in the current Unit of Work
     */
    public function clearDirty()
    {   
        $this->getCurrentUnitOfWork()->clearDirty();
    }
   
    /**
     * Clear the ‘removed’ entities stored in the current Unit of Work
     */
    public function clearRemoved()
    {   
        $this->getCurrentUnitOfWork()->clearRemoved();
    }
   
    /**
     * Clear the entities stored in all the Units of Work
     */
    public function clearAll()
    {
        if (!empty($this->_unitOfWorks)) {
            foreach ($this->_unitOfWorks as $unitOfWork) {
                $unitOfWork->clearAll();
            } 
        }
    }
   
    /**
     * Find an entity by its ID
     */  
    public function findById($id)
    {
        return $this->getCurrentUnitOfWork()->findById($id);
    }
   
    /**
     * Find all the entities
     */
    public function findAll()
    {
        return $this->getCurrentUnitOfWork()->findAll();  
    } 
   
    /**
     * Commit all the pending entity operations (create, update, remove)
     */
    public function commit()
    {
        if (!empty($this->_unitOfWorks)) {
            foreach ($this->_unitOfWorks as $unitOfWork) {
                $unitOfWork->commit();
            }   
        }
    }           
}

 

(EntityManagerException.php)

<?php

class EntityManagerException extends Exception {}

To be frank, there’s no reason to feel intimidated by the rather long definition of the above “EntityManager” class. The tasks that it performs are fairly straightforward. The manager is nothing but a wrapper for a Unit of Work, except that in this case it’s capable of using multiple UoWs via its complementary “setCurrentUnitOfWork()” and “addUnitOfWork()” methods. What’s more, the latter uses  the injected factory internally to create a UoW with the specified name. That’s quite simple to grasp, isn’t it?

In addition, you should notice that the class’s “init()” method creates by default a UoW that specifically manipulates user entities. While this may not make much sense now, it will later on. In a coming tutorial I plan to demonstrate how to implement a UoW that executes transactional operations in user entities, so defining the method that way offers a pretty solid foundation.

But I’m getting ahead of myself, since the implementation of a concrete UoW will be covered in depth in another installment of this series.  

Final thoughts

In this fifth installment of the series, I created a simple entity manager class, which is capable of switching over multiple UoWs by using something as simple as a single method call. Also, the class injects into its internals a factory responsible for spawning different UoWs on request, which permits you to decouple object instantiation from application logic.

With the previous entity manager already up and running, the conditions are finally set to create an example application that shows how to put the sample UoW in action. In line with this concept, in the coming tutorial I’m going to start defining the building blocks of this application, which will be tasked with performing CRUD operations on a few user entities.

Here’s my final piece of advice: don’t miss the next part!  

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan