Основная единица архитектуры LIMB - это объект сайта (site object). Каждый элемент данных в LIMB является объектом сайта, будь то документ или сообщение в гостевой.
Все объекты сайта иерархически организованы в виде единого дерева.
Объект сайта характеризуется набором аттрибутов. Наиболее важны следующие:
Зачем нужны и 'node_id', и 'id'? Предполагалось, что объекты сайта будут иметь возможность крепиться к нескольким элементам дерева. Пока этой функциональности нет, и она вряд ли появится, однако рефакторинг был бы слишком большим. В основном используется 'node_id'.
Есть 2 способа получить определенный объект сайта:
В ядро Limb включены 2 типа объектов сайта:
Основные отличия у них в том, что контентный объект находится под простым версионным контролем, плюс базовая реализация контентного объекта привязана к записи в дополнительной таблицы базы данных.
Пример объекта сайта статья (article):
<?php require_once(LIMB_DIR . '/src/site_objects/content_object.class.php'); class article extends content_object { function _define_class_properties() { return array( 'class_ordr' => 1, 'can_be_parent' => 0, ); } } ?>
Каждый объект сайта соединен с каким-либо контроллером, который определяет, какие действия объект может выполнять.
Пример контроллера:
<?php require_once(LIMB_DIR . '/src/controllers/site_object_controller.class.php'); require_once(LIMB_DIR . '/src/i18n/strings.class.php'); class article_controller extends site_object_controller { function _define_actions() { return array( 'display' => array( 'template_path' => '/article/display.html', ), 'admin_detail' => array( 'template_path' => '/admin/object_detail_info.html', 'popup' => true, 'JIP' => true, 'img_src' => '/shared/images/admin_detail.gif', 'action_name' => strings :: get('detail_info'), ), 'print_version' => array( 'template_path' => '/article/print_version.html', 'action_name' => strings :: get('print_version_action', 'document'), 'display_in_breadcrumbs' => false, ), 'edit' => array( 'popup' => true, 'JIP' => true, 'action_name' => strings :: get('edit_article', 'article'), 'action_path' => '/article/edit_article_action', 'template_path' => '/article/edit.html', 'img_src' => '/shared/images/edit.gif' ), 'publish' => array( 'popup' => true, 'JIP' => true, 'action_name' => strings :: get('publish'), 'action_path' => '/doc_flow_object/set_publish_status_action', 'img_src' => '/shared/images/publish.gif', 'can_have_access_template' => true, ), 'unpublish' => array( 'popup' => true, 'JIP' => true, 'action_name' => strings :: get('unpublish'), 'action_path' => '/doc_flow_object/set_publish_status_action', 'img_src' => '/shared/images/unpublish.gif', 'can_have_access_template' => true, ), 'delete' => array( 'JIP' => true, 'popup' => true, 'action_name' => strings :: get('delete_article', 'article'), 'action_path' => '/article/delete_article_action', 'template_path' => '/site_object/delete.html', 'img_src' => '/shared/images/rem.gif' ), ); } } ?>
Действия отвечают за выполнение некоторой логики приложения. По сути, это класс, который инстанциируется контроллером для вызова метода perform(&$request, &$response). Как видно из сигнатуры, в метод perform приходят объекты запроса(request) и ответа(response), используя которые можно получить входные параметры HTTP запроса и повлиять на формирование определенного ответа приложения клиенту.
То, какое действие должно выполниться, определяется контроллером при помощи параметра 'action' из переменной $_REQUEST, поэтому следующий код:
http://somedomain.com/documents/article1?action=edit
приведет к тому, что найдется site_object по пути в дереве 'documents/article1', затем определится прикрепленный к нему контроллер и затем контроллер попытается исполнить действие edit
Рассмотрим внимательнее 'edit' раздел контроллера. Обратите внимание на параметр 'action_path', который определяет путь до класса-действия (в нашем случае это будет '/article/edit_article_action.class.php'). Для пути до класса-действия применяется специальная техника резолвинга путей.
Итак, содержимое '/article/edit_article_action.class.php':
<?php require_once(LIMB_DIR . 'core/actions/form_edit_site_object_action.class.php'); class edit_article_action extends form_edit_site_object_action { function _define_site_object_class_name() { return 'article'; } function _define_dataspace_name() { return 'article_form'; } function _define_datamap() { return complex_array :: array_merge( parent :: _define_datamap(), array( 'article_content' => 'content', 'annotation' => 'annotation', 'author' => 'author', 'source' => 'source', 'uri' => 'uri', ) ); } function _init_validator() { parent :: _init_validator(); $this->validator->add_rule(new required_rule('title')); $this->validator->add_rule(new required_rule('author')); $this->validator->add_rule(new required_rule('article_content')); } } ?>
LIMB содержит определенное количество классов для базовых действий, поэтому обычно разработчику необходимо отнаследоваться от одного из таких действий, в данном случае таковым выступает form_edit_site_object_action, который специализируется на редактировании site_object'ов
Также в разделе 'edit' контроллера у нас описан необязательный аттрибут 'template_path' как '/article/edit.html'. Контроллер в этом случае при выполнении действия, инициализирует WACT шаблон и передаст его в объект-действие. Этот шаблон будет выглядеть приблизительно так:
<core:WRAP file="popup.html" placeholder="content"> <form method="post" name="article_form" id="article_form"> <table width=100% border=0 cellspacing=0 cellpadding=0 height=100%> <tr> <td colspan=2 class=table-title><locale:STRING name='article_edition' file='article'> <h3> "<fetch:MAPPED>{$title}</fetch:MAPPED>" </h3></td> </tr> <tr> <td colspan=2 height=100% valign=top class=com4> <table width="100%" border="0" cellspacing="0" cellpadding="0" style='padding:5px 10px 1px 5px;' id=param_req_content> <col align=right width=200 class=labels> <tr> <td><label for="identifier"><span class='req'>*</span><locale:STRING name='identifier' ></label></td> <td><input type="text" name="identifier" id="identifier" label="Identifier" class='input'></td> </tr> <tr> <td><label for="title"><span class='req'>*</span><locale:STRING name='title' ></label></td> <td><input type="text" name="title" id="title" label="Title" class='input' size='40'></td> </tr> <tr> <td><label for="annotation"><locale:STRING name='annotation'></label></td> <td><textarea class='textarea' name="annotation" id="annotation" label="Annotation" cols='40' rows='5'></textarea></td> </tr> <tr> <td><label for="author"><span class=req>*</span><locale:STRING name='author' file='article'></label></td> <td><input type="text" name="author" id="author" label="Author" size="60" class='input'></td> </tr> <tr> <td><label for="source"><locale:STRING name='source' file='article'></label></td> <td><input type="text" name="source" id="source" label="Source" size="60" class='input'></td> </tr> <tr> <td><label for="uri"><locale:STRING name='uri' file='article'></label></td> <td><input type="text" name="uri" id="uri" label="URL" size="60" class='input'></td> </tr> </table> </td> </tr> <tr> <td colspan=2 align=center height=30> <action_button action="edit" name="update" type="submit" id="update" value="update" reload_parent="true" class="button"> <input name="cancel" type="button" id="cancel" value="close" onclick='window.close();' class="button"> </td> </tr> </table> </form>
На самом деле, каждое действие получает ссылку на объект View, однако он используется нечасто, так как LIMB использует концепцию активного шаблона (pull).
Объекты сайта передаются внутри LIMB в виде массивов, и обращаются в объекты только по необходимости. Это позволяет значительно экономить на времени выполнения и облегчает многие задачи, к примеру, таким образом объекты передаются в шаблон что позволяет обращаться к их аттрибутам непосредственно из шаблонной системы WACT.
Обсуждение