TransactionManager

<?php require_once "autoload.php";

class TransactionManager extends Bean
{
	private static $instance;

	public static function getInstance()
	{
		if (!isset(self::$instance))
		{
			$c = __CLASS__;
			self::$instance = new $c;
		}
		return self::$instance;
	}

	protected $txStack;

	public function __construct()
	{
		$pm = PersistenceManager::getInstance();
		$this->txStack = $pm->load("TX_STACK");
		if (!$this->txStack)
			$this->txStack = array();
	}


	public function persist()
	{
		$ret = false;
		
		$pm = PersistenceManager::getInstance();
		$pm->save("TX_STACK", $this->txStack);
		
		$ret = true;
		return $ret;
	}
	
	public function push($item)
	{
		$tx = end($this->txStack);
		if ($tx)
		{
			$ret = $tx->push($item);
			$this->persist();
		}
		
		return $ret;
	}
	
	public function pop()
	{
		$tx = $this->topTx();
		if (!$tx)
			return null;
		
		while ($tx && !$tx->count())
		{
			$tx = $this->popTx();
			$tx = $this->topTx();
		}		

		if (!$tx)
			return null;

		$tx = $this->topTx();
		$item = $tx->pop();
		while ($tx && !$tx->count())
		{
			$tx = $this->popTx();
			$tx = $this->topTx();
		}		

		$this->persist();
		
		return $item;
	}	
	
	/*cutTo trips the stack to the $item.  Only defined for use within one transaction.  Cutting 
	to an item outside the current transaction scope crashes.
	*/
	public function cutTo($item)
	{
		
		$ret;
		$topTx = $this->topTx();
		do{
		$ret = $topTx->pop();
		$model = $ret->get("model");
	//	echo "comparision<br>".print_r($item,true)."<br>to".print_r($model["path"],true);
		}
		while($item != $model["path"] & $topTx->top());
		$topTx->push($ret);
		return $ret;
		
	}
	public function top()
	{
		$ret = null;
		do
		{	
			$tx = end($this->txStack);
			if (!$tx)
				break;
				
			$ret = $tx->top();
		} while (false);
		
		return $ret;
	}

	public function topTx()
	{
		return end($this->txStack);
	}
	
	public function popTx()
	{
		return array_pop($this->txStack);
	}
	
	public function pushTx($tx)
	{
		$this->txStack[] = $tx;
	}
	
	public function start(&$tx)
	{
		$ret = false;


		$x = $this->topTx();
		if ($x && (get_class($x) == get_class($tx)))
		{
			return $this->top()->view();
		}

		$this->txStack[] = $tx;
		$this->persist();
		
		$ret = $tx->start();
		
		return $ret;
	}
	
	public function endPassive()
	{
		$ret = true;
		
		$tx = array_pop($this->txStack);
		$this->persist();
		
		$ret &= $tx->end();
		$tx = end($this->txStack);
		
		return true;
	}
	public function end()
	{
		$ret = true;
		
		$tx = array_pop($this->txStack);
		$this->persist();
		
		$ret &= $tx->end();
		$tx = end($this->txStack);

		$item = $tx->pop();
		$ret = $item->view();
		
		return $ret;
	}
}

Bean

<?php include_once "autoload.php";

abstract class Bean
{
	public function set($field, &$value) { $this->$field = $value; }
	public function &get($field) { return $this->$field; }

	public function __construct()
	{
	}

	public function map_to_vars(&$map)
	{
		foreach (array_keys(get_object_vars($this)) as $key)
		{
			$this->$key = $map[$key];
		}
	}
}
?>