Home Joomla Код Joomla Модули Joomla Создание MVC модуля для Joomla 1.5!
Создание MVC модуля для Joomla 1.5! PDF Печать E-mail
Автор: cleverscript.ru   

А.Волос: Недавно, бороздя просторы инета наткнулся на интересную (для меня) статью в cleverscript.ru, которая называется "Создание MVC модуля для Joomla 1.5!" Это как раз то, чего мне не хватало на сегодняшний день...



Скачать архив

Как программист, который написал довольно много кода на разных языках, я приобрел определенный опыт в этом деле. Но! Когда я увидел открытый код Joomla, то как говорится возрадовался. Увидеть открытым код сделанный командой профессиональных программистов - это производит впечатление! Чистота стиля. Общая концепция, работа с БД и тд.

Ну как тут удержаться и не поторошить код пытаясь определить взаимосвяь и общую картину. Однако без помощи со стороны не обойтись. И вот она - помощь - как раз в этой статье. Воспроизвожу ее полностью на данном сайте, думаю не нарушаю прав, поскольку ссылаюсь на автора. Да и написана хорошо. Доступно. Приоткрывает завесу над тайной. Ну прочитав такую статью чувствуешь себя уже способным и на другие подвиги в плане изучения и написания новых модулей.

Но, поскольку теория без практики мертва, то разместим новый модуль на своем сайте. И привяжем его к подпункту Тест mod_mvc пункта Код Joomla. Теперь при выборе этого подпункта меню мы видим справа колонку, в которой перечислен introtext всех файлов, которые находятся в главе "Создание MVC модуля для Joomla 1.5!". Модуль работает! Возможно было бы лучше, если бы вывод происходил в виде таблицы, так как в нынешнем виде может происходить (и происходит) наслоение текста друг на друга. Это происходит тогда, когда интротекст более, чем одна строка. Мы можем видеть это на тесте. Это есть поле для дальнейших экспериментов.

Теперь перейдем к чтению оригинальной статьи от cleverscript:


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

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

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

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

Шаблон MVC позволяет разделить данные, представление и обработку на три отдельных компонента

  1. Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера).
  2. Поведение (Controller). Интерпретирует данные, введенные пользователем, и сообщает модели и представление о необходимости выполнения определенных действий.
  3. Представление (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[@]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="" 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. Запуск модуля, фреймверком Joomla осуществляется таким образом (упрощенное описание) - вызывается файл модуля, в нашем случае это файл mod_mvc.php в котором доступны все значения из полей формы в админке модуля, другими словами доступны параметры в виде
пара-значение.

Значение параметра получаем таким образом:

 $source_sec  = $params->get('source_sec');  
Таким образом например, мы получим значение ID раздела, указанного в настройках модуля. Теперь по порядку... Файл модуля mod_mvc.php - это "входная точка" нашего модуля, при его запуске вызывается метод (функция) из helper.php которой передаются параметры о которых я говорил чуть выше, этот метод выполняет определенные операции (выбр из БД, обработка данных и их преобразование и т.д) возвращает данные которые будут выводится через шаблон модуля.

В упрощенном виде это звучит так:

  1. Вызов функции с передачей ей параметров и получение данных возвращаемых этой функцией.
  2. Подключаем в HEAD стили CSS модуля.
  3. Подключение шаблона.
  4. Вывод данных в шаблоне.

В файле 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()" который принимает параметры, и использует их в своей работе.

Эта функция выполняет запрос к БД и выполняет выборку записей (статей) на основе полученных параметров (настроек из админки модуля). И так как выглядит этот класс с принадлежащим ему методом, для начала приведу пример того каким образом принимаются параметры (настройки из админки).

Выглядит это так:

<?php 
defined('_JEXEC') or die('Restricted access');

require_once (JPATH_SITE.DS.'components'.DS.'com_content'.DS.'helpers'.DS.'route.php');

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 align="left" 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);
			$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 align="left" 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 "
".$item->introtext.""; 
			 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, а затем указать ваш шаблон из админки.




Комментарии:

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

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

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

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

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

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

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


Вверх

Обновлено 07.10.2015 11:31