BIG UPDATE: Новый базовый класс под модели, новые модели, новый код в контролерах и вьюхах

This commit is contained in:
Krivchikov Dmitry 2014-07-24 12:54:27 +04:00
parent 39de8ae0a1
commit 27e4f6d577
11 changed files with 330 additions and 164 deletions

View File

@ -29,7 +29,7 @@ class App
private static $basedir = false; private static $basedir = false;
private static $config = array(); private static $config = array();
private static $urlParams = array(); private static $urlParams = array();
public static $DB = null; private static $DB = null;
public static $user = null; public static $user = null;
/** /**
@ -65,21 +65,7 @@ class App
self::$config = $config ? include_once $config : array(); self::$config = $config ? include_once $config : array();
self::parseUrl(); self::parseUrl();
if (self::getConfig('DB'))
{
try
{
$confDB = self::getConfig('DB');
self::$DB = new PDO('mysql:host=' . $confDB['host'] . ';dbname=' . $confDB['dbname'].';charset=utf8;', $confDB['user'], $confDB['password']);
// Работать с пользователями моно только при наличии БД
self::userInit(); self::userInit();
}
catch (PDOException $e)
{
echo $e->getMessage();
}
}
$controller = self::$controller; $controller = self::$controller;
$action = self::$action; $action = self::$action;
@ -93,6 +79,24 @@ class App
} }
} }
public static function DB()
{
if (self::$DB === NULL && self::getConfig('DB'))
{
try
{
$confDB = self::getConfig('DB');
self::$DB = new PDO('mysql:host=' . $confDB['host'] . ';dbname=' . $confDB['dbname'].';charset=utf8;', $confDB['user'], $confDB['password']);
}
catch (PDOException $e)
{
echo $e->getMessage();
}
}
return self::$DB;
}
public static function error404($message = '') public static function error404($message = '')
{ {
header("HTTP/1.0 404 Not Found"); header("HTTP/1.0 404 Not Found");
@ -104,12 +108,11 @@ class App
{ {
if (isset($_SESSION['user_id']) && isset($_SESSION['user_key']) && $_SESSION['user_id'] && $_SESSION['user_key'] ) if (isset($_SESSION['user_id']) && isset($_SESSION['user_key']) && $_SESSION['user_id'] && $_SESSION['user_key'] )
{ {
$user = new User(); $user = User::model()->getByPK((int)$_SESSION['user_id']);
$user = $user->getByPK((int)$_SESSION['user_id']);
if ( $user && md5($user->uid) == $_SESSION['user_key'] ) if ( $user && md5($user->uid) == $_SESSION['user_key'] )
{ {
self::$user = $user; App::$user = $user;
} }
} }
} }

View File

@ -1,27 +1,105 @@
<?php <?php
class Model /*
Пример работы:
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_; private $_primaryKey_;
protected $_tableName_; protected $_tableName_;
private $_id_; private $_id_;
private $_vals_ = array(); private $_vals_ = array();
protected $_relations_ = array();
function __construct($table) function __construct($fromArray = array())
{ {
$this->_tableName_ = $table;
$this->_primaryKey_ = $this->getPk(); $this->_primaryKey_ = $this->getPk();
if ($fromArray)
{
$this->setValues($fromArray);
}
} }
/**
* TODO: Проверять, есть ли такие поля в БД.
* @param type $name
* @param type $value
*/
function __set($name, $value) function __set($name, $value)
{ {
$this->_vals_[$name] = $value; $this->_vals_[$name] = $value;
if ($name == $this->_primaryKey_)
{
$this->_id_ = $value;
}
} }
function __get($name) function __get($name)
{ {
return isset($this->_vals_[$name]) ? $this->_vals_[$name] : null; 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;
} }
/** /**
@ -30,10 +108,29 @@ class Model
*/ */
private function getPk() private function getPk()
{ {
$res = App::$DB->query("SHOW KEYS FROM " . $this->_tableName_ . " WHERE Key_name = 'PRIMARY'")->fetch(PDO::FETCH_ASSOC); $res = App::DB()->query("SHOW KEYS FROM " . $this->_tableName_ . " WHERE Key_name = 'PRIMARY'")->fetch(PDO::FETCH_ASSOC);
return $res["Column_name"]; 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 * @param int $id
@ -41,43 +138,52 @@ class Model
*/ */
function getByPK($id) function getByPK($id)
{ {
$this->_vals_ = App::$DB->query('SELECT * FROM ' . $this->_tableName_ . ' WHERE ' . $this->_primaryKey_ . ' = ' . $id)->fetch(PDO::FETCH_ASSOC); $this->_vals_ = App::DB()->query('SELECT * FROM ' . $this->_tableName_ . ' WHERE ' . $this->_primaryKey_ . ' = ' . $id)->fetch(PDO::FETCH_ASSOC);
$this->_id_ = $this->_vals_[$this->_primaryKey_]; $this->_id_ = $this->_vals_[$this->_primaryKey_];
return $this; return $this;
} }
static function getByPrimaryKey($id)
{
$instance = new self();
return $instance->getByPK($id);
}
/** /**
* Возвращает массив с ассоциативными массивами, соответствующими записями в БД. * Возвращает массив с объектами, соответствующими записями в БД.
* @param string $where просто строка с условиями: (`id` > 1) AND (`name` == 'TEST') * @param array $params ['where'] просто строка с условиями: (`id` > 1) AND (`name` == 'TEST'); ['order'] строка с именем толбца и напрабления: `summ` DESC
* @param string $order строка с именем толбца и напрабления: `summ` DESC * @return array с объектами
* @return type
*/ */
function getAll($where = '', $order = '') function getAll($params = array())
{ {
/* TODO: Переделать этот метод. Сделать статическим, возвращать массив объектов. */ $sql = 'SELECT * FROM `' . $this->_tableName_ . '`';
$sql = 'SELECT * FROM ' . $this->_tableName_; $sql .= isset($params['where'])&&$params['where'] ? ' WHERE ' . $params['where'] : '';
$sql .= $where ? ' WHERE '.$where : ''; $sql .= isset($params['order'])&&$params['order'] ? ' ORDER BY ' . $params['order'] : '';
$sql .= $order ? ' ORDER BY '.$order : ''; $sql .= isset($params['limit'])&&$params['limit'] ? ' LIMIT ' . $params['limit'] : '';
$res = App::$DB->query($sql); $res = App::DB()->query($sql);
$this->_id_ = NULL; // Это больше не конкретная запись
$ready = array(); $ready = array();
//print_r($res);die;
$calledClass = get_called_class();
while ($res && $row = $res->fetch(PDO::FETCH_ASSOC)) while ($res && $row = $res->fetch(PDO::FETCH_ASSOC))
{ {
$ready[$row[$this->_primaryKey_]] = $row; $ready[$row[$this->_primaryKey_]] = isset($params['asArray'])&&$params['asArray'] ? $row : new $calledClass($row);
} }
return $ready; return $ready;
} }
/**
* Возвращает один элемент, соотбетствующий параметрам
* @param string $whereField - имя поля по которому производим поиск
* @param type $whereValue - искомое значение
* @return type
*/
function getOne($whereField, $whereValue)
{
return array_shift(
$this->getAll(array(
'where' => '`' . $whereField . '` = "' . $whereValue . '"',
'limit' => 1
))
);
}
/** /**
* Удаляет запись из БД. * Удаляет запись из БД.
* @param int $id * @param int $id
@ -85,21 +191,43 @@ class Model
*/ */
function delete($id) function delete($id)
{ {
return $id ? App::$DB->query('DELETE FROM ' . $this->_tableName_ . ' WHERE ' . $this->_primaryKey_ . ' = ' . $id) : false; return $id ? App::DB()->query('DELETE FROM `' . $this->_tableName_ . '` WHERE `' . $this->_primaryKey_ . '` = ' . $id) : false;
} }
/** /**
* Добавляет новую запись в БД. * Добавляет новую запись в БД.
* @param array $values - ассоциативный массив соо значениями. * @param array $values - ассоциативный массив соо значениями.
* @return int/boolean - id добавленной записи или false. * @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) function add($values)
{ {
$request = App::DB()->prepare('INSERT INTO ' . $this->_tableName_ . ' (' . implode(',', array_keys($values)) . ') values (:' . implode(', :', array_keys($values)) . ')');
$request = App::$DB->prepare('INSERT INTO ' . $this->_tableName_ . ' (' . implode(',', array_keys($values)) . ') values (:' . implode(', :', array_keys($values)) . ')');
if ( $request->execute((array) $values) ) if ( $request->execute((array) $values) )
{ {
return $this->getByPK(App::$DB->lastInsertId()); return $this->getByPK(App::DB()->lastInsertId());
} }
else else
{ {
@ -108,11 +236,16 @@ class Model
} }
/** /**
* Устанавливает значения полей из массива. * Устанавливает значения полей из массива. Нужно проверять, есть ли такие поля в таблице.
* @param array $values - ассоциативный массив со значениями. * @param array $values - ассоциативный массив со значениями.
*/ */
function setValues($values) function setValues($values)
{ {
if (isset($values[$this->_primaryKey_]))
{
$this->_id_ = $values[$this->_primaryKey_];
}
$this->_vals_ = $values; $this->_vals_ = $values;
} }
@ -120,15 +253,48 @@ class Model
* Сохраняет объект в БД. * Сохраняет объект в БД.
* @return object/boolean * @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() function save()
{ {
if (!$this->_id_ || !$this->_vals_) if (!$this->_id_ || !$this->_vals_)
{
if ($this->_vals_)
{
return $this->add($this->_vals_);
}
else
{
return FALSE; return FALSE;
}
}
$values = $this->_vals_; $values = $this->_vals_;
unset($values[$this->_primaryKey_]); unset($values[$this->_primaryKey_]);
$request = App::$DB->prepare('UPDATE ' . $this->_tableName_ . ' SET ' . implode('=?, ', array_keys($values)) . '=? WHERE '.$this->_primaryKey_.'='.$this->_id_); $request = App::DB()->prepare('UPDATE ' . $this->_tableName_ . ' SET ' . implode('=?, ', array_keys($values)) . '=? WHERE '.$this->_primaryKey_.'='.$this->_id_);
$res = $request->execute(array_values($values)); $res = $request->execute(array_values($values));
return $res ? $this : FALSE; return $res ? $this : FALSE;
@ -143,4 +309,9 @@ class Model
return $this->_vals_; return $this->_vals_;
} }
function removeId()
{
$this->_vals_[$this->_primaryKey_] = $this->_id_ = NULL;
}
} }

View File

@ -47,10 +47,11 @@ class IndexController extends Controller
self::addVar('isAdmin', (int)(App::$user && App::$user->isAdmin == 1) ); self::addVar('isAdmin', (int)(App::$user && App::$user->isAdmin == 1) );
$res = App::$DB->query("SELECT COUNT(`id`) pointsCount FROM `points`")->fetch(PDO::FETCH_ASSOC); $res = App::DB()->query("SELECT COUNT(`id`) pointsCount FROM `points`")->fetch(PDO::FETCH_ASSOC);
App::setConfig('title', $res['pointsCount'].' или даже больше поводов не сидеть дома'); App::setConfig('title', $res['pointsCount'].' или даже больше поводов не сидеть дома');
self::addVar('pointsCount', $res['pointsCount']); self::addVar('pointsCount', $res['pointsCount']);
$og = array();
if(isset($_GET['point']) && $_GET['point'] && is_numeric($_GET['point'])) if(isset($_GET['point']) && $_GET['point'] && is_numeric($_GET['point']))
{ {
$id = (int) $_GET['point']; $id = (int) $_GET['point'];
@ -110,7 +111,7 @@ class IndexController extends Controller
$user = new User(); $user = new User();
$user->getByUID($uLoginUser['identity']); $user->getByUID($uLoginUser['identity']);
//var_dump($uLoginUser,'<br><br>', $user);die;
if( !$user->id ) if( !$user->id )
{ {
$user = $user->add(array( $user = $user->add(array(

View File

@ -9,17 +9,18 @@ class JsonController extends Controller
static function actionPoints() static function actionPoints()
{ {
$points = Point::model()->getAll(); $points = Point::model()->getAll();
$categories = Category::model()->getAll(); $categories = Category::model()->getAll(array('asArray'=>true));
$result = array(); $result = array();
foreach ($points as $point) { foreach ($points as $point) {
$result[$point['id']]['id'] = $point['id']; $id = $point->id;
$result[$point['id']]['name'] = $point['name']; $result[$id]['id'] = $point->id;
$result[$point['id']]['lat'] = $point['lat']; $result[$id]['name'] = $point->name;
$result[$point['id']]['lng'] = $point['lng']; $result[$id]['lat'] = $point->lat;
$result[$point['id']]['categoryId'] = $point['categoryId']; $result[$id]['lng'] = $point->lng;
$result[$point['id']]['categoryIcon'] = $categories[$point['categoryId']]['icon']; $result[$id]['categoryId'] = $point->categoryId;
$result[$id]['categoryIcon'] = $categories[$point->categoryId]['icon'];
} }
self::renderPartial('json.php', array( self::renderPartial('json.php', array(
@ -35,34 +36,12 @@ class JsonController extends Controller
$id = (int) App::getParam('id'); $id = (int) App::getParam('id');
if ($id) if ($id)
{ {
//$point = Point::getByPrimaryKey($id);
//$point = $point->getByPK($id);
// $point = new Point();
// $point->name = 'TEST';
// $point->lat = 12;
// $point->lng = 44;
// $point->img = 'sdfsdfsdf';
// $point->description = 'sdfsdfsdfsdfsdfsdfsdfsfd';
// $point->categoryId = 1;
// $point->source = '';
// $point->author = 2;
// $point->date = time();
//
// print_r($point->save());
//
// print '<br/><br/><br/><br/>';
//
//
// print_r($point);
// die;
$point = Point::model()->getByPK($id); $point = Point::model()->getByPK($id);
$point->descriptionHtml = nl2br($point->description); $point->descriptionHtml = nl2br($point->description);
$point->name = htmlspecialchars($point->name); $point->name = htmlspecialchars($point->name);
$categories = Category::model()->getAll(); $categories = Category::model()->getAll(array('asArray'=>true));
$point->categoryIcon = $categories[$point->categoryId]['icon']; $point->categoryIcon = $categories[$point->categoryId]['icon'];
$point->categoryName = $categories[$point->categoryId]['name']; $point->categoryName = $categories[$point->categoryId]['name'];
@ -79,7 +58,7 @@ class JsonController extends Controller
*/ */
static function actionCategories() static function actionCategories()
{ {
$categories = Category::model()->getAll(); $categories = Category::model()->getAll(array('asArray'=>true));
self::renderPartial('json.php', array( self::renderPartial('json.php', array(
'data' => $categories, 'data' => $categories,

View File

@ -12,30 +12,25 @@ class PageController extends Controller
self::addStyle('/css/bootstrap.min.css'); self::addStyle('/css/bootstrap.min.css');
self::addStyle('/css/bootstrap-theme.min.css'); self::addStyle('/css/bootstrap-theme.min.css');
$categoryId = (int)App::getParam('category'); $param['order']='id DESC';
$where = $categoryId ? 'categoryId = '.$categoryId : ''; $param['where']=App::getParam('category') ? 'categoryId = '.(int)App::getParam('category') : '';
$points = Point::model()->getAll($param);
$points = new Point(); $categories = Category::model()->getAll();
$points = $points->getAll($where, 'id DESC');
$categories = new Category();
$categories = $categories->getAll('', 'ord');
$users = new User();
$users = $users->getAll();
$result = array(); $result = array();
foreach ($points as $point) foreach ($points as $point) {
{ $id = $point->id;
$result[$point['id']]['id'] = $point['id']; $result[$id]['id'] = $point->id;
$result[$point['id']]['name'] = $point['name']; $result[$id]['name'] = $point->name;
$result[$point['id']]['img'] = $point['img']; $result[$id]['lat'] = $point->lat;
$result[$point['id']]['categoryIcon'] = $categories[$point['categoryId']]['icon']; $result[$id]['lng'] = $point->lng;
$result[$point['id']]['author'] = $users[$point['author']]['nick']; $result[$id]['author'] = $point->authorUser->name;
$result[$id]['categoryId'] = $point->categoryId;
$result[$id]['categoryIcon'] = $categories[$point->categoryId]->icon;
} }
$res = App::$DB->query("SELECT COUNT(`id`) pointsCount FROM `points`")->fetch(PDO::FETCH_ASSOC); $res = App::DB()->query("SELECT COUNT(`id`) pointsCount FROM `points`")->fetch(PDO::FETCH_ASSOC);
App::setConfig('title', $res['pointsCount'] . ' или даже больше поводов не сидеть дома'); App::setConfig('title', $res['pointsCount'] . ' или даже больше поводов не сидеть дома');
self::render('pointsTemplate.php', array( self::render('pointsTemplate.php', array(

View File

@ -2,14 +2,16 @@
class Category extends Model class Category extends Model
{ {
function __construct() function __construct($fromArray = array())
{ {
return self::model(); $this->_tableName_ = 'categories';
parent::__construct($fromArray);
$this->setRelation('points', 'id', 'Point', 'categoryId', self::TO_MANY);
} }
static function model() static function model()
{ {
return new Model('categories'); return new self();
} }
} }

View File

@ -2,14 +2,17 @@
class Point extends Model class Point extends Model
{ {
function __construct() function __construct($fromArray = array())
{ {
return self::model(); $this->_tableName_ = 'points';
parent::__construct($fromArray);
$this->setRelation('category', 'categoryId', 'Category', 'id', self::TO_ONE);
$this->setRelation('authorUser', 'author', 'User', 'id', self::TO_ONE);
} }
static function model() static function model()
{ {
return new Model('points'); return new self();
} }
} }

View File

@ -2,16 +2,20 @@
class Route extends Model class Route extends Model
{ {
function __construct() function __construct($fromArray = array())
{ {
$this->_tableName_ = 'routes'; $this->_tableName_ = 'routes';
parent::__construct(); parent::__construct($fromArray);
}
static function model()
{
return new self();
} }
function getByAuthor($authorId) function getByAuthor($authorId)
{ {
return $this->getAll('`author` = '.$authorId); return $this->getAll(array('where'=>'`author` = '.$authorId));
} }
} }

View File

@ -2,20 +2,28 @@
class User extends Model class User extends Model
{ {
function __construct() function __construct($fromArray = array())
{ {
$this->_tableName_ = 'users'; $this->_tableName_ = 'users';
parent::__construct(); parent::__construct($fromArray);
$this->setRelation('category', 'catogoryId', 'Category', 'id', self::TO_ONE);
}
static function model()
{
return new self();
} }
function getByUID($uid) function getByUID($uid)
{ {
$res = App::$DB->query('SELECT `id` FROM ' . $this->_tableName_ . ' WHERE `uid` = "' . $uid . '"'); $res = App::DB()->query('SELECT `id` FROM `' . $this->_tableName_ . '` WHERE `uid` = "' . $uid . '"');
if ($res) if ($res)
{ {
$res = $res->fetch(PDO::FETCH_ASSOC); $res = $res->fetch(PDO::FETCH_ASSOC);
return parent::getByPK((int)$res['id']); print_r($res['id']);
$user = $this->getByPK((int)$res['id']);
return $user;
} }
else else
{ {

View File

@ -50,7 +50,7 @@
</span> </span>
<br /> <br />
<?php foreach ($categories as $category): ?> <?php foreach ($categories as $category): ?>
<input type="checkbox" value="<?=$category['id']?>" class="filterSelector"> <?=$category['name']?><br/> <input type="checkbox" value="<?=$category->id?>" class="filterSelector"> <?=$category->name?><br/>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
<div id="boxRoute" style="height: 100%; overflow-y: auto;"> <div id="boxRoute" style="height: 100%; overflow-y: auto;">
@ -68,7 +68,7 @@
<div id="routes"> <div id="routes">
<?php if ($routes): ?> <?php if ($routes): ?>
<?php foreach ($routes as $route) : ?> <?php foreach ($routes as $route) : ?>
<div class="route" onclick="loadRoute(<?= $route['id'] ?>)"><span onclick="deleteRoute(<?= $route['id'] ?>);$(this).parent().remove();event.stopPropagation();">&times;</span> <?= $route['name'] ?></div> <div class="route" onclick="loadRoute(<?= $route->id ?>)"><span onclick="deleteRoute(<?= $route->id ?>);$(this).parent().remove();event.stopPropagation();">&times;</span> <?= $route->name ?></div>
<?php endforeach; ?> <?php endforeach; ?>
<?php else: ?> <?php else: ?>
У вас пока нет сохраненных маршрутов. У вас пока нет сохраненных маршрутов.

View File

@ -7,7 +7,7 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<?php foreach ($categories as $category): ?> <?php foreach ($categories as $category): ?>
<img src="<?=$category['icon']?>"> - <a href="/page/points/category/<?=$category['id']?>"><?=$category['name']?></a><br/> <img src="<?=$category->icon?>"> - <a href="/page/points/category/<?=$category->id?>"><?=$category->name?></a><br/>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">