array(TYPE, REQUIRED, VERIFY METHOD (:self for self-named method)) * @var array */ var $fields = array(); /** * Values array: sanitized and verified field values * @var array */ var $values = array(); /** * Fields that were manually set with set(), not by using set_existing() * @var array */ var $setfields = array(); /** * WHERE condition * @var string */ var $condition = ''; /** * The object table row; a fetched row that represents this instance * @var array */ var $objdata = array(); /** * Insert ID from the insert() command * @var integer */ var $insertid = 0; /** * Pre- and post-action method stoppers * @var array */ var $norunners = array(); // ################################################################### /** * Constructor: cannot instantiate class directly */ function __construct(&$registry) { if (!is_subclass_of($this, 'API')) { trigger_error('Cannot instantiate the API module directly', E_USER_ERROR); } if (!is_object($registry)) { trigger_error('The passed registry is not an object', E_USER_ERROR); } $this->registry =& $registry; } // ################################################################### /** * (PHP 4) Constructor */ function API(&$registry) { $this->__construct($registry); } // ################################################################### /** * Constructs an error for the error handler to receive * * @access protected * * @param string Error message */ function error($message) { call_user_func(APIError(), $message); } // ################################################################### /** * Sets a value, sanitizes it, and verifies it * * @access public * * @param string Field name * @param mixed Value * @param bool Do clean? * @param bool Do verify? */ function set($field, $value, $doclean = true, $doverify = true) { if (!isset($this->fields["$field"])) { trigger_error('Field `' . $field . '` is not valid', E_USER_WARNING); return; } $this->values["$field"] = ($doclean ? $this->registry->clean($value, $this->fields["$field"][F_TYPE]) : $value); $this->setfields["$field"] = $field; if (isset($this->fields["$field"][F_VERIFY]) AND $doverify) { if ($this->fields["$field"][F_VERIFY] == ':self') { $verify = $this->{"verify_$field"}($field); } else { $verify = $this->{$this->fields["$field"][F_VERIFY]}($field); } if (!$verify) { $this->error(sprintf($this->registry->modules['localize']->string('Validation of %1$s failed'), $field)); } } } // ################################################################### /** * Sets the condition to use in the WHERE clause; if not passed, then * it calculates it from the REQ_AUTO field * * @access public * * @param string WHERE conditional bit */ function set_condition($condition = '') { if ($condition != '') { $this->condition = $condition; } else { foreach ($this->fields AS $name => $options) { if ($options[F_REQ] == REQ_AUTO) { if (!$this->values["$name"]) { trigger_error('Cannot determine condition from the REQ_AUTO field because it is not set', E_USER_WARNING); continue; } $this->condition = "$name = " . $this->prepare_field_for_sql($name); } } if ($this->condition == '') { trigger_error('No REQ_AUTO fields are present and therefore the condition cannot be created', E_USER_WARNING); } } } // ################################################################### /** * Sets existing data into $values where it's not already present * * @access public */ function set_existing() { static $run; if ($run) { return; } $this->fetch(); foreach ($this->objdata AS $field => $value) { if (!isset($this->values["$field"])) { $this->values["$field"] = $value; } } $run = true; } // ################################################################### /** * Fetches a record based on the condition * * @access public */ function fetch() { if ($this->condition == '') { trigger_error('Condition is empty: cannot fetch', E_USER_ERROR); } $this->run_action_method('pre_fetch'); $result = $this->registry->modules['db_mysql']->query_first("SELECT * FROM {$this->prefix}{$this->table} WHERE {$this->condition}"); if (!$result) { $this->error($this->registry->modules['localize']->string('No records were returned')); return; } $this->run_action_method('post_fetch'); $this->objdata = $result; } // ################################################################### /** * Inserts a record in the database * * @access public */ function insert() { $this->verify(); $this->run_action_method('pre_insert'); foreach ($this->setfields AS $field) { $fields[] = $field; $values[] = $this->prepare_field_for_sql($field); } $this->registry->modules['db_mysql']->query("INSERT INTO {$this->prefix}{$this->table} (" . implode(',', $fields) . ") VALUES (" . implode(',', $values) . ")"); $this->insertid = $this->registry->modules['db_mysql']->insert_id(); $this->run_action_method('post_insert'); } // ################################################################### /** * Updates a record in the database using the data in $vaues * * @access public */ function update() { if ($this->condition == '') { trigger_error('Condition is empty: cannot fetch', E_USER_ERROR); } $this->run_action_method('pre_update'); foreach ($this->setfields AS $field) { $updates[] = "$field = " . $this->prepare_field_for_sql($field); } $updates = implode(', ', $updates); $this->registry->modules['db_mysql']->query("UPDATE {$this->prefix}{$this->table} SET $updates WHERE {$this->condition}"); $this->run_action_method('post_update'); } // ################################################################### /** * Deletes a record * * @access public */ function delete() { if ($this->condition == '') { trigger_error('Condition is empty: cannot fetch', E_USER_ERROR); } $this->set_existing(); $this->run_action_method('pre_delete'); $this->registry->modules['db_mysql']->query("DELETE FROM {$this->prefix}{$this->table} WHERE {$this->condition}"); $this->run_action_method('post_delete'); } // ################################################################### /** * Verifies that all required fields are set * * @access private */ function verify() { foreach ($this->fields AS $name => $options) { if ($options[F_REQ] == REQ_YES) { if (!isset($this->values["$name"])) { $this->error(sprintf($this->registry->modules['localize']->string('Required field %1$s was not set'), $name)); } } else if ($options[F_REQ] == REQ_SET) { $this->{"set_$name"}(); } } } // ################################################################### /** * Runs a pre- or post-action method for database commands * * @access private * * @param string Action to run */ function run_action_method($method) { if (in_array($method, $this->norunners)) { return; } $actmethod = (method_exists($this, $method) ? $this->$method() : ''); } // ################################################################### /** * Prepares a value for use in a SQL query; it encases and escapes * strings and string-like values * * @access private * * @param string Field name * * @return string Prepared value entry */ function prepare_field_for_sql($name) { $type = $this->fields["$name"][F_TYPE]; if ($type == TYPE_NOCLEAN OR $type == TYPE_STR OR $type == TYPE_STRUN) { return "'" . $this->registry->escape($this->values["$name"]) . "'"; } else if ($type == TYPE_BOOL) { return (int)$this->values["$name"]; } else { return $this->values["$name"]; } } // ################################################################### /** * Verify field: not a zero value * * @access protected */ function verify_nozero($field) { if ($this->values["$field"] == 0) { return false; } return true; } // ################################################################### /** * Verify field: not empty * * @access protected */ function verify_noempty($field) { if (empty($this->values["$field"])) { return false; } return true; } } // ################################################################### /** * Setter and getter method for the API error reporting system. Passing * a name will cause the set, no arguments will cause the get. * * @access public * * @param mixed Method name in callable form * * @return mixed Method name in callable form */ function APIError($new = null) { static $caller; if ($new !== null) { $caller = $new; } return $caller; } /*=====================================================================*\ || ################################################################### || # $HeadURL$ || # $Id$ || ################################################################### \*=====================================================================*/ ?>