|
Приведенные в статье общие размышления можно проиллюстрировать реализацией
простого примера с использованием различных средств. Примером будет список
логотипов выводимых в каком-либо месте страницы - например, вдоль нижнего
края. Каждый логотип характеризуется следующими атрибутами:
- Изображение
- Ссылка
В результате нужно получить на странице фрагмент HTML-кода примерно
следующего содержания:
<P>
<A HREF="ссылка-1"> <IMG SRC="URL-изображения-1"> </A>
... несколько повторений ...
</P>
Причем должна быть возможность легкого изменения дизайна приведенного
фрагмента и списка логотипов.
CGI-скрипт & HTML::Template
За отсутствием серьезных альтернатив для более масштабных задач, будем
хранить логотипы в базе данных MySQL в таблице, определяемой строкой:
CREATE TABLE logo (
id int primary key auto_increment,
img varchar(32),
ref varchar(32)
);
Для отображения будем использовать следующий фрагмент
кода HTML::Template
..... какое-то начало .... <P>
<TMPL-LOOP name="logo_list">
<A HREF="%ref%"> <IMG SRC="%img%"> </A>
</TMPL-LOOP>
</P>
..... какой-то конец ....
Для получения данных из базы создадим perl-модуль под названием LOGO,
который будет содеражать следующий фрагмент кода:
if ($self->query(logo_list)) {
$self->htmltable("select ref,img from logo",logo_list,ref,img)
}
(Позже мы поясним почему нужен "целый модуль" для одной строки кода)
Все, задача практически решена: после небольшого тестирования
HTML::Template-код можно отдать дизайнеру, который из вышеприведенного
незамысловатого фрагмента сделает конфетку. Как нетрудно видеть, дизайнер не
выходит за пределы привычной ему концепции HTML-тегов: просто появились два
новых тега. Нарушить программный код дизайнер не может, т.к. не имеет к нему
доступ.
Но за этими победными словами кроется подводный камень: приведенный фрагмент
кода функционально не полон. Как разместить новые логотипы в списке? Открыть
Unix-shell, запустить консольный клиент MySQL и начать писать SQL-запросы?
Вполне возможный вариант, хотя на самом деле, вышеупомянутый "целый модуль"
придется существенно доработать, добавив средства редактирования таблицы
логотипов. Это нетрудно - но выходит за рамки нашего примера. Результатом
будет функционально полное решение, позволяющее вставлять в CGI-скрипт
возможность отображать строку логотипов, написав команду вида:
$logo = LOGO->new(tablename=>"logo", edit=>"1");
Как видим, объект здесь - строка логотипов, методы которого - отображение, редактировние и т.п.
Midgard
Хотя можно хранить список логотипов в таблице базы данных, но, здесь есть
лучшая альтернатива: создать каталог в прострастве "Публикуемых материалов",
статьи которого будут определениями отдельных логотипов. Пусть это будет
каталог No.54 (в новых версиях Midgard возможна ссылка по имени). В каталоге
54 разместим статьи, причем в атрибут extra1 этой статьи запишем url
изображения, а в атрибут extra2 - url ссылки. Чбы отличать логотипы от всех
других статей в этом каталоге, присвоим им тип номер 12. Несмотря на то, что
при этом используется интерфейс Midgard и который позволяет создать статьи в
каталоге, на самом деле вносятся данные в аналогичную таблицу MySQL, но ее
поля были предопределены разработчиками (если не хватило предопределенных
полей - то об этом отдельный разговор, начиная с версии Bifrost).
Для отображения указаного списка логотипов требуется в адресном пространстве
поместить следующий фрагмент кода:
<P>
<?
$article = mgd_list_topic_articles(54,"order",12);
if ($article)
while($article->fetch()) {
$article_item = mgd_get_article($article->id);
?> <A HREF="&(article_item.extra2);">
<IMG SRC="&(article_item.extra1);"> </A>
}
?>
</P>
Как видим, о декомпозиции кода и дизайна речи пока не идет. К счастью, есть
выход: определить участки HTML-кода в виде стилевых элементов и разместить
их в пространстве Стилей. Тогда фрагмент кода изменится:
<[LOGO_head]> <?
$article = mgd_list_topic_articles(54,"order",12);
if ($article) while($article->fetch()) {
$article_item = mgd_get_article($article->id);
?> <[LOGO_item]>
}
?>
<[LOGO_tail]>
А в таблице стилей появятся
следующие элементы:
- LOGO_head
- <p>
- LOGO_item
- <A HREF="&(article_item.extra2);">
<IMG SRC="&(article_item.extra1);">
- LOGO_tail
- <p>
Кажется, нужно еще сказать что-то о повторном использовании? Хорошо,
создадим страничный элемент LOGO_list, следующего содержания:
<[LOGO_head]> <?
$article =
mgd_list_topic_articles($article_topic,"order",12);
if ($article) while($article->fetch()) {
$article_item = mgd_get_article($article->id);
?> <[LOGO_item]>
}
?>
<[LOGO_tail]>
А на самой странице разместим
следующий код:
<? $article_topic = 54; ?>
<[LOGO_list]>
Вот, в принципе готово. Объяснив дизайнеру какие элементы можно
редактировать и зачем, можно ожидать что дизайнер сделает дизайн.
Несмотря на технологические затруднения при разделении труда разработчиков,
необходимо отметить отсутствие необходимости создания обвязки для достижения
функциональной полноты. Все уже есть - контент-менеджер может спокойно
положить статью в каталог и забыть о ней. Причем интерфейс для
контент-менеджера вполне удобный, это не командная строка mysql....
Zope
Теперь все тоже самое, только в Zope . Опять-таки, будем хранить объект в
рамках самого Zope , правда, на этот раз это будет действительно объект -
объект, для которого помимо свойств определим метод: tag. Не останавливаясь
на подробностях создания объекта, скажем лишь что класс объекта называется
Logo. В отличие от двух предыдущих случаев будем хранить изображение в самой
базе данных, породив класс Logo от встроенного класса image. Хотя метод
render можно написать на языке Python, в данном случае будет проще
воспользоваться самим DTML. Назначение метода - вернуть строку, отображающую
логотип. Вот он:
<A HREF="<dtml_var ref>"> <dtml_var "tag(border=0)">" </A>
(Нам не потребовался тег img, потому что сам по себе объект Image уже делает
операцию отображения изображения используя метод tag)
Создадим для объекта Logo вид по умолчанию, вызывающий этот метод. Теперь в
каталоге Logo создадим несколько объектов типа Logo, а в нужном месте
вставим следующий DTML-код:
<dtml-in "Logo.objectItems()">
<dtml-var sequence-item>
</dtml-in>
Все, готово. Нашему дизайнеру, как и в Midgard, нужно лезть в разные
фрагменты, однако здесь при сохранении всех преимуществ Midgard, мы
получаем еще одно: инкапсуляцию. Что будет если в каталог Logo мы положим
объект класса Image ? Мы получим картинку без ссылки. А объект класса
DTML-document? Вставленный текст документа. Кроме того, мы можем аналогично
Logo определить более сложный тип Banner, причем, это происходит незаметно
для дизайнера (он лишь определяет метод render()) и прозрачно - для
контент-менеджера (в списке классов объектов, которые он может добавить в
каталог появляется еще один). Заметим еще одну немаловажную деталь:
несколькими манипуляциями мышью мы можем экспортировать определение объекта
и сам объект в виде переносимого формата (XML или ZEXP) и импортировать в
другой сайт - вот и повторное использование. Функциональная полнота
обеспечивается за счет наследования при создании типа объекта.
|