All pastes #581520 Raw Edit

k4st

public php v1 · immutable
·published 2007-06-21 15:43 UTC
rendered paste body
<?php/** * $header * @copyright Copyright 2007, Peter Goodman * @package valkyrie * @subpackage Database.activerecord * @author Peter Goodman */if(!defined('IN_VALKYRIE')) {	exit;}/** * A decorator class for an individual row in the database. This class extends * VK_Overload. */class Record extends VK_Overload {		/**	 * A reference to the database abstraction layer	 * @see Database	 * @internal	 */	protected $dba;		/**	 * A reference to this table's model definition	 * @see ModelDefinition	 * @internal	 */	private $model;		/**	 * A boolean of whether or not this row/record exists in the database yet.	 * @internal	 */	private $saved = FALSE;		/**	 * An array holding saved data from the database. If a database row for this	 * record does not exist, this array will be empty.	 * @internal	 */	private $data = array();		/**	 * An array of all user-set values to this table row that don't exist in the database	 * yet and haven't been validated.	 * @internal	 */	private $dirty = array();		/**	 * A cache of the return values of getter functions in this class. all functions prefixed	 * by 'get' are available to the template engine via {$record.func_name} (refers to getFuncName)	 * @internal	 */	private $cache = array();		/**	 * Constructor, bring in references to the database abstraction layer, model definition, and an	 * array of saved data. If that array is empty, then Record::$saved will remain false.	 * @param array $data An array containing initial saved data (if the row is saved).	 * @param mixed $dba A reference to the database abstractin layer.	 * @param mixed $model A reference to the model definition for this database table.	 * @see Database, ModelDefinition	 * @internal	 */	final public function __construct(array $data = array(), DatabaseDriver $dba, ModelDefinition $model) {		$this->dba = $dba;		$this->model = $model;				if(!empty($data)) {			$this->saved = TRUE;		}				$this->data = $data;	}		/**	 * Get the value of a row from the record. First it will look in the dirty array, then the data (saved)	 * array, then the cache from functions, then it will check if a $key 'func_name' function exists as 	 * 'getFuncName', and if so, cache that result.	 * @param string $key The table column name or cache result to get.	 * @return mixed	 * @see VK_Overload	 * @see Record::__set(), Record::__isset(), Record::__unset()	 */	final public function __get($key = '') {		$ret = NULL;				// dirty first, important		if(isset($this->dirty[$key])) {			$ret = $this->dirty[$key];		} else if(isset($this->data[$key])) {			$ret = $this->data[$key];		} else if(isset($this->cache[$key])) {			$ret = $this->cache[$key];		} else {			$method_name = 'get'. camelize($key);			if(method_exists($this, $method_name)) {				$this->cache[$key] = $this->$method_name();				$ret = $this->cache[$key];			}		}				return $ret;	}		/**	 * Set a value to the array of dirty data.	 * @param string $key The key (column name) to set the the dirty array	 * @param string $val The value to set the the dirty array for this column	 * @see VK_Overload	 * @see Record::__get(), Record::__isset(), Record::__unset()	 */	final public function __set($key = '', $val) {		$this->dirty[$key] = $val;	}		/**	 * Check if a value for a column name exists	 * @param string $key The key (column name) check	 * @see VK_Overload	 * @see Record::__get(), Record::__set(), Record::__unset()	 */	final public function __isset($key = '') {		return isset($this->dirty[$key]) || isset($this->data[$key]) || isset($this->cache[$key]);	}		/**	 * Unset the value for a column name	 * @param string $key The key (column name) to unset	 * @see VK_Overload	 * @see Record::__get(), Record::__set(), Record::__isset()	 */	final public function __unset($key = '') {		unset($this->dirty[$key], $this->data[$key]);	}		/**	 * Overrideable function (in custom record classes) to execute before a record is	 * saved. This is particularly useful if you want to do any sort of operations on the	 * values of columns before saving, eg: special validation/cleaning.	 */	public function preSave() { }		/**	 * Overrideable function (in custom record classes) to execute after a record has	 * been saved. I haven't thought of a use case for this, but because preSave exists,	 * I thought: "why not postSave?", and so it is here.	 */	public function postSave() { }		/**	 * Save a record to the database. If the record already exists in the database, then this	 * will perform an UPDATE query, otherwise it will perform an INSERT query.	 */	final public function save() {		$this->preSave();				$insert_vals = array();				$keys = array_keys($this->dirty);		$vals = array_values($this->dirty);				// validate the dirty things against the model		$this->model->validate($keys, $vals);				// update		if($this->saved) {			$sql = 'UPDATE '. $this->model->table['name'] .' SET ';						$sep = '';			foreach($keys as $key) {				$sql .= $sep . $key .'=?';				$sep = ',';			}						$this->dba->update($sql, $vals);				// insert, same as Finder::insertOne		} else {			$this->dba->update($this->dba->buildInsert($this->model->table['name'], $keys, $vals), $vals);		}				if($this->model->primary !== NULL) {			$this->data[$this->model->primary] = $this->dba->insertId();		}					$this->saved = TRUE;		$this->data = array_merge($this->data, $this->dirty);		$this->dirty = array();				$this->postSave();				return TRUE;	}		/**	 * Delete a record from the database if it exists there already.	 */	final public function delete() {		if($this->saved) {			if($this->model->primary !== NULL) {				$this->dba->update('DELETE FROM '. $this->model->table['name'] .' WHERE '. $this->model->primary .'=?', array($this->data[$this->model->primary]));			} else {				// hrm.			}		}	}}/** * A class it iterate over a result set. Each iteration will return a Record * decorator class for the row. This class extends IteratorIterator because the * database result sets passed in implement Iterator. * @see Record, IteratorIterator, DatabaseResultSet */class RecordSet extends IteratorIterator {		/**	 * A reference to the current database abstraction layer	 * @see Database	 * @internal	 */	private $dba;		/**	 * A reference to this tables model definition	 * @see ModelDefinition	 * @internal	 */	private $model;		/**	 * An array of cached record classes. The record classes are cached because	 * if one decides to iterate over this result set multiple times then each	 * time we want to return to them the same record class for each database row.	 * @internal	 */	private $cache = array();		/**	 * Constructor, bring in the result set, the database layer and the model definition.	 * @param mixed $result A reference to a DatabaseResultSet	 * @param mixed $dba A reference to the current database abstraction layer	 * @param mixed $model A reference to the this tables model definition	 * @see DatabaseResultSet, Database, ModelDefinition	 * @internal	 */	final public function __construct(DatabaseResultSet $result, DatabaseDriver $dba, ModelDefinition $model) {		$this->dba = $dba;		$this->model = $model;		$this->iterator = $result;	}		/**	 * The current function of the iterator, called in each loop. This function returns	 * a cached version of the Record decorator class for the current row in the database	 * result set.	 * @return mixed A cached instance of Record	 * @see Record	 * @internal	 */	final public function current() {				if(!isset($this->cache[$this->key()])) {			$record = camelize($model->table['name']) .'Record';			$this->cache[$this->key()] = new $record($this->iterator->current(), $this->dba, $this->model);		}				return $this->cache[$this->key()];	}		/**	 * Return the number of rows in the internal result set	 * @see DatabaseResultSet::numRows()	 */	final public function numRows() {		return $this->iterator->numRows();	}}