📄 dataobject.class.php
字号:
<?php /** * Data object class * * This class enables easy implementation of any object that is based * on single database row. It enables reading, updating, inserting and * deleting that row without writing any SQL. Also, it can chack if * specific row exists in database. * * This class supports PKs over multiple fields * * @package System * @version 1.0.1 * @http://www.projectpier.org/ * */ abstract class DataObject { /** * Indicates if this is new object (not saved) * * @var boolean */ private $is_new = true; /** * Indicates if this object have been deleted from database * * @var boolean */ private $is_deleted = false; /** * Object is loaded * * @var boolean */ private $is_loaded = false; /** * Cached column values * * @var array */ private $column_values = array(); /** * Array of modified columns (if any) * * @var array */ private $modified_columns = array(); /** * Array of updated primary key columns with cached old values (used in WHERE clausule on update or delete) * * @var array */ private $updated_pks = array(); /** * Manager object instance * * @var DataManager */ protected $manager; /** * Array of protected attributes that can not be set through mass-assignment functions (like setFromAttributes) * * One of the great ActiveRecord tricks * * @var array */ protected $attr_protected = array('id', 'created_on', 'created_by_id', 'updated_on', 'updated_by_id'); /** * Array of acceptable attributes (fields) that can be set through mass-assignment function (setFromAttributes) * * One of the great ActiveRecord tricks * * @var array */ protected $attr_acceptable = null; /** * Constructor * * @param void * @return null */ function __construct() { // Empty... } // __construct // ---------------------------------------------------------- // Abstract function // ---------------------------------------------------------- /** * Return object manager * * @access public * @param void * @return DataManager */ abstract function manager(); /** * Validate input data (usualy collected from from). This method is called * before the item is saved and can be used to fetch errors in data before * we really save it database. $errors array is populated with errors * * @access public * @param array $errors * @return boolean * @throws ModelValidationError */ function validate($errors) { return true; } // validate /** * Set object attributes / properties. This function will take hash and set * value of all fields that she finds in the hash * * @access public * @param array $attributes * @return null */ function setFromAttributes($attributes) { if (is_array($attributes)) { foreach ($attributes as $k => &$v) { if (is_array($this->attr_protected) && in_array($k, $this->attr_protected)) { continue; // protected attribute } // if if (is_array($this->attr_acceptable) && !in_array($k, $this->attr_acceptable)) { continue; // not acceptable } // if if ($this->columnExists($k)) { $this->setColumnValue($k, $attributes[$k]); // column exists, set } // if } // foreach } // if } // setFromAttributes /** * Return table name * * @access public * @param boolean $escape Escape table name * @return boolean */ function getTableName($escape = false) { return $this->manager()->getTableName($escape); } // getTableName /** * Return array of columns * * @access public * @param void * @return array */ function getColumns() { return $this->manager()->getColumns(); } // getColumns /** * Check if specific column exists in this object * * @access public * @param string $column_name * @return boolean */ function columnExists($column_name) { return in_array($column_name, $this->getColumns()); } // columnExists /** * Return type of specific column * * @access public * @param string $column_name * @return string */ function getColumnType($column_name) { return $this->manager()->getColumnType($column_name); } // getColumnType /** * Return name of Primary key column (or array of columns) * * @access public * @param void * @return string or array */ function getPkColumns() { return $this->manager()->getPkColumns(); } // getPkColumns /** * Check if specific column is part of the primary key * * @access public * @param string $column Column that need to be checked * @return boolean */ function isPrimaryKeyColumn($column) { // Get primary key column name or array of column names that // make PK here $pks = $this->getPkColumns(); // Check... if (is_array($pks)) { return in_array($column, $pks); } else { return $column == $pks; } // if } // isPrimaryKeyColumn /** * Check if this column is PK and if it is modified * * @access public * @param string $column * @return boolean */ function isModifiedPrimaryKeyColumn($column) { // Check if we have modified column... if ($this->isPrimaryKeyColumn($column)) { return isset($this->modified_columns[$column]); } // if // Selected column is not PK column return false; } // isModifiedPrimaryKeyColumn /** * Return value of PK colum(s) that was initaly loaded (it will * load old values of PK columns that was modified) * * @access public * @param void * @return array or mixed */ function getInitialPkValue() { // Get primary key column, name... $pks = $this->getPkColumns(); // If we have multiple PKs get values and return as array // else, return as scalar if (is_array($pks)) { // Prepare result $ret = array(); // Loop primary keys and get values... foreach ($pks as $column) { $ret[$column] = $this->isModifiedPrimaryKeyColumn($column) ? $this->modified_columns[$column] : $this->getColumnValue($column); } // foreach // Return result return $ret; } else { return $this->isModifiedPrimaryKeyColumn($pks) ? $this->modified_columns[$pks] : $this->getColumnValue($pks); } // if } // getInitialPkValue /** * Return auto increment column if exists * * @access public * @param void * @return string */ function getAutoIncrementColumn() { return $this->manager()->getAutoIncrementColumn(); } // getAutoIncrementColumn /** * Return auto increment column * * @access public * @param string $column * @return boolean */ function isAutoIncrementColumn($column) { return $this->getAutoIncrementColumn() == $column; } // isAutoIncrementColumn /** * Return lazy load columns if there are lazy load columns * * @access public * @param void * @return array */ function getLazyLoadColumns() { return $this->manager()->getLazyLoadColumns(); } // getLazyLoadColumns /** * Check if specific column is lazy load * * @access public * @param string $column * @return boolean */ function isLazyLoadColumn($column) { $lazy_load = $this->getLazyLoadColumns(); if (is_array($lazy_load)) { return in_array($column, $lazy_load); } // if return false; } // isLazyLoadColumn /** * Return value of specific column * * @access public * @param string $column_name * @param mixed $default * @return mixed */ function getColumnValue($column_name, $default = null) { // Do we have it cached? if (isset($this->column_values[$column_name])) { return $this->column_values[$column_name]; } // if // We don't have it cached. Exists? if (!$this->columnExists($column_name) && $this->isLazyLoadColumn($column_name)) { return $this->loadLazyLoadColumnValue($column_name, $default); } // if // Failed to load column or column DNX return $default; } // getColumnValue /** * Set specific field value * * @access public * @param string $field Field name * @param mixed $value New field value * @return boolean */ function setColumnValue($column, $value) { // Field defined if (!$this->columnExists($column)) return false; // Get type... $coverted_value = $this->rawToPHP($value, $this->getColumnType($column)); $old_value = $this->getColumnValue($column); // Do we have modified value? if ($this->isNew() || ($old_value <> $coverted_value)) { // Set the value and report modification $this->column_values[$column] = $coverted_value; $this->addModifiedColumn($column); // Save primary key value. Also make sure that only the first PK value is // saved as old. Not to save second value on third modification ;) if ($this->isPrimaryKeyColumn($column) && !isset($this->updated_pks[$column])) { $this->updated_pks[$column] = $old_value; } // if } // if // Set! return true; } // setColumnValue // ------------------------------------------------------------- // Top level manipulation methods // ------------------------------------------------------------- /** * Save object into database (insert or update) * * @access public * @param void * @return boolean * @throws DBQueryError * @throws DAOValidationError */ function save() { $errors = $this->doValidate(); if (is_array($errors)) { throw new DAOValidationError($this, $errors); } // if return $this->doSave(); } // save /** * Delete specific object (and related objects if neccecery) * * @access public * @param void * @return boolean * @throws DBQueryError */ function delete() { if ($this->isNew() || $this->isDeleted()) { return false; } // if if ($this->doDelete()) { $this->setDeleted(true); $this->setLoaded(false); return true; } else { return false; } // if } // delete // ------------------------------------------------------------- // Loader methods // ------------------------------------------------------------- /** * Load data from database row * * @access public * @param array $row Database row * @return boolean */ function loadFromRow($row) { //if (isset($row['assigned_to_user_id'])) { // pre_var_dump($this->columnExists('assigned_to_user_id')); // pre_var_dump($row); //} // Check input array... if (is_array($row)) { // Loop fiedls... foreach ($row as $k => $v) { // If key exists set value if ($this->columnExists($k)) { $this->setColumnValue($k, $v); } // if } // foreach // Prepare stamps... $this->setLoaded(true); $this->notModified(); // Job well done... return true; } // if // Error... return false; } // loadFromRow /** * Load lazy load column value * * @access private * @param string $column_name * @param mixed $default * @return mixed */ private function loadLazyLoadColumnValue($column_name, $default = null) { return $default; } // loadLazyLoadColumnValue /** * Check if specific row exists in database * * @access public * @param mixed $value Primay key value that need to be checked * @return boolean */ private function rowExists($value) { // Don't do COUNT(*) if we have one PK column $escaped_pk = is_array($pk_columns = $this->getPkColumns()) ? '*' : DB::escapeField($pk_columns); $sql = "SELECT count($escaped_pk) AS 'row_count' FROM " . $this->getTableName(true) . " WHERE " . $this->manager()->getConditionsById($value); $row = DB::executeOne($sql); return (boolean) array_var($row, 'row_count', false); } // rowExists /** * This function will call validate() method and handle errors * * @access public * @param void * @return array or NULL if there are no errors */ private function doValidate() { // Prepare errors array and call validate() method $errors = array(); $this->validate($errors); // If we have errors return them as array, else return NULL return count($errors) ? $errors : null; } // doValidate /** * Save data into database * * @access public * @param void * @return integer or false */ private function doSave() { // Do we need to insert data or we need to save it... if ($this->isNew()) { // Lets check if we have created_on and updated_on columns and they are empty if ($this->columnExists('created_on') && !$this->isColumnModified('created_on')) { $this->setColumnValue('created_on', DateTimeValueLib::now()); } // if if ($this->columnExists('updated_on') && !$this->isColumnModified('updated_on')) { $this->setColumnValue('updated_on', DateTimeValueLib::now()); } // if if (function_exists('logged_user') && (logged_user() instanceof User)) { if ($this->columnExists('created_by_id') && !$this->isColumnModified('created_by_id') && (logged_user() instanceof User)) { $this->setColumnValue('created_by_id', logged_user()->getId()); } // if if ($this->columnExists('updated_by_id') && !$this->isColumnModified('updated_by_id')) { $this->setColumnValue('updated_by_id', logged_user()->getId()); } // if } // if // Get auto increment column name $autoincrement_column = $this->getAutoIncrementColumn(); $autoincrement_column_modified = $this->columnExists($autoincrement_column) && $this->isColumnModified($autoincrement_column); // Get SQL $sql = $this->getInsertQuery(); if (!DB::execute($this->getInsertQuery())) { return false; } // if // If we have autoincrement field load it... if (!$autoincrement_column_modified && $this->columnExists($autoincrement_column)) { $this->setColumnValue($autoincrement_column, DB::lastInsertId()); } // if // Loaded... $this->setLoaded(true); // Done... return true; // Update... } else { // Set value of updated_on column... if ($this->columnExists('updated_on') && !$this->isColumnModified('updated_on')) { $this->setColumnValue('updated_on', DateTimeValueLib::now()); } // if if (function_exists('logged_user') && (logged_user() instanceof User)) { if ($this->columnExists('updated_by_id') && !$this->isColumnModified('updated_by_id')) { $this->setColumnValue('updated_by_id', logged_user()->getId()); } // if } // if // Get update SQL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -