Location: PHPKode > projects > Spiral > ametaireau-spiral-272a2b1/framework/persistence/classes/orm/AbstractUnitOfWork.php
<?php

namespace spiral\framework\persistence\orm;

/**
 * Abstract unit of work
 * 
 * This component manages objects status changes.
 * See methods documentation to learn how status are updated.
 * 
 * Note on the implementation:
 * 	- This implementation is directly dependent from OID classification
 * 		which means that the OID is used to identify an object and not the reference
 * 		as it could be thought.
 * 	- OIDs are considered to be scalar values.
 * 
 * @author		Frédéric Sureau <hide@address.com>
 * @copyright	2009 Spiral-project.org <http://www.spiral-project.org>
 * @license		GNU General Public License <http://www.gnu.org/licenses/gpl.html>
 */
abstract class AbstractUnitOfWork implements UnitOfWork
{
	/**
	 * Internal status constants
	 * 
	 * @var string
	 */
	const _STATUS_NEW = 'new';
	const _STATUS_DIRTY = 'dirty';
	const _STATUS_DELETED = 'deleted';
	const _STATUS_CLEAN = 'clean';
	
	/**
	 * Objects collection
	 * 
	 * @var	array
	 */
	protected $_objects = array();
	
	/**
	 * Objects status collection
	 * 
	 * @var	array
	 */
	protected $_objectsStatus = array();
	
	/**
	 * Previous objects status collection
	 * 
	 * @var	array
	 */
	protected $_previousObjectsStatus = array();
	
	/**
	 * Commit all operations to the storage engine
	 * 
	 * @return	void
	 */
	public function commit()
	{
		$this->_commit();
		$this->_cleanUp();
	}
	
	/**
	 * Rollback all operations
	 * 
	 * @return	void
	 */
	public function rollback()
	{
		$this->_cleanUp();
	}
	
	/**
	 * Add an object
	 * 
	 * Here is the table of applied status modifications:
	 * ---------------------------------------------------------------------------------
	 * | Initial status | New status     | Comment                                     |
	 * ---------------------------------------------------------------------------------
	 * | clean          | new            | Simply register new status                  |
	 * | dirty          | ???            | Impossible situation, can't insert a        |
	 * |                |                |  registered object                          |
	 * | deleted        | clean or dirty | Recover previous status                     |
	 * ---------------------------------------------------------------------------------
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object
	 * @return	void
	 */
	public function add($oid, $object)
	{
		$currentStatus = $this->_getObjectStatus($oid, $object);
		
		switch($currentStatus)
		{
			case self::_STATUS_DELETED:
				if($this->_getPreviousObjectStatus($oid, $object) === self::_STATUS_DIRTY)
				{
					$newStatus = self::_STATUS_DIRTY;
				}
				else
				{
					$newStatus = self::_STATUS_CLEAN;
				}
				break;
				
			default:
				$newStatus = self::_STATUS_NEW;
				break;
		}
		
		$this->_setObjectStatus($oid, $object, $newStatus);
	}
	
	/**
	 * Update an object
	 * 
	 * Here is the table of applied status modifications:
	 * ---------------------------------------------------------------------------------
	 * | Initial status | New status     | Comment                                     |
	 * ---------------------------------------------------------------------------------
	 * | clean          | dirty          | Simply register new status                  |
	 * | new            | new            | Since the object is not yet registered in   |
	 * |                |                |  the storage engine, an insert will save    |
	 * |                |                |  dirty values as well                       |
	 * | deleted        | deleted        | The object is supposed to be deleted so     |
	 * |                |                |  changes have no importance                 |
	 * ---------------------------------------------------------------------------------
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object
	 * @return	void
	 */
	public function update($oid, $object)
	{
		$currentStatus = $this->_getObjectStatus($oid, $object);
		
		switch($currentStatus)
		{
			case self::_STATUS_NEW:
				$newStatus = self::_STATUS_NEW;
				break;
				
			case self::_STATUS_DELETED:
				$newStatus = self::_STATUS_DELETED;
				break;
				
			default:
				$newStatus = self::_STATUS_DIRTY;
				break;
		}
		
		$this->_setObjectStatus($oid, $object, $newStatus);
	}
	
	/**
	 * Delete an object
	 * 
	 * Here is the table of applied status modifications:
	 * ---------------------------------------------------------------------------------
	 * | Initial status | New status     | Comment                                     |
	 * ---------------------------------------------------------------------------------
	 * | clean          | deleted        | Simply register new status                  |
	 * | new            | clean          | Deleting a new object means to do nothing   |
	 * |                |                |  at the end                                 |
	 * | dirty          | deleted        | Do not take care of changes anymore since   |
	 * |                |                |  we want to delete the object               |
	 * ---------------------------------------------------------------------------------
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object
	 * @return	void
	 */
	public function delete($oid, $object)
	{
		$currentStatus = $this->_getObjectStatus($oid, $object);
		
		switch($currentStatus)
		{
			case self::_STATUS_NEW:
				$newStatus = self::_STATUS_CLEAN;
				break;
				
			default:
				$newStatus = self::_STATUS_DELETED;
				break;
		}
		
		$this->_setObjectStatus($oid, $object, $newStatus);
	}
	
	/**
	 * Make an object clean
	 * 
	 * The object is made clean whatever the current status.
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object
	 * @return	void
	 */
	public function clean($oid, $object)
	{
		$this->_setObjectStatus($oid, $object, self::_STATUS_CLEAN);
	}
	
	/**
	 * Commit all operations to the storage engine
	 * 
	 * @return	void
	 */
	abstract protected function _commit();
	
	/**
	 * Clean up object collections
	 * 
	 * @return	void
	 */
	private function _cleanUp()
	{
		$this->_objects = array();
		$this->_objectsStatus = array();
		$this->_previousObjectsStatus = array();
	}
	
	/**
	 * Define the new status of an object
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object which status has to be set
	 * @param	string	$status		New status
	 * @return	void
	 */
	private function _setObjectStatus($oid, $object, $status)
	{
		$this->_previousObjectsStatus[$oid] = $this->_getObjectStatus($oid, $object);
		
		if($status === self::_STATUS_CLEAN)
		{
			unset($this->_objectsStatus[$oid]);
			unset($this->_objects[$oid]);
		}
		else
		{
			$this->_objectsStatus[$oid] = $status;
			$this->_objects[$oid] = $object;
		}
	}
	
	/**
	 * Return the current status of an object
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object
	 * @return	string
	 */
	private function _getObjectStatus($oid, $object)
	{
		if(!isset($this->_objectsStatus[$oid]))
		{
			return self::_STATUS_CLEAN;
		}
		 
		return $this->_objectsStatus[$oid];
	}
	
	/**
	 * Return the previous status of an object
	 * 
	 * @param	mixed	$oid		Object ID
	 * @param	object	$object		Object
	 * @return	string
	 */
	private function _getPreviousObjectStatus($oid, $object)
	{
		if(!isset($this->_previousObjectsStatus[$oid]))
		{
			return self::_STATUS_CLEAN;
		}
		 
		return $this->_previousObjectsStatus[$oid];
	}
}
Return current item: Spiral