Категории
ORM, Создание моделей и сущностей
ORM - это програмнная прослойка между базой данных и контроллерами(модулями). ORM позволяет оперировать данными в виде объектов, а не в виде табличных данных, как они храняться в БД. Зачем это нужно? Ответ очень прост - объектами проще манипулировать на уровне ООП приложения(программы).
Основными частями ORM являются:
- Models- Entities
- DB Driver
Рассмотрим каждую из этих частей подробнее:
Models
/sys/inc/ORM/Models/Модели служат для описания связей между собой, а так же для описания функций выборки. Каждой таблице в БД должна соответствовать одна модель. Модель представляет из себя класс унаследованный от класса FpsModel. Для того, чтобы стало понятно как должна называться сама модель(класс модели), проще всего привести несколько примеров(имя_таблицы БД = Модель):
news = NewsModel
news_add_fields = NewsAddFieldsModel
Пример
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php /**
*
*/
class NewsModel extends FpsModel
{
public $Table = 'news';
protected $RelatedEntities = array(
'author' => array(
'model' => 'Users',
'type' => 'has_one',
'foreignKey' => 'author_id',
),
'category' => array(
'model' => 'NewsSections',
'type' => 'has_one',
'foreignKey' => 'category_id',
),
'comments_' => array(
'model' => 'Comments',
'type' => 'has_many',
'foreignKey' => 'entity_id',
'additionCond' => array("module = 'news'"),
),
'attaches' => array(
'model' => 'NewsAttaches',
'type' => 'has_many',
'foreignKey' => 'entity_id',
),
);
}?>
Entities
/sys/inc/ORM/Entities/Сущности служат для представления данных. По сути, каждый объект сущности соответствует одной записе в базе данных. А свойства этих объектов соответствуют значениям полей этих записей. Так же как и в случае с моделями, на каждую таблицу в БД должна быть одна сущность. Другими словами, для каждой таблицы в базе данных у нас должна быть модель и сущность(классы модели и сущности). Сущность это класс унаследованный от класса FpsEntity, а так же содержащий описание всех своих свойст(полей) и методов save() и delete(), которые будут служить для сохранения и удаления записей соответственно. Именование сущностей происходит по-тому же принципу, что и моделей, только в конце вместо Model, будет Entity:
news = NewsEntity
news_add_fields = NewsAddFieldsEntity
Пример
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?php /**
*
*/
class NewsEntity extends FpsEntity
{
protected $id;
protected $title;
protected $main;
protected $views;
protected $date;
protected $category_id;
protected $category = null;
protected $author_id;
protected $author = null;
protected $comments;
protected $comments_ = null;
protected $attaches = null;
protected $tags;
protected $description;
protected $sourse;
protected $sourse_email;
protected $sourse_site;
protected $commented;
protected $available;
protected $view_on_home;
protected $on_home_top;
protected $add_fields = null;
protected $premoder;
protected $rating;
public function save()
{
$params = array(
'title' => $this->title,
'main' => $this->main,
'views' => intval($this->views),
'date' => $this->date,
'category_id' => $this->category_id,
'author_id' => $this->author_id,
'comments' => (!empty($this->comments)) ? intval($this->comments) : 0,
'tags' => (is_array($this->tags)) ? implode(',', $this->tags) : $this->tags,
'description' => $this->description,
'sourse' => $this->sourse,
'sourse_email' => $this->sourse_email,
'sourse_site' => $this->sourse_site,
'commented' => (!empty($this->commented)) ? '1' : new Expr("'0'"),
'available' => (!empty($this->available)) ? '1' : new Expr("'0'"),
'view_on_home' => (!empty($this->view_on_home)) ? '1' : new Expr("'0'"),
'on_home_top' => (!empty($this->on_home_top)) ? '1' : new Expr("'0'"),
'premoder' => (!empty($this->premoder) && in_array($this->premoder, array('nochecked', 'rejected', 'confirmed'))) ? $this->premoder : 'nochecked',
'rating' => intval($this->rating),
);
if ($this->id) $params['id'] = $this->id;
$Register = Register::getInstance();
return $Register['DB']->save('news', $params);
}
public function delete()
{
$Register = Register::getInstance();
$attachClass = $Register['ModManager']->getModelNameFromModule('newsAttaches');
$commentsClass = $Register['ModManager']->getModelNameFromModule('Comments');
$addContentClass = $Register['ModManager']->getModelNameFromModule('newsAddContent');
$attachesModel = new $attachClass;
$commentsModel = new $commentsClass;
$addContentModel = new $addContentClass;
$attachesModel->deleteByParentId($this->id);
$commentsModel->deleteByParentId($this->id);
$addContentModel->deleteByParentId($this->id);
$Register['DB']->delete('news', array('id' => $this->id));
}
}?>
DB Driver
Драйвер формирует SQL запросы и выполняет их. Дело в то, что модели передают запросы драйверу в виде набора параметров, а задача драйвера превратить эти данные в SQL запрос, понятный движку БД. Например:Было
1
2
<?php $this->getDbDriver()->select('news', DB_FIRST, array('cond' => array('id' => 1)));?>
Стало
SELECT * FROM `news` WHERE `id` = 1 LIMIT 1
Пример создания модели и сущности
Допустим мы решили добавить на наш сайт фильмы, а это значит, что нам понадобиться таблица в БД, в которой будут храниться записи, а так же модель и сущность. Для простоты примера, в нашей табличке будет всего два поля:CREATE TABLE `films` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR( 255 ) NOT NULL
) ENGINE = InnoDB;
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR( 255 ) NOT NULL
) ENGINE = InnoDB;
Создаем модель(/sys/inc/ORM/Models/Films.php):
1
2
3
4
5
6
7
8
9
<?php /**
*
*/
class FilmsModel extends FpsModel
{
public $Table = 'films';
protected $RelatedEntities = array();
}?>
Создаем сущность(/sys/inc/ORM/Entities/Films.php):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php /**
*
*/
class FilmsEntity extends FpsEntity
{
protected $id;
protected $title;
public function save()
{
$params = array(
'title' => $this->title,
);
if ($this->id) $params['id'] = $this->id;
$Register = Register::getInstance();
return $Register['DB']->save('films', $params);
}
public function delete()
{
$Register = Register::getInstance();
$Register['DB']->delete('films', array('id' => $this->id));
}
}?>
Как вы могли заметить, массив $RelatedEntities в нашей моделе пуст. Это по-тому, что с нашими фильмами не связанны другие таблицы. Теперь мы можем делать выборку по нашим фильмам(далее мы рассмотрим как сязать наши фильмы и пользователей).
1
2
3
<?php $filmsModel = new FilmsModel;
$film = $filmsModel->getById(1);
$films = $filmsModel->getCollection(array('title' => 'Terminator'));?>
Связывание моделей
Допустим, со временем, мы решили расширить функционал нашего сайта с фильмами и решили, кроме названия, хранить еще и ID пользователя, который добавил этот фильм. Для этого нам понадобиться расширить нашу таблицу films и немного подправить модель и сущность.Добавляем поле в таблицу
ALTER TABLE `films` ADD `user_id` INT( 11 ) NOT NULL
А вот как теперь будет выглядеть модель:
1
2
3
4
5
6
7
8
9
10
11
12
<?php class FilmsModel extends FpsModel
{
public $Table = 'films';
protected $RelatedEntities = array(
'author' => array(
'model' => 'Users',
'type' => 'has_one',
'foreignKey' => 'user_id',
),
);
}?>
Если перевести это на человеческий язык, то получим следующее - автором считается та сущность модели Users, ID которой равен полю user_id из нужной нам записи. А has_one говорит о том, что у каждого видео может быть только один автор. Ну или еще так: допустим мы выбрали из базы видео и хотим узнать кто его добавил. Тогда мы смотрим какой ID стоит у этого видео в поле user_id и затем ищем по этому ID пользователя. Только тут вся работа ложиться на плечи моделей, которые делают это все автоматически. Ухх.. Надеюсь доступно объяснил.
А вот наша сущность:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php /**
*
*/
class FilmsEntity extends FpsEntity
{
protected $id;
protected $title;
protected $user_id;
protected $author;
public function save()
{
$params = array(
'title' => $this->title,
'user_id' => intval($this->user_id),
);
if ($this->id) $params['id'] = $this->id;
$Register = Register::getInstance();
return $Register['DB']->save('films', $params);
}
public function delete()
{
$Register = Register::getInstance();
$Register['DB']->delete('films', array('id' => $this->id));
}
}?>
Теперь наши фильмы связаны с пользователями. Но важно понимать, что теперь мы можем выбрать автора видео, используя модель FilmsModel, но не можем выбрать все видео конкретного пользователя, используя модель UsersModel. Ведь мы ничего не меняли в этой моделе. Для того чтобы UsersModel автоматически связывалась с FilmsModel придется подправить ее $RelatedEntities, добавив туда что-то вроде:
1
2
3
4
5
<?php 'films' => array(
'model' => 'Films',
'type' => 'has_many',
'foreignKey' => 'user_id',
)?>