_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()) { $sql = 'SELECT * FROM `' . $this->_tableName_ . '`'; $sql .= isset($params['where']) && $params['where'] ? ' WHERE ' . $params['where'] : ''; $sql .= isset($params['order']) && $params['order'] ? ' ORDER BY ' . $params['order'] : ''; $sql .= isset($params['limit']) && $params['limit'] ? ' LIMIT ' . $params['limit'] : ''; $res = App::DB()->query($sql); $ready = array(); $calledClass = get_called_class(); while ($res && $row = $res->fetch(PDO::FETCH_ASSOC)) { $ready[$row[$this->_primaryKey_]] = isset($params['asArray']) && $params['asArray'] ? $row : new $calledClass($row); } return (isset($params['limit']) && $params['limit'] == 1) ? array_shift($ready) : $ready; } /** * Возвращает один элемент, соотбетствующий параметрам * @param string $whereField - имя поля по которому производим поиск * @param type $whereValue - искомое значение * @return type */ 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; } }