Создание MVC модуля для Joomla 1.5!
В одной из пред-идущих статей я описывал как создать модуль для Joomla 1.5!, но тот модуль был довольно прост как по своей структуре, так и по функциональности. Напомню - он просто отображал в себе (вызывал) модули из определенной позиции, которую пользователь указывал в его настройках из административной панели.
При этом модуль не использовал технологию Model View Controller (MVC) которая значительно расширяет возможности разработчика, упрощает для понимания код и структурирует его части. При этом каждый файл выполняет свою конкретную задачу, о которых и пойдет речь в данной статье.
Но для начала немного теории :), о ней не как нельзя забывать! как говорится:
"Теория без практики мертва, практика без теории слепа!"
И так, "what this MVC?" - это архитектура программного обеспечения, в которой модель данных, пользовательский интерфейс и управляющая логика разделены на три отдельных компонента, и при модификации в каждом отдельном компоненте изменения оказывают минимальное влияние на остальные компоненты. Это одна из важных преимуществ использования MVC в программировании.
Шаблон MVC позволяет разделить данные, представление и обработку на три отдельных компонента 1)Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера). 3)Поведение (Controller). Интерпретирует данные, введенные пользователем, и сообщает модели и представление о необходимости выполнения определенных действий. 2)Представление (View). Отвечает за отображение информации (пользовательский интерфейс, шаблон вывода данных).
Так выглядит простейшая схема MVC:
Хватит теории, по этом вопросу в сети полно материала, переходим к написанию модуля. И как обычно для начала определимся что будет выполнять наш модуль а далее реализуем это в коде)). А выполнять модуль будет такую полезную вещь как вывод превью статей с кратким описанием из интротекста, превью и заголовок будет ссылкой которая будет вести пользователя на страницу с материалом (статью).
Ко всему этому модуль настраивается из админки, и в его настройках можно указать из какого раздела/категории использовать материалы для отображения. Тоесть должна быть возможность указать на вывод материалов из категории определенного раздела, из раздела по всем категориям этого раздела или же отказаться от разделов и категорий и выводить просто последние N-количество статей, которые опубликованы администратором. Ну и конечно же должна быть возможность указания количества выводимых материалов.
И еще чуть не забыл... Реализуем подключение стилевого файла модуля в Head документа.
И так наш моду будет иметь тематическое название - mod_mvc, и содержать в себе такую структуру файлов и каталогов:
Эта структура на картинке показана не просто так, ее необходимо описать в установочном файле модуля "mod_mvc.xml" для того что бы установщик Joomla содал такую же структуру каталогов в директории /modules, и скопировал в все файлы модуля в соответствующие каталоги данной структуры.
Установочный файл "mod_mvc.xml":
- <?xml version="1.0" encoding="utf-8"?>
- <install type="module" version="1.5.0">
- <name>MVC</name>
- <author>Cleverscript</author>
- <creationDate>December 2009</creationDate>
- <copyright></copyright>
- <license>GPL 2.0</license>
- <authorEmail>toorr2p[dog]bigmir.net</authorEmail>
- <authorUrl>http://cleverscript.ru/</authorUrl>
- <version>0.0.1</version>
- <description>Module MVC</description>
- <files>
- <filename module="mod_mvc">mod_mvc.php</filename>
- <filename>helper.php</filename>
- <filename>index.html</filename>
- <filename>tmpl/default.php</filename>
- <filename>tmpl/index.html</filename>
- <filename>tmpl/css/index.html</filename>
- <filename>tmpl/css/style.css</filename>
- </files>
- <params>
- <param name="moduleclass_sfx" type="text" default="" label="Module Class Suffix" description="PARAMMODULECLASSSUFFIX" />
- <param name="source_sec" type="section" default="" label="Раздел" description="Укажите желаемый раздел для вывода превью" />
- <param name="source_cat" type="category" default="" label="Категория" description="Укажите желаемую категорию раздела для вывода превью" />
- <param name="show_all" type="radio" default="0" label="Без раздела и категории" description="Вывод материалов без учета раздела и категориии">
- <option value="0">Нет</option>
- <option value="1">Да</option>
- </param>
- <param name="count" type="text" default="10" label="Количество" description="Укажите желаемое количество выводимых материалов" />
- <param name="template" type="filelist" default="default.php" directory="/modules/mod_mvc/tmpl" filter="\.php$" hide_none="1" hide_default="1" label="Шаблон" description="Выберите шаблон модуля" />
- </params>
- </install>
Начну с описания параметров группы Files (те то перечислены между тегами
- <filename module="mod_mvc">mod_mvc.php</filename>
Это файл-входной точки модуля, то есть наш как-бы наш контроллер который запускается Фреймверком Joomla и далее передает параметры в helper.php который использует их для выборки записей из БД и возвращает данные, это будет описано ниже... А так, на что здесь следует обратить внимание это на атрибут module="" в котором должно содержатся имя модуля, которое в свою очередь соответствует названию файла-входа в модуль ("контроллера"). Исходя из этого установщик Joomla создаст каталог для модуля с названием из параметра module.
Ну а далее обычным образом перечисляем все файлы и директории модуля, уже относительно папки самого модуля (см. иллюстрацию выше).
Файлы модуля описаны, теперь самое интересное, опишем параметры которые будут доступны в настройках модуля из адми-панели, это те которые в группе "params" (заключены между тегами
Первый параметр стандартный - он позволяет указать суффикс класса для выводимого модуля, для применения к нему специфических CSS стилей.
- <param name="moduleclass_sfx" type="text" default="" label="Module Class Suffix" description="PARAMMODULECLASSSUFFIX" />
Содержит атрибуты:
1)name - имя параметра; 2)type - тип (тип поля); 3)default - значение поля по умолчанию; 4)label - ярлык возле поля; 5)description - подсказка-описание для поля
Таким образом создается параметр для модуля, значение которого будет доступно в коде модуля и в зависимости от его значения можно выполнять те или иные действия. при этом данное значение хранится в БД Joomla в таблице "jos_modules" в поле "params", для нашего модуля.
Следующие два параметра "source_sec" и "source_cat" имеют другой тип (атрибут type), первый из них отображает выпадающий список всех разделов сайта, а второй категорий по этим разделам, и в своих значениях содержит id раздела и категории - соответственно. С помощью этих двух типов полей администратор может выбрать какой материал выводить.
Третий параметр "show_all" имеет тип radio и содержит для выбора два значения 0 и 1 где ноль это "Нет" а 1 это "Да", по дефолту (default) устанавливается значение 0 - "Нет".
Четвертый параметр "count" - в нем администратор будет указывать какое количество записей отображать.
Ну и наконец то пятый параметр "template" - позволяет выбрать один из нескольких возможных шаблонов вывода материалов, обратите внимание на атрибут "directory" и "filter" первый указывает на папку c шаблонами модуля, а второй на расширение в названии используемых файлов в качестве шаблона.
Ну вот все параметры описаны и теперь после установки модуля в его административной части будет такая картина:
Двигаемся далее, и подходим к описанию принципа работы модуля по шаблону MVC. Запуск модуля, фреймверком Joomla осуществляется таким образом (упрощенное описание) - вызывается файл модуля, в нашем случае это файл mod_mvc.php в котором доступны все значения из полей формы в админке модуля, другими словами доступны параметры в виде пара-значение.
Значение параметра получаем таким образом:
- $source_sec = $params->get('source_sec');
Таким образом например, мы получим значение ID раздела, указанного в настройках модуля. Теперь по порядку... Файл модуля mod_mvc.php - это "входная точка" нашего модуля, при его запуске вызывается метод (функция) из helper.php которой передаются параметры о которых я говорил чуть выше, этот метод выполняет определенные операции (выбр из БД, обработка данных и их преобразование и т.д) возвращает данные которые будут выводится через шаблон модуля.
В упрощенном виде это звучит так:
1)Вызов функции с передачей ей параметров и получение данных возвращаемых этой функцией. 3)Подключаем в HEAD стили CSS модуля. 2)Подключение шаблона. 3)Вывод данных в шаблоне.
В файле mod_mvc.php это выглядит так:
- <?php
- //параметры доступные модулю
- //print_r($params);
- //Получаем паремтр с именем шаблона
- //Подключаем наш helper и
- //и обращаемся к его классу, вызывая метод - который возвращает нам массив обьектов
- //при этом передавая методу все параметры полученные модулем (из админки)
- $list = MVC::getList($params);
- return;
- }
- //Подключаем CSS
- jimport('joomla.document.html.html');
- $document =& JFactory::getDocument();
- $link = JURI::root().'modules/mod_mvc/tmpl/css/style.css';
- //Подключаем шаблон (который указан из админке)
- $template = JModuleHelper::getLayoutPath('mod_mvc', $tmpl);
- require($template);
- } else {
- }
- ?>
Далее поговорим о helper.php который является по сути "моделью" для получения данных, этот файл содержит в себе один класс - "MVC" который содержит метод (это он вызывается как было описано выше) "getList()" который принимает параметры, и использует их в своей работе.
Эта функция выполняет запрос к БД и выполняет выборку записей (статей) на основе полученных параметров (настроек из админки модуля).
И так как выглядит этот класс с принадлежащим ему методом, для начала приведу пример того каким образом принимаются параметры (настройки из админки).
Выглядит это так:
- class MVC {
- function getList(&$params) {
- $db =& JFactory::getDBO();
- $source_sec = $params->get('source_sec');
- $source_cat = $params->get('source_cat');
- $show_all = $params->get('show_all');
- $count = $params->get('count');
- }
- }
Здесь получаем соединение с БД JFactory::getDBO() и присваиваем значения параметров переменным.
- JParameter Object ( [_raw] => source_sec=9 source_cat=35 template=default.php count= [_xml] => [_elements] => Array ( ) [_elementPath] => Array ( [0] => W:\home\localhost\www\funky_dyk\libraries\joomla\html\parameter\element ) [_defaultNameSpace] => _default [_registry] => Array ( [_default] => Array ( [data] => stdClass Object ( [source_sec] => 9 [source_cat] => 35 [template] => default.php [count] => ) ) ) [_errors] => Array ( ) )
Присвоив переменным значения параметров используем их для формирования запроса к Базе Данных Joomla. А конкретней - в случае если пользователь в настройках модуля указал раздел и категорию и не выбрал опцию "Показывать без учета раздел / категория", а также указал количество выводимых записей (если не указано то 10) формируем запрос следующим образом:
1)Условие в запросе:
- if($show_all == 0){
- $where = 'sectionid='.$source_sec.' AND catid='.$source_cat.' AND ';
- }else{
- $where = '';
- }
2)Сам запрос:
- $query = 'SELECT a.*, s.title as stitle, c.title as ctitle, u.name, ' .
- ' CASE WHEN CHAR_LENGTH(a.alias) THEN CONCAT_WS(":", a.id, a.alias) ELSE a.id END as slug,'.
- ' CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(":", c.id, c.alias) ELSE c.id END as catslug'.
- ' FROM #__content AS a' .
- ' LEFT JOIN #__users AS u ON u.id = a.created_by' .
- ' INNER JOIN #__categories AS c ON c.id = a.catid' .
- ' INNER JOIN #__sections AS s ON s.id = a.sectionid' .
- ' WHERE '.$where.
- ' s.published = 1' .
- ' AND c.published = 1' .
- ' ORDER BY id DESC';
Данный запрос выведет только те записи, которые опубликованы администратором.
Выполняем запрос. Если лимит не указан пользователем то выводим все
- if($count == ''){
- $db->setQuery($query);
- }else{
- $db->setQuery($query, 0, $count);
- }
Загружаем результаты запроса к БД в массив
- $rows = $db->loadObjectList();
А теперь самое интересное, из полученных данных, которые содержатся в виде объекта stdClass, формируем контент с помощью итерации, помещая данные(переменные) в массив в виде ключ=>значение:
- $i=0;
- foreach ($rows as $row) {
- //формируем ссылку
- $lists[$i]->link = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catslug, $row->sectionid));
- //формируем превью
- $regex = "/<img[^>]+src\s*=\s*[\"']\/?([^\"']+)[\"'][^>]*\>/";//поиск картинки
- if ($images) {
- $lists[$i]->image = '<img src="'.$images[1].'" alt="thumbs" class="thumbs" />';
- $lists[$i]->image = '<a href="'. $lists[$i]->link .'">'.$lists[$i]->image.'</a>';
- }
- //формируем интротекст
- $lists[$i]->paramss = $params;
- $i++;
- }
В начале формируем URL который будет указывать на материал и использоваться в ссылке "Далее" в шаблоне модуля, для этого в самом начале файла нужно было добавить подгрузку файла route.php, в котором содержится класс ContentHelperRoute и вызываемый нами метод getArticleRoute которому в качестве аргументов передаются параметры статьи - id материала с псевдонимом(через двоеточие), id категории и id раздела. При этом формируется ссылка на материал и заносится в элемент массива с ключом "link":
- $lists[$i]->link = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catslug, $row->sectionid));
Далее формируем превью (изображение к статье), для этого приводим весь интро-текст и фулл-текст к нижнему регистру и используем поиск тега IMG сразу и в introtext и в fulltext.
Первый найденный тег IMG (или из интро-текста или фул-текста), будет использоваться в качестве превью, вернее из этого тега будет извлечен параметр SRC содержащий путь к картинке, и далее использован в формировании картинки:
- //формируем превью
- $regex = "/<img[^>]+src\s*=\s*[\"']\/?([^\"']+)[\"'][^>]*\>/";//поиск картинки
- if ($images) {
- $lists[$i]->image = '<img src="'.$images[1].'" alt="thumbs" class="thumbs" />';
- $lists[$i]->image = '<a href="'. $lists[$i]->link .'">'.$lists[$i]->image.'</a>';
- }
К тому же эта картинка еще и является ссылкой на материал.
Следующий этап - формирование интротекста:
- //формируем интротекст
При этом с помощью функции strip_tags() удаляем все теги, оставляя только текст.
Сформировав массив с данными возвращаем его в качестве результата работы функции:
- function getList(&$params) {
- ...
- //возвращаем многомерный массив объектов
- return $lists;
- }
Теперь поговорим о шаблоне, файле default.php который находится в папке tmpl. Этот файл подгружается ниже вызова функции getList() в нашем главном файле-входной точки модуля mod_mvc.php (см. выше), и поэтому в нем доступен результат вызова функции.
Так как этим результатом является многомерный массив то в шаблоне обрабатываем его соответствующим образом:
- <?php
- echo "<ul class='mod_mvc'>";
- foreach ($list as $item){
- echo '<li>';
- endif;
- echo '</li>';
- }
- echo "</ul>";
- ?>
Здесь с помощью итерации извлекаем данные из массива и помещаем их в нужные вам контейнеры, для наглядности я решил использовать не маркированный список UL, в котором каждый LI это отдельное краткое описание статьи с превью и ссылкой "Далее".
А оформление CSS прописывается в файле style.css который находится в папке css шаблона модуля, и подключается в документ из файла модуля mod_mvc.php, перед подгрузкой шаблона модуля (см. выше).
В данном примере он содержит описание для элементов списка:
- ul.mod_mvc li{width:100%;height:160px;}
Структуру шаблона вы можете изменять по своему усмотрению или же просто создать еще один шаблон и положить его в папку tmpl, а затем указать ваш шаблон из админки.
PS. И не забудьте подписатся на ленту новостей RSS

Комментарии
Спасибо
У меня одна вопрос, как можно работать с языковыми файлами, при создания модуля??
Не в обиду владельцу сайта, но ИМХО, над дизайном стоило бы поработать чуть подольше и поусерднее. Всё-таки внешний вид сайта играет немаловажную роль. Могу судить по личному опыту: после того как-на rem-stroy.com - моём сайте был нарисован и свёрстан новый диз, читатели стали задерживаться гораздо надольше, да и самому приятно смотреть. Подумайте над этим, думаю моё мнение разделят многие..
Кстате поправьте отображение кода, xml не верно отображает
$list = MVC::getList($p arams); //дык откуда $params вариабла появилась?
$params - доступен в модуле по умолчанию, и содержит обьект StdClass Object со всеми параметрами модуля, которые устанавливаются в админ-панели модуля.
Выше в статье описано как создавать админку модуля с настройками, вот значения этих настроек и присутствуют в $params.
ru-RU.mod_имя_модуля.ini и поместите его в папку language/ru-RU/.
Что касается XML установщика то в нем смотрите содержимое атрибутов name='...' или description='...' в param копируете их значения и переносите в файл ru-RU.mod_имя_модуля.ini, где затем переопределяете (переводите).
Например если вот так в xml установщике:
...description="The number of items to display (default is 10)"...
то в ru-RU.mod_имя_модуля.ini пишете так:
THE NUMBER OF ITEMS TO DISPLAY (DEFAULT IS 10)=Количество отображаемых статей (по умолчанию - 10)
Всем тем, кто собирается создавать модуль сам, ссылка на документацию Joomla-Framework:
http://api.joomla.org/elementindex_Joomla-Framework.html
Хотел указать на недочет.
В коде очень часто встречается "жестко зашитое" название модуля - "mod_mvc", например:
$link = JURI::root().'modules/mod_mvc/tmpl/css/style.css';
$template = JModuleHelper:: getLayoutPath('mod_mvc', $tmpl);
и т.д
Если кто-то захочет взять этот пример за скелет, а я думаю многие начинающие захотят( я например:), для того чтобы поменять имя модуля "mod_mvc" на что-то своё придется побегать по коду.
Только у меня выводит весь текст новости, как его ограничить буквально несколькими строчками? Подскажите, пожалуйста!
echo "".substr($item->introtext, 0, 150)."";
выведет текcт в 150 символов
Вот бы еще для удобства доставать из бд заголовки материала. Это в запрос включить надо, я правильно понимаю?
Рад что получилось;) В запрос это включено, вам нужно добавить элемент в объект который формируется в helper.php, этот элемент и будет содержать заголовок:
$lists[$i]->title = $row->title;
А в tpl/default.php уже выводитьь его в итерации через:
echo $item->title;
Подскажите, пожалуйста, что нужно переделать в модуле, чтобы под 1.7 работал?