Как стать автором
Обновить

LiveStreet и ORM

LiveStreet
Из песочницы
Выход версии 0.5 для меня было нечто большим, чем добавление страницы активности и ленты топиков из подписанных блогов. В новой версии реализованы ORM и ActiveRecord. Вместе они дают мощнейший инструментарий для разработчика, избавляя того от кучи однотипного кода, который приходилось писать каждый раз при разработке плагина. Тот-же форум, о котором будет идти речь в статье, после обновления похудел на 2177 строк кода. В этой статье я хочу углубиться в ORM и AR на примере создания плагина для LiveStreet.

Почти год назад пользователь runawayed опубликовал статью о новшествах в транковой версии.

Отталкивался я от той статьи, но она всего-лишь вводная часть того инструментария. Там нет ни слова о кеше, постраничности, древовидного вида массива. Я постараюсь подать как можно больше информации читателю не нагружая его лишним. Начнем?

Я буду рассматривать все на примере плагина forum. Для начала нам надо создать скелет плагина:

plugin

Исходники файлов можно посмотреть на гитхабе, на описании плагина я останавливаться не буду.

Теперь создадим модуль с именем forum.

plugin

Нам надо описать модуль как ModuleORM, и, в методе Init нам надо наследовать родителя метода Init у обычного модуля:

class PluginForum_ModuleForum extends ModuleORM {

	public function Init() {
		parent::Init();
	}

}


Прежде чем описывать сущности, надо обдумать все связи между ними, чтобы было легче манипулировать через геттеры:

relations

И описать созданные сущности:

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'у за его замечания.
Теги:
Хабы:
Всего голосов 13: ↑8 и ↓5 +3
Просмотры 2.9K
Комментарии Комментарии 9