Location: PHPKode > projects > ZooP Framework > zoop-1.5.0/db/dbobject.php
<?php
class DbObject implements Iterator
{
	protected $tableName;
	protected $primaryKey;
	protected $keyAssignedBy;
	private $missingKeyFields;
	private $bound;
	private $persisted;
	private $scalars;
	// private $krumoHack = array();
	
	const keyAssignedBy_db = 1;
	const keyAssignedBy_dev = 2;
	const keyAssignedBy_auto = 3;
	
	function __construct($init = NULL)
	{
		//	set up some sensible defaults
		$this->primaryKey = array('id');
		$this->tableName = $this->getDefaultTableName();
		$this->bound = false;
		$this->keyAssignedBy = self::keyAssignedBy_db;
		$this->scalars = array();
		$this->persisted = NULL;
		
		$this->init($init);
		
		$this->missingKeyFields = count($this->primaryKey);
		if($this->keyAssignedBy == self::keyAssignedBy_db && count($this->primaryKey) != 1)
			trigger_error("in order for 'keyAssignedBy_db' to work you must have a single primary key field");
		
		if(is_array($init))
		{
			$this->assignScalars($init);
		}
		else if($init === NULL)
		{
			return;
		}
		else
		{
			assert(count($this->primaryKey) == 1);
			$this->assignScalars(array($this->primaryKey), $init);
		}
	}
	
	//	second stage constructor
	protected function init()
	{
		//	override this function to setup relationships without having to handle the constructor chaining
	}
	
	private function getDefaultTableName()
	{
		$name = get_class($this);

		//      if there are any capitals after the firstone insert and underscore
		$name = $name[0] . preg_replace('/[A-Z]/', '_$0', substr($name, 1));

		//      lowercase everything and return it
		return strtolower($name);		
	}
	
	public function getTableName()
	{
		return $this->tableName;
	}
	
	public function getId()
	{
		assert(count($this->primaryKey) == 1);
		return $this->scalars[$this->primaryKey[0]];
	}
	
	public function getString()
	{
		$s = '';
		$this->loadScalars();
		foreach($this->scalars as $field => $value)
			$s .= " $field => $value";
		return get_class($this) . ':' . $s;
	}
		
	//
	//	the scalar handlers
	//
	//	rewrite them and make them handle primary keys with different names or more than one field
	//
		
	public function getFields()
	{
		return $this->scalars;
	}
	
	public function setFields($data)
	{
		$this->assignScalars($data);
	}
	
	private function getScalar($field)
	{
		if(!isset($this->scalars[$field]))
		{
			if(!$this->bound)
				trigger_error("the field: $field is not present in memory and this object is not yet bound to a database row");
			$this->loadScalars();
		}
		
		if(!isset($this->scalars[$field]))
			trigger_error("the field $field present neither in memory nor in the cooresponding database table");
		
		return $this->scalars[$field];
	}
	
	private function setScalar($field, $value)
	{
		$data[$field] = $value;
		$this->assignScalars($data);
	}
	
	/*
	private function setScalars($data)
	{
		foreach($data as $field => $value)
		{
			$this->scalars[$field] = $value;
		}
	}
	*/
	
	private function assignScalars($data)
	{
		foreach($data as $member => $value)
		{
			if(!isset($this->scalars[$member]) && in_array($member, $this->primaryKey))
			{
				$this->missingKeyFields--;
				if($this->missingKeyFields == 0)
					$this->bound = 1;
			}
			
			$this->scalars[$member] = $value;
		}
	}
	
	private function loadScalars()
	{
		assert($this->bound);
		$row = $this->fetchPersisted();
		$this->assignPersisted($row);
	}
	
	private function assignPersisted($row)
	{
		//	if they manually set a field don't write over it just because they loaded one scalar
		foreach($row as $field => $value)
		{
			if(!isset($this->scalars[$field]))
				$this->scalars[$field] = $value;
		}		
	}
	
	private function fetchPersisted()
	{
		$wheres = array();
		$whereValues = array();
		foreach($this->primaryKey as $keyField)
		{
			$wheres[] = "$keyField = :$keyField";
			$whereValues[$keyField] = $this->scalars[$keyField];
		}
		$whereClause = implode(' and ', $wheres);
		$row = self::_getConnection(get_class($this))->fetchRow("select * from $this->tableName where $whereClause", $whereValues);
		if($row)
			$this->persisted = true;
		else
			$this->persisted = false;
		return $row;
	}
	
	private function _persisted()
	{
		if(!$this->bound)
			return false;
		
		if($this->keyAssignedBy == self::keyAssignedBy_db)
			return true;
		else
		{
			$row = $this->fetchPersisted();
			if($row)
			{
				//	we might as well save the results
				$this->assignPersisted();
				return true;
			}
			
			return false;
		}
	}
	
	public function persisted()
	{
		if($this->persisted !== NULL)
			return $this->persisted;
		else
			return $this->persisted = $this->_persisted();
	}
	
	public function save()
	{
		if(!$this->bound)
		{
			if($this->keyAssignedBy == self::keyAssignedBy_db)
				$this->setScalar($this->primaryKey[0], self::_getConnection(get_class($this))->insertArray($this->tableName, $this->scalars));
			else
				trigger_error("you must define all foreign key fields in order by save this object");
		}
		else
		{
			if($this->keyAssignedBy == self::keyAssignedBy_db)
			{
				$updateInfo = DbConnection::generateUpdateInfo($this->tableName, $this->getKeyConditions(), $this->scalars);
				self::_getConnection(get_class($this))->updateRow($updateInfo['sql'], $updateInfo['params']);
			}
			else
			{
				if(!$this->persisted())
					self::_getConnection(get_class($this))->insertArray($this->tableName, $this->scalars, false);
				else
				{
					$updateInfo = DbConnection::generateUpdateInfo($this->tableName, $this->getKeyConditions(), $this->scalars);
					self::_getConnection(get_class($this))->updateRow($updateInfo['sql'], $updateInfo['params']);
				}
			}
		}
	}
	
	private function getKeyConditions()
	{
		assert($this->bound);
		return array_intersect_key($this->scalars, array_flip($this->primaryKey));
	}
	
	public function destroy()
	{
		$deleteInfo = DbConnection::generateDeleteInfo($this->tableName, $this->getKeyConditions());
		self::_getConnection(get_class($this))->deleteRow($deleteInfo['sql'], $deleteInfo['params']);
	}
	
	//
	//	end of scalar handlers
	//
	
	
	//
	//	vector handlers
	//
	/*
	protected function hasMany($name, $params = NULL)
	{
		if(isset($params['class']))
			$className = $params['class'];
		else
			$className = $name;
		
		if(isset($params['field']))
			$foreignKey = $params['field'];
		else
			$foreignKey = $this->getTableName() . '_id';
		
		$this->hasMany[$name] = array('className' => $className, 'foreignKey' => $foreignKey);
	}
	
	protected function getMany($name)
	{
		$className = $this->hasMany[$name]['className'];
		$foreignKey = $this->hasMany[$name]['foreignKey'];
		
		//	work around lack of "late static binding"
		$dummy = new $className(0);
		$tableName = $dummy->getTableName();
		
		$sql = "select * from $tableName where $foreignKey = :id";
		
		$rows = SqlFetchRows($sql, array('id' => $this->id));
		$objects = array();
		foreach($rows as $thisRow)
		{
			$objects[] = new $className($thisRow);
		}
		
		return $objects;
	}
	
	protected function belongsTo($name, $params = NULL)
	{
		//	determine the name of the class we belong to
		$className = isset($params['class']) ? $params['class'] : $name;
		
		$tableName = DbObject::_getTableName($className);
		
		//	get the name of the foreign key in this table
		$localKey = isset($params['key']) ? $params['key'] : $tableName . '_id';
		
		$this->belongsTo[$name] = array('className' => $className, 'localKey' => $localKey);
	}
	
	protected function getOwner($name)
	{
		$className = $this->belongsTo[$name]['className'];
		$localKey = $this->belongsTo[$name]['localKey'];
		$tableName = DbObject::_getTableName($className);
		return new $className($this->getScalar($localKey));
	}
	*/
	//
	//	end vector handlers
	//
	
	//
	//	begin magic functions
	//
	
	function __get($varname)
	{
		//	krumo hack
		// if(substr($varname, 0, 5) == 'krumo')
		// 	return isset($this->krumoHack[$varname]) ? $this->krumoHack[$varname] : NULL;
		
		/*
		if(isset($this->hasMany[$varname]))
			return $this->getMany($varname);
		
		if(isset($this->belongsTo[$varname]))
			return $this->getOwner($varname);
		*/
		return $this->getScalar($varname);
	}

	function __set($varname, $value)
	{
		//	krumo hack
		// if(substr($varname, 0, 5) == 'krumo')
		// 	$this->krumoHack[$varname] = $value;
		$this->setScalar($varname, $value);
	}
	
	//
	//	end magic functions
	//
	
	//
	//	begin iterator functions
	//
	
	public function rewind()
	{
		reset($this->scalars);
	}

	public function current()
	{
		$var = current($this->scalars);
		return $var;
	}

	public function key()
	{
		$var = key($this->scalars);
		return $var;
	}

	public function next()
	{
		$var = next($this->scalars);
		return $var;
	}

	public function valid()
	{
		$var = $this->current() !== false;
		return $var;
	}
	
	//
	//	end iterator functions
	//
	
	
	//
	//	static methods
	//
	
	static private function _getConnectionName($className)
	{
		return 'default';
	}
	
	static private function _getConnection($className)
	{
		return DbModule::getConnection(call_user_func(array($className, '_getConnectionName'), $className));
	}
	
	static private function _getTableName($className)
	{
		//	work around lack of "late static binding"
		$dummy = new $className();
		return $dummy->getTableName();
	}
	
	static public function _create($className, $values)
	{
		$object = new $className($values);
		$object->save();
		return $object;
	}
	
	static public function _insert($className, $values)
	{
		self::_getConnection($className)->insertArray(self::_getTableName($className), $values, false);			
	}
		
	static public function _findBySql($className, $sql, $params)
	{
		$res = self::_getConnection($className)->query($sql, $params);
		
		if(!$res->valid())
			return array();
		
		$objects = array();
		for($row = $res->current(); $res->valid(); $row = $res->next())
		{
			$objects[] = new $className($row);
		}
		
		return $objects;
	}
	
	static public function _findByWhere($className, $where, $params)
	{
		$tableName = DbObject::_getTableName($className);
		return self::_findBySql($className, "select * from $tableName where $where", $params);
	}
	
	static public function _find($className, $conditions = NULL)
	{
		$tableName = DbObject::_getTableName($className);
		if($conditions)
		{
			$selectInfo = self::_getConnection($className)->generateSelectInfo($tableName, '*', $conditions);
			$sql = $selectInfo['sql'];
			$params = $selectInfo['params'];
		}
		else
		{
			$sql = "select * from $tableName";
			$params = array();
		}
		
		return self::_findBySql($className, $sql, $params);
	}
	
	/**
	 * Retrieve one object from the database and map it to an object
	 * @param string $className The name of the class corresponding to the table in the database 
	 * @param array $conditions Key value pair for the fields you want to look up
	 * @return DbObject
	 */	
	
	static public function _findOne($className, $conditions = NULL)
	{
		$a = DbObject::_find($className, $conditions);
		if(!$a)
			return false;
		
		assert(is_array($a));
		assert(count($a) == 1);
		
		return current($a);
	}
	
	static public function _getOne($className, $conditions = NULL)
	{
		$tableName = DbObject::_getTableName($className);
		$row = self::_getConnection($className)->selsertRow($tableName, "*", $conditions);
		return new $className($row);
	}
	
	//
	//	end static methods
	//
}
Return current item: ZooP Framework