348 lines
9.6 KiB
PHP
348 lines
9.6 KiB
PHP
<?php
|
||
|
||
/*
|
||
|
||
Пример работы:
|
||
|
||
class User extends Model
|
||
{
|
||
function __construct($fromArray = array())
|
||
{
|
||
$this->_tableName_ = 'Users';
|
||
parent::__construct($fromArray);
|
||
}
|
||
|
||
static function model()
|
||
{
|
||
return new self();
|
||
}
|
||
}
|
||
|
||
Просто новый пользователь:
|
||
new User();
|
||
|
||
Новый пользователь из массива данных:
|
||
new User(array('ID'=>12, 'Name'=>'John', 'Fname'=>'Doe'));
|
||
|
||
Берём пользователя по ID:
|
||
User::model()->getByPK(2);
|
||
|
||
Всех пользователей:
|
||
User::model()->getAll()
|
||
|
||
Или всех пользователей с параметрами:
|
||
User::model()->getAll(array('where'=>'`ID` > 5', 'order'=>'`Name` ASC'))
|
||
|
||
*/
|
||
|
||
abstract class Model
|
||
{
|
||
|
||
// Relations
|
||
const TO_ONE = 'TO_ONE';
|
||
const TO_MANY = 'TO_MANY';
|
||
|
||
private $_primaryKey_;
|
||
protected $_tableName_;
|
||
private $_id_;
|
||
private $_vals_ = array();
|
||
protected $_relations_ = array();
|
||
|
||
function __construct($fromArray = array())
|
||
{
|
||
$this->_primaryKey_ = $this->getPk();
|
||
|
||
if ($fromArray) {
|
||
$this->setValues($fromArray);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* TODO: Проверять, есть ли такие поля в БД.
|
||
* @param type $name
|
||
* @param type $value
|
||
*/
|
||
function __set($name, $value)
|
||
{
|
||
$this->_vals_[$name] = $value;
|
||
|
||
if ($name == $this->_primaryKey_) {
|
||
$this->_id_ = $value;
|
||
}
|
||
}
|
||
|
||
function __get($name)
|
||
{
|
||
if (isset($this->_vals_[$name])) {
|
||
return $this->_vals_[$name];
|
||
} else {
|
||
if (isset($this->_relations_[$name])) {
|
||
extract($this->_relations_[$name]);
|
||
$model = new $targetModel;
|
||
|
||
switch ($relationType) {
|
||
case self::TO_ONE:
|
||
return $model::model()->getOne($targetField, $this->$localField);
|
||
break;
|
||
case self::TO_MANY:
|
||
return $model::model()->getAll(array('where' => "`$targetField` = '" . $this->$localField . "'"));
|
||
break;
|
||
default:
|
||
throw new Exception('Undefined relation type');
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Получаем Primary Key
|
||
* @return type
|
||
*/
|
||
private function getPk()
|
||
{
|
||
$res = App::DB()->query("SHOW KEYS FROM " . $this->_tableName_ . " WHERE Key_name = 'PRIMARY'")->fetch(PDO::FETCH_ASSOC);
|
||
return $res["Column_name"];
|
||
}
|
||
|
||
/**
|
||
* Устанавливает отношение с другой таблицей
|
||
* @param string $nameOfRelation - название отношения. В дальнейшем по этому имени будт происходить обращение.
|
||
* @param string $localField - локальные данные по которым происходит связывание.
|
||
* @param string $targetModel - имя внешней модели (с которой хотим связаться).
|
||
* @param string $targetField - имя поля в удалённой таблице.
|
||
* @param const $relationType - тип связи (к одному / ко многим).
|
||
* @return obkect/array
|
||
*/
|
||
public function setRelation($nameOfRelation, $localField, $targetModel, $targetField, $relationType)
|
||
{
|
||
return $this->_relations_[$nameOfRelation] = array(
|
||
'localField' => $localField,
|
||
'targetModel' => $targetModel,
|
||
'targetField' => $targetField,
|
||
'relationType' => $relationType,
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Возвращает объект - запись в БД.
|
||
* @param int $id
|
||
* @return \Model
|
||
*/
|
||
function getByPK($id)
|
||
{
|
||
$this->_vals_ = App::DB()->query('SELECT * FROM ' . $this->_tableName_ . ' WHERE ' . $this->_primaryKey_ . ' = ' . $id)->fetch(PDO::FETCH_ASSOC);
|
||
$this->_id_ = $this->_vals_[$this->_primaryKey_];
|
||
return $this;
|
||
}
|
||
|
||
/**
|
||
* Возвращает массив с объектами, соответствующими записями в БД.
|
||
* @param array $params ['where'] просто строка с условиями: (`id` > 1) AND (`name` == 'TEST'); ['order'] строка с именем толбца и напрабления: `summ` DESC
|
||
* @return array с объектами
|
||
*/
|
||
function getAll($params = array(), $values = array())
|
||
{
|
||
$sql = 'SELECT * FROM `' . $this->_tableName_ . '`';
|
||
$sql .= isset($params['useIndex']) ? ' USE INDEX(' . $params['useIndex'] . ')' : '';
|
||
$sql .= isset($params['where']) ? ' WHERE ' . $params['where'] : '';
|
||
$sql .= isset($params['order']) ? ' ORDER BY ' . $params['order'] : '';
|
||
if (isset($params['limit']) && intval($params['limit'])) {
|
||
if (isset($params['offset']) && intval($params['offset'])) {
|
||
$sql .= ' LIMIT ' . intval($params['offset']) . ', ' . intval($params['limit']);
|
||
} else {
|
||
$sql .= ' LIMIT ' . intval($params['limit']);
|
||
}
|
||
}
|
||
|
||
$res = App::DB()->prepare($sql);
|
||
$res->execute($values);
|
||
|
||
$ready = array();
|
||
|
||
$calledClass = get_called_class();
|
||
while ($res && $row = $res->fetch(PDO::FETCH_ASSOC)) {
|
||
$element = isset($params['asArray']) && $params['asArray'] ? $row : new $calledClass($row);
|
||
|
||
if (isset($params['noKeys']) && $params['noKeys']) {
|
||
$ready[] = $element;
|
||
} else {
|
||
$ready[$row[$this->_primaryKey_]] = $element;
|
||
}
|
||
}
|
||
|
||
return (isset($params['limit']) && $params['limit'] == 1) ? array_shift($ready) : $ready;
|
||
}
|
||
|
||
/**
|
||
* Возвращает один элемент, соотбетствующий параметрам
|
||
* @param string $whereField - имя поля по которому производим поиск
|
||
* @param type $whereValue - искомое значение
|
||
* @return \Model
|
||
*/
|
||
function getOne($whereField, $whereValue)
|
||
{
|
||
return $this->getAll(array(
|
||
'where' => '`' . $whereField . '` = "' . $whereValue . '"',
|
||
'limit' => 1
|
||
));
|
||
}
|
||
|
||
/**
|
||
* Удаляет запись из БД.
|
||
* @param int $id
|
||
* @return boolean
|
||
*/
|
||
function delete($id)
|
||
{
|
||
return $id ? App::DB()->query('DELETE FROM `' . $this->_tableName_ . '` WHERE `' . $this->_primaryKey_ . '` = ' . $id) : false;
|
||
}
|
||
|
||
/**
|
||
* Добавляет новую запись в БД.
|
||
* @param array $values - ассоциативный массив соо значениями.
|
||
* @return object - id добавленной записи или false.
|
||
*/
|
||
function add2($values)
|
||
{
|
||
$values = $this->_vals_;
|
||
unset($values[$this->_primaryKey_]);
|
||
|
||
$q = array();
|
||
foreach ($values as $val) {
|
||
$q[] = '?';
|
||
}
|
||
|
||
var_dump('INSERT INTO `' . $this->_tableName_ . '` (`' . implode('`, `', array_keys($values)) . '`) VALUES (' . implode(', ', array_values($q)) . ') ');
|
||
die;
|
||
$res = App::DB()->prepare_query('INSERT INTO `' . $this->_tableName_ . '` (`' . implode('`, `', array_keys($values)) . '`) VALUES (' . implode(', ', array_values($q)) . ') ', self::arrayWithTypes($values));
|
||
|
||
if ($res) {
|
||
throw new Exception('MySQL error #' . $res->errno . ' - ' . $res->error);
|
||
}
|
||
|
||
return $this->getByPK(App::DB()->insert_id);
|
||
}
|
||
|
||
function add($values)
|
||
{
|
||
$request = App::DB()->prepare('INSERT INTO ' . $this->_tableName_ . ' (' . implode(',', array_keys($values)) . ') values (:' . implode(', :', array_keys($values)) . ')');
|
||
if ($request->execute((array) $values)) {
|
||
return $this->getByPK(App::DB()->lastInsertId());
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Устанавливает значения полей из массива. Нужно проверять, есть ли такие поля в таблице.
|
||
* @param array $values - ассоциативный массив со значениями.
|
||
*/
|
||
function setValues($values)
|
||
{
|
||
if (isset($values[$this->_primaryKey_])) {
|
||
$this->_id_ = $values[$this->_primaryKey_];
|
||
}
|
||
|
||
$this->_vals_ = $values;
|
||
}
|
||
|
||
/**
|
||
* Сохраняет объект в БД.
|
||
* @return object/boolean
|
||
*/
|
||
function save2()
|
||
{
|
||
if (!$this->_id_ || !$this->_vals_) {
|
||
if ($this->_vals_) {
|
||
return $this->add($this->_vals_);
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
$values = $this->_vals_;
|
||
unset($values[$this->_primaryKey_]);
|
||
$keys = array_keys($values);
|
||
$values = array_values($values);
|
||
$values[] = $this->_id_;
|
||
$res = App::DB()->prepare_query('UPDATE `' . $this->_tableName_ . '` SET `' . implode('`=?, `', array_values($keys)) . '`=? WHERE `' . $this->_primaryKey_ . '`=?', self::arrayWithTypes($values));
|
||
|
||
return $res ? $this : FALSE;
|
||
}
|
||
|
||
function save()
|
||
{
|
||
if (!$this->_id_ || !$this->_vals_) {
|
||
if ($this->_vals_) {
|
||
return $this->add($this->_vals_);
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
$values = $this->_vals_;
|
||
unset($values[$this->_primaryKey_]);
|
||
|
||
$request = App::DB()->prepare('UPDATE ' . $this->_tableName_ . ' SET `' . implode('`=?, `', array_keys($values)) . '`=? WHERE ' . $this->_primaryKey_ . '=' . $this->_id_);
|
||
$res = $request->execute(array_values($values));
|
||
|
||
return $res ? $this : FALSE;
|
||
}
|
||
|
||
/**
|
||
* Возвращает значения полей объекта в виде ассоциативного массива.
|
||
* @return array
|
||
*/
|
||
function getValues()
|
||
{
|
||
return $this->_vals_;
|
||
}
|
||
|
||
function removeId()
|
||
{
|
||
$this->_vals_[$this->_primaryKey_] = $this->_id_ = NULL;
|
||
}
|
||
|
||
function getCount($params = array())
|
||
{
|
||
$sql = 'SELECT count(*) AS `cnt` FROM `' . $this->_tableName_ . '`';
|
||
$sql .= isset($params['where']) && $params['where'] ? ' WHERE ' . $params['where'] : '';
|
||
$res = App::DB()->query($sql);
|
||
|
||
$ready = array();
|
||
|
||
|
||
$row = $res->fetch(PDO::FETCH_ASSOC);
|
||
|
||
return (int)$row['cnt'];
|
||
}
|
||
|
||
function update(array $fields)
|
||
{
|
||
if (empty($fields)) {
|
||
return FALSE;
|
||
}
|
||
|
||
$request = App::DB()->prepare('UPDATE ' . $this->_tableName_ . ' SET `' . implode('`=?, `', array_keys($fields)) . '`=? WHERE ' . $this->_primaryKey_ . '=' . $this->_id_);
|
||
$res = $request->execute(array_values($fields));
|
||
|
||
if ($res)
|
||
{
|
||
return $this->getByPK($this->_id_);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/**
|
||
* Возвращает информаци о том, пуст ли объект.
|
||
* @return bool
|
||
*/
|
||
function isEmpty()
|
||
{
|
||
return empty($this->_vals_);
|
||
}
|
||
}
|