You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
5.2 KiB
198 lines
5.2 KiB
<?php
|
|
/**
|
|
* Base class for models
|
|
*
|
|
* @author Pavel Kulbakin <p.kulbakin@gmail.com>
|
|
*/
|
|
abstract class PMXE_Model extends ArrayObject {
|
|
/**
|
|
* WPDB instance
|
|
* @var wpdb
|
|
*/
|
|
protected $wpdb;
|
|
/**
|
|
* Table name the model is linked to
|
|
* @var string
|
|
*/
|
|
protected $table;
|
|
/**
|
|
* Array of columns representing primary key
|
|
* @var array
|
|
*/
|
|
protected $primary = array('id');
|
|
/**
|
|
* Wether key field is auto_increment (sure make scence only if key s
|
|
* @var bool
|
|
*/
|
|
protected $auto_increment = FALSE;
|
|
|
|
/**
|
|
* Cached data retrieved from database
|
|
* @var array
|
|
*/
|
|
private static $meta_cache = array();
|
|
|
|
/**
|
|
* Initialize model
|
|
* @param array[optional] $data Array of record data to initialize object with
|
|
*/
|
|
public function __construct() {
|
|
$this->wpdb = $GLOBALS['wpdb'];
|
|
}
|
|
|
|
/**
|
|
* Read records from database by specified fields and values
|
|
* When 1st parameter is an array, it expected to be an associative array of field => value pairs to read data by
|
|
* If 2 parameters are set, first one is expected to be a field name and second - it's value
|
|
*
|
|
* @param string|array $field
|
|
* @param mixed[optional] $value
|
|
* @return PMXE_Model
|
|
*/
|
|
abstract public function getBy($field = NULL, $value = NULL);
|
|
|
|
/**
|
|
* Magic function to automatically resolve calls like $obj->getBy%FIELD_NAME%
|
|
* @param string $method
|
|
* @param array $args
|
|
* @return PMXE_Model
|
|
*/
|
|
public function __call($method, $args) {
|
|
if (preg_match('%^get_?by_?(.+)%i', $method, $mtch)) {
|
|
array_unshift($args, $mtch[1]);
|
|
return call_user_func_array(array($this, 'getBy'), $args);
|
|
} else {
|
|
throw new Exception("Requested method " . get_class($this) . "::$method doesn't exist.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind model to database table
|
|
* @param string $tableName
|
|
* @return PMXE_Model
|
|
*/
|
|
public function setTable($tableName) {
|
|
if ( ! is_null($this->table)) {
|
|
throw new Exception('Table name cannot be changed once being set.');
|
|
}
|
|
$this->table = $tableName;
|
|
if ( ! isset(self::$meta_cache[$this->table])) {
|
|
$tableMeta = $this->wpdb->get_results("SHOW COLUMNS FROM $this->table", ARRAY_A);
|
|
$primary = array();
|
|
$auto_increment = false;
|
|
foreach ($tableMeta as $colMeta) {
|
|
if ('PRI' == $colMeta['Key']) {
|
|
$primary[] = $colMeta['Field'];
|
|
}
|
|
if ('auto_increment' == $colMeta['Extra']) {
|
|
$auto_increment = true;
|
|
break; // no point to iterate futher since auto_increment means corresponding primary key is simple
|
|
}
|
|
}
|
|
self::$meta_cache[$this->table] = array('primary' => $primary, 'auto_increment' => $auto_increment);
|
|
}
|
|
$this->primary = self::$meta_cache[$this->table]['primary'];
|
|
$this->auto_increment = self::$meta_cache[$this->table]['auto_increment'];
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return database table name this object is bound to
|
|
* @return string
|
|
*/
|
|
public function getTable() {
|
|
return $this->table;
|
|
}
|
|
/**
|
|
* Return column name with table name
|
|
* @param string $col
|
|
* @return string
|
|
*/
|
|
public function getFieldName($col) {
|
|
return $this->table . '.' . $col;
|
|
}
|
|
|
|
/**
|
|
* Compose WHERE clause based on parameters provided
|
|
* @param string|array $field
|
|
* @param mixed[optional] $value
|
|
* @param string[optional] $operator AND or OR string, 'AND' by default
|
|
* @return string
|
|
*/
|
|
protected function buildWhere($field, $value = NULL, $operator = NULL) {
|
|
if ( ! is_array($field)) {
|
|
$field = array($field => $value);
|
|
} else { // shift arguments
|
|
$operator = $value;
|
|
}
|
|
! is_null($operator) or $operator = 'AND'; // apply default operator value
|
|
|
|
$where = array();
|
|
foreach ($field as $key => $val) {
|
|
if (is_int($key)) {
|
|
$where[] = '(' . call_user_func_array(array($this, 'buildWhere'), $val) . ')';
|
|
} else {
|
|
if ( ! preg_match('%^(.+?) *(=|<>|!=|<|>|<=|>=| (NOT +)?(IN|(LIKE|REGEXP|RLIKE)( BINARY)?))?$%i', trim($key), $mtch)) {
|
|
throw new Exception('Wrong field name format.');
|
|
}
|
|
$key = $mtch[1];
|
|
if (is_array($val) and (empty($mtch[2]) or 'IN' == strtoupper($mtch[4]))) {
|
|
$op = empty($mtch[2]) ? 'IN' : strtoupper(trim($mtch[2]));
|
|
if (count($val)) $where[] = $this->wpdb->prepare("$key $op (" . implode(', ', array_fill(0, count($val), "%s")) . ")", $val);
|
|
} else {
|
|
$op = empty($mtch[2]) ? '=' : strtoupper(trim($mtch[2]));
|
|
$where[] = $this->wpdb->prepare("$key $op %s", $val);
|
|
}
|
|
}
|
|
}
|
|
return implode(" $operator ", $where);
|
|
}
|
|
|
|
|
|
/**
|
|
* Return associative array with record data
|
|
* @param bool[optional] $serialize Whether returned fields should be serialized
|
|
* @return array
|
|
*/
|
|
public function toArray($serialize = FALSE) {
|
|
$result = (array)$this;
|
|
if ($serialize) {
|
|
foreach ($result as $k => $v) {
|
|
if ( ! is_scalar($v)) {
|
|
$result[$k] = serialize($v);
|
|
}
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Check whether object data is empty
|
|
* @return bool
|
|
*/
|
|
public function isEmpty() {
|
|
return $this->count() == 0;
|
|
}
|
|
|
|
/**
|
|
* Empty object data
|
|
* @return PMXE_Model
|
|
*/
|
|
public function clear() {
|
|
$this->exchangeArray(array());
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Delete all content from model's table
|
|
* @return PMXE_Model
|
|
*/
|
|
public function truncateTable() {
|
|
if (FALSE !== $this->wpdb->query("TRUNCATE $this->table")) {
|
|
return $this;
|
|
} else {
|
|
throw new Exception($this->wpdb->last_error);
|
|
}
|
|
}
|
|
} |