Создание MVC модуля для Joomla 1.5!

Среда, 12 Май 2010

 

В одной из пред-идущих статей я описывал как создать модуль для Joomla 1.5!, но тот модуль был довольно прост как по своей структуре, так и по функциональности. Напомню - он просто отображал в себе (вызывал) модули из определенной позиции, которую пользователь указывал в его настройках из административной панели.

 

При этом модуль не использовал технологию Model View Controller (MVC) которая значительно расширяет возможности разработчика, упрощает для понимания код и структурирует его части. При этом каждый файл выполняет свою конкретную задачу, о которых и пойдет речь в данной статье.

 

Но для начала немного теории :), о ней не как нельзя забывать! как говорится:

 

"Теория без практики мертва, практика без теории слепа!"

 

И так, "what this MVC?" - это архитектура программного обеспечения, в которой модель данных, пользовательский интерфейс и управляющая логика разделены на три отдельных компонента, и при модификации в каждом отдельном компоненте изменения оказывают минимальное влияние на остальные компоненты. Это одна из важных преимуществ использования MVC в программировании.

 

Шаблон MVC позволяет разделить данные, представление и обработку на три отдельных компонента 1)Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера). 3)Поведение (Controller). Интерпретирует данные, введенные пользователем, и сообщает модели и представление о необходимости выполнения определенных действий. 2)Представление (View). Отвечает за отображение информации (пользовательский интерфейс, шаблон вывода данных).

 

Так выглядит простейшая схема MVC:

 

Создание MVC модуля для Joomla1.5!

 

Хватит теории, по этом вопросу в сети полно материала, переходим к написанию модуля. И как обычно для начала определимся что будет выполнять наш модуль а далее реализуем это в коде)). А выполнять модуль будет такую полезную вещь как вывод превью статей с кратким описанием из интротекста, превью и заголовок будет ссылкой которая будет вести пользователя на страницу с материалом (статью).

 

Ко всему этому модуль настраивается из админки, и в его настройках можно указать из какого раздела/категории использовать материалы для отображения. Тоесть должна быть возможность указать на вывод материалов из категории определенного раздела, из раздела по всем категориям этого раздела или же отказаться от разделов и категорий и выводить просто последние N-количество статей, которые опубликованы администратором. Ну и конечно же должна быть возможность указания количества выводимых материалов.

 

И еще чуть не забыл... Реализуем подключение стилевого файла модуля в Head документа.

 

И так наш моду будет иметь тематическое название - mod_mvc, и содержать в себе такую структуру файлов и каталогов:

 

Создание MVC модуля для Joomla1.5!

 

 

Эта структура на картинке показана не просто так, ее необходимо описать в установочном файле модуля "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 (те то перечислены между тегами ) - это и есть наша структура которую будет формировать установщик Joomla при инсталляции модуля, здесь в строгом порядки указываем все файлы ходящие в наш модуль. Первый параметр немного отличается от остальных и имеет такой вид:

 

 
<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 модуля для Joomla1.5!

 

Двигаемся далее, и подходим к описанию принципа работы модуля по шаблону 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
  defined('_JEXEC') or die('Restricted access');
 
  //параметры доступные модулю
  //print_r($params);
 
  //Получаем паремтр с именем шаблона
  $tmpl = str_replace('.php', '', $params->def('template', 'default.php'));
 
  //Подключаем наш helper и
  //и обращаемся к его классу, вызывая метод  - который возвращает нам массив обьектов
  //при этом передавая методу все параметры полученные модулем (из админки)
  require_once (dirname(__FILE__).DS.'helper.php');
  $list = MVC::getList($params);
  if (!count($list)) {
    return;
  }
 
  //Подключаем CSS
  jimport('joomla.document.html.html');
  $document =& JFactory::getDocument();
  $link = JURI::root().'modules/mod_mvc/tmpl/css/style.css';
  $attribs = array('type' => 'text/css');
  $document->addHeadLink(JRoute::_($link), 'stylesheet', 'rel', $attribs);
 
  //Подключаем шаблон (который указан из админке)
  $template = JModuleHelper::getLayoutPath('mod_mvc', $tmpl);
  if (file_exists($template)) {
    require($template);
  } else {
    echo JText::_('ERROR_TEMPLATE');
  }
?>
 

 

Далее поговорим о 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() и присваиваем значения параметров переменным. $params - это объект (экземпляр класс stdClass), который является удобным контейнером для передачи данных, в данном случае параметров, print_r($params) выведет на экран такое:

 

 
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;
$lists  = array();
foreach ($rows as $row) {
  //формируем ссылку
  $lists[$i]->link = JRoute::_(ContentHelperRoute::getArticleRoute($row->slug, $row->catslug, $row->sectionid));
  //формируем превью
  $text = strtolower($row->introtext.$row->fulltext);
  $regex  = "/<img[^>]+src\s*=\s*[\"']\/?([^\"']+)[\"'][^>]*\>/";//поиск картинки
  preg_match ($regex, $text, $matches);
  $images  = (count($matches)) ? $matches : array();
  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]->introtext = strip_tags($row->introtext);
  $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 содержащий путь к картинке, и далее использован в формировании картинки:

 

 
//формируем превью
$text = strtolower($row->introtext.$row->fulltext);
$regex  = "/<img[^>]+src\s*=\s*[\"']\/?([^\"']+)[\"'][^>]*\>/";//поиск картинки
preg_match ($regex, $text, $matches);
$images  = (count($matches)) ? $matches : array();
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]->introtext = strip_tags($row->introtext);
 

 

При этом с помощью функции strip_tags() удаляем все теги, оставляя только текст.

 

Сформировав массив с данными возвращаем его в качестве результата работы функции:

 

 
function getList(&$params) {
 
  ...
 
  //возвращаем многомерный массив объектов
  return $lists;
}
 

 

Теперь поговорим о шаблоне, файле default.php который находится в папке tmpl. Этот файл подгружается ниже вызова функции getList() в нашем главном файле-входной точки модуля mod_mvc.php (см. выше), и поэтому в нем доступен результат вызова функции.

 

Так как этим результатом является многомерный массив то в шаблоне обрабатываем его соответствующим образом:

 

 
<?php
  defined('_JEXEC') or die('Restricted access');
 
  echo "<ul class='mod_mvc'>";
 
    foreach ($list as $item){
       echo '<li>';
       if (!empty($item->image)) : 
          echo $item->image;
       endif; 
       echo "<p>".$item->introtext."</p>"; 
       echo "<a href='".$item->link."'>Далее</a>";
       echo '</li>';
    }
  echo "</ul>";
?>
 

 

Здесь с помощью итерации извлекаем данные из массива и помещаем их в нужные вам контейнеры, для наглядности я решил использовать не маркированный список UL, в котором каждый LI это отдельное краткое описание статьи с превью и ссылкой "Далее".

 

А оформление CSS прописывается в файле style.css который находится в папке css шаблона модуля, и подключается в документ из файла модуля mod_mvc.php, перед подгрузкой шаблона модуля (см. выше).

 

В данном примере он содержит описание для элементов списка:

 

 
ul.mod_mvc li{width:100%;height:160px;}
 

 

Структуру шаблона вы можете изменять по своему усмотрению или же просто создать еще один шаблон и положить его в папку tmpl, а затем указать ваш шаблон из админки.

 

Download

 

PS. И не забудьте подписатся на ленту новостей RSS

Комментарии 

 
anonim Пятница, 09 Июль 2010

Отличная, подробная статья. В русскоязычном интернете так мало написано про программировани е для Joomla. Автору большое спасибо.

 

 
 
anonim Вторник, 13 Июль 2010

очень, очень полезная инфо.
Спасибо

 

 
 
anonim Вторник, 13 Июль 2010

Рад что статья вышла полезной, задавайте вопросы если что то не ясно описано.

 

 
 
anonim Понедельник, 19 Июль 2010

Спасибо, хорошая статья.

У меня одна вопрос, как можно работать с языковыми файлами, при создания модуля??

 

 
 
anonim Понедельник, 19 Июль 2010

И вам спасибо за вопрос по существу)) этот вопрос решу в ближайшее время.

 

 
 
anonim Воскресенье, 29 Август 2010

Прочитано, принято, понято :) то что искал)
Не в обиду владельцу сайта, но ИМХО, над дизайном стоило бы поработать чуть подольше и поусерднее. Всё-таки внешний вид сайта играет немаловажную роль. Могу судить по личному опыту: после того как-на rem-stroy.com - моём сайте был нарисован и свёрстан новый диз, читатели стали задерживаться гораздо надольше, да и самому приятно смотреть. Подумайте над этим, думаю моё мнение разделят многие..

 

 
 
anonim Понедельник, 30 Август 2010

Новый дизайн уже отрисован, нужно время на верстку, а его как всегда нет(((

 

 
 
anonim Четверг, 09 Сентябрь 2010

спасибо!!!

 

 
 
anonim Пятница, 29 Октябрь 2010

Автор, Вам спасибо.
Кстате поправьте отображение кода, xml не верно отображает

$list = MVC::getList($p arams); //дык откуда $params вариабла появилась?

 

 
 
anonim Пятница, 29 Октябрь 2010

Спасибо за комментарий и вопрос.
$params - доступен в модуле по умолчанию, и содержит обьект StdClass Object со всеми параметрами модуля, которые устанавливаются в админ-панели модуля.

Выше в статье описано как создавать админку модуля с настройками, вот значения этих настроек и присутствуют в $params.

 

 
 
anonim Четверг, 04 Ноябрь 2010

Очень полезная статья..хотелось бы чтобы вы написали статью про то..вообщем у меня возникла проблема есть модуль на английском языке,нашёл к нему фаил руссификации но к нему надо же .xml прописать,как это сделать?

 

 
 
anonim Четверг, 04 Ноябрь 2010

Для этого правильно переименуйте (если требуется) данный файл русификации
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)

 

 
 
anonim Вторник, 09 Ноябрь 2010

Полезная статья, спасибо! Но, встречаются орфографические ошибки.

 

 
 
anonim Суббота, 13 Ноябрь 2010

Отличная статья на тему: "Создание модуля Joomla для начинающих".
Всем тем, кто собирается создавать модуль сам, ссылка на документацию Joomla-Framework:
http://api.joomla.org/elementindex_Joomla-Framework.html

 

 
 
anonim Суббота, 20 Ноябрь 2010

Читаю посты у вас уже какоето время. И могу сказать сразу что буду продолжать это делать :P

 

 
 
anonim Среда, 20 Апрель 2011

Статья отличная, без шуток!
Хотел указать на недочет.
В коде очень часто встречается "жестко зашитое" название модуля - "mod_mvc", например:

$link = JURI::root().'modules/mod_mvc/tmpl/css/style.css';
$template = JModuleHelper:: getLayoutPath('mod_mvc', $tmpl);
и т.д
Если кто-то захочет взять этот пример за скелет, а я думаю многие начинающие захотят( я например:), для того чтобы поменять имя модуля "mod_mvc" на что-то своё придется побегать по коду.

 

 
 
anonim Среда, 20 Апрель 2011

Вы предлагаете вынести в константу?

 

 
 
anonim Пятница, 26 Август 2011

Охринеть то что надо )) Уважаемый почтенный поклон тебе )) с одного раза нашел пост где описали как надо правильно делать.Удачи вам!!!

 

 
 
anonim Вторник, 29 Ноябрь 2011

Статья действительно полезная, мне очень пригодилась как новичку.
Только у меня выводит весь текст новости, как его ограничить буквально несколькими строчками? Подскажите, пожалуйста!

 

 
 
anonim Вторник, 29 Ноябрь 2011


echo "".substr($item->introtext, 0, 150)."";


выведет текcт в 150 символов

 

 
 
anonim Среда, 30 Ноябрь 2011

Спасибо большое за подсказку! У меня благодаря Вам получилось! :)
Вот бы еще для удобства доставать из бд заголовки материала. Это в запрос включить надо, я правильно понимаю?

 

 
 
anonim Четверг, 01 Декабрь 2011

>>>Olga
Рад что получилось;) В запрос это включено, вам нужно добавить элемент в объект который формируется в helper.php, этот элемент и будет содержать заголовок:

$lists[$i]->title = $row->title;

А в tpl/default.php уже выводитьь его в итерации через:

echo $item->title;

 

 
 
anonim Воскресенье, 04 Декабрь 2011

Да-да-да! Спасибо за помощь. Искренне благодарна)))

 

 
 
anonim Вторник, 31 Январь 2012

Добрый день.
Подскажите, пожалуйста, что нужно переделать в модуле, чтобы под 1.7 работал?

 

 
 
anonim Четверг, 02 Февраль 2012

Жорж, откройте любой стандартный модуль входящий в сборку 1,7 (советую mod_latestnews) , и посмотрите как изменен установочный xml, а также возможно прийдется изменить SQL запрос - в связи с изменениями в структуре базы данных. Так одним махом и не скажешь, но начать нужно с установочного XML, а затем уже поставив модуль на сайт, отлавливать ошибки и исправлять код под 1,7

 

 

Добавить комментарий