Выход версии 0.5 для меня было нечто большим, чем добавление страницы активности и ленты топиков из подписанных блогов. В новой версии реализованы ORM и ActiveRecord. Вместе они дают мощнейший инструментарий для разработчика, избавляя того от кучи однотипного кода, который приходилось писать каждый раз при разработке плагина. Тот-же форум, о котором будет идти речь в статье, после обновления похудел на 2177 строк кода. В этой статье я хочу углубиться в ORM и AR на примере создания плагина для LiveStreet.
Почти год назад пользователь runawayed опубликовал статью о новшествах в транковой версии.
Отталкивался я от той статьи, но она всего-лишь вводная часть того инструментария. Там нет ни слова о кеше, постраничности, древовидного вида массива. Я постараюсь подать как можно больше информации читателю не нагружая его лишним. Начнем?
Я буду рассматривать все на примере плагина forum. Для начала нам надо создать скелет плагина:
Исходники файлов можно посмотреть на гитхабе, на описании плагина я останавливаться не буду.
Теперь создадим модуль с именем forum.
Нам надо описать модуль как ModuleORM, и, в методе Init нам надо наследовать родителя метода Init у обычного модуля:
Прежде чем описывать сущности, надо обдумать все связи между ними, чтобы было легче манипулировать через геттеры:
И описать созданные сущности:
Category.entity.class.php
Forum.entity.class.php
Topic.entity.class.php
Post.entity.class.php
Read.entity.class.php
Теперь всем этим можно манипулировать без описания классов в модуле плагина, например:
Фильтр #cache также может принимать следующиме параметры:
Есть несколько типов связей:
После описания сущностей, нам будут доступные следующие методы:
Таблицы в базе данных должны называться следующим образом: prefix_<module-name>_<entity-name> (или прописать их названия в конфиге), а если же название сущности совпадает с названием модуля, то достаточно назвать таблицу так: prefix_<module-name>. Поля тоже имеют свои стандарты: <entity-name>_<field-name>, или просто <field-name>.
Вот и все, господа, спасибо за уделенное внимание. Напоминаю, что свежие исходники форума можно посмотреть в git'е.
UPD: Сделал корректировки в статье, спасибо ort'у за его замечания.
Почти год назад пользователь runawayed опубликовал статью о новшествах в транковой версии.
Отталкивался я от той статьи, но она всего-лишь вводная часть того инструментария. Там нет ни слова о кеше, постраничности, древовидного вида массива. Я постараюсь подать как можно больше информации читателю не нагружая его лишним. Начнем?
Я буду рассматривать все на примере плагина forum. Для начала нам надо создать скелет плагина:
Исходники файлов можно посмотреть на гитхабе, на описании плагина я останавливаться не буду.
Теперь создадим модуль с именем forum.
Нам надо описать модуль как ModuleORM, и, в методе Init нам надо наследовать родителя метода Init у обычного модуля:
class PluginForum_ModuleForum extends ModuleORM {
public function Init() {
parent::Init();
}
}
Прежде чем описывать сущности, надо обдумать все связи между ними, чтобы было легче манипулировать через геттеры:
И описать созданные сущности:
Category.entity.class.php
class PluginForum_ModuleForum_EntityCategory extends EntityORM {}
Forum.entity.class.php
class PluginForum_ModuleForum_EntityForum extends EntityORM {
protected $aRelations = array(
'category'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityCategory','category_id'),
'user'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'ModuleUser_EntityUser','user_id'),
'topic'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityTopic','topic_id'),
'post'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityPost','post_id'),
);
}
Topic.entity.class.php
class PluginForum_ModuleForum_EntityTopic extends EntityORM {
protected $aRelations = array(
'user'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'ModuleUser_EntityUser','user_id'),
'post'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityPost','post_id'),
'forum'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityForum','forum_id'),
);
}
Post.entity.class.php
class PluginForum_ModuleForum_EntityPost extends EntityORM {
protected $aRelations = array(
'user'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'ModuleUser_EntityUser','user_id'),
'topic'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityTopic','topic_id'),
'forum'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'PluginForum_ModuleForum_EntityForum','forum_id'),
);
}
Read.entity.class.php
class PluginForum_ModuleForum_EntityRead extends EntityORM {}
Теперь всем этим можно манипулировать без описания классов в модуле плагина, например:
$this->PluginForum_ModuleForum_GetCategoryItemsAll(); // получим все категории
$this->PluginForum_ModuleForum_GetForumItemsByCategoryId($oCategory->getId()); // получим все форумы по ID категории
$this->PluginForum_ModuleForum_GetTopicItemsByForumId($oForum->getId(),array('#page' => array(1,15), '#cache'=>''));
/**
* Получим массив для вывода с постраничностью и без кеширования запроса вида:
* array(
* 'collection' => array of objects
* 'count' => integer
* );
* Где array('#page' => array('номер страницы', 'элементов на страницу'))
* Где array('#cache' => '') отказ от кеширования запроса
*/
Фильтр #cache также может принимать следующиме параметры:
array(
'#cache' => array(
'keys', 'tags', 'time'
)
);
Есть несколько типов связей:
protected $aRelations = array(
'entity'=>array(EntityORM::RELATION_TYPE_BELONGS_TO,'ModuleSome_EntitySome','field_id'), // Получаем один элемент по одному элементу. Например, в таблице prefix_forum_topic есть поле с ID'шником пользователя, тогда мы получим юзера по ID с этого поля
'entity'=>array(EntityORM::RELATION_TYPE_HAS_MANY,'ModuleSome_EntitySome','field_id'), // Получает массив элементов
'entity'=>array(EntityORM::RELATION_TYPE_HAS_ONE,'ModuleSome_EntitySome','field_id'), // Это, например, когда у пользователя (основная сущность) есть сессия, и она хранится в отдельной таблице (с) ort
'entity'=>array(EntityORM::RELATION_TYPE_MANY_TO_MANY,'ModuleSome_EntitySome','field_id'), // Получает массив элементов по массиву
EntityORM::RELATION_TYPE_TREE // Строит дерево, необходимо наличие поля parent_id в таблице
);
После описания сущностей, нам будут доступные следующие методы:
/**
* Конструкции вида [name] сделаны для примера
*/
/**
* Работа с объектами
*/
Add();
Update();
Save(); // Совмещает и Update() и Add(), первый выполняется если сущность уже есть в бд, второй когда ее еще нет (с) ort
Delete();
Reload();
// пример:
$oParam->setTitle('Пара-пам-пам');
$oParam->Update();
/**
* Запросы на получение объекта/массива объектов
*/
ShowColumnsFrom[Table]();
LoadTreeOf[Entity]();
Get[Entity]ItemsBy[Filter, Array, JoinTable, Gte, Lte, Gt, Lt, Like, In]();
Get[Entity]All();
Get[Entity]ItemsAll();
/**
* Методы, доступные только для типа tree
*/
GetChildrenOf[Entity]();
GetParentOf[Entity]();
GetDescendantsOf[Entity]();
GetAncestorsOf[Entity]();
// пример:
$this->ModuleHabr_GetTopicItemsAll();
/**
* А так-же сгенерированные через singleton Engine, работа с самим объектом
*/
get[Column]();
// пример:
$oParam->getTitle();
Таблицы в базе данных должны называться следующим образом: prefix_<module-name>_<entity-name> (или прописать их названия в конфиге), а если же название сущности совпадает с названием модуля, то достаточно назвать таблицу так: prefix_<module-name>. Поля тоже имеют свои стандарты: <entity-name>_<field-name>, или просто <field-name>.
Вот и все, господа, спасибо за уделенное внимание. Напоминаю, что свежие исходники форума можно посмотреть в git'е.
UPD: Сделал корректировки в статье, спасибо ort'у за его замечания.