Цель лекции: Изучить базовые сведения об архитектуре Joomla. Получить представление о функционировании такого типа расширений как компоненты.

 

Предисловие

Важнейшим источником сведений о программировании под Joomla является официальная документация к этой системе [5]. Однако на момент составления данного курса эта документация является достаточно неполной, особенно с учетом того, что ряд статей относится к старой версии Joomla (1.5). Код расширений, написанных под Joomla 1.5, несколько отличается от кода, написанного под недавно вышедшие версии Joomla 1.6, 1.7 и 2.5.

Руководство по разработке компонента на официальном сайте Joomla начинается сразу с написания кода в соответствии с архитектурой MVC (Модель – Вид – Представление). Такой подход едва ли удобен, так как значительно легче для студента было бы начать с изучения основ программирования под Joomla, с изучения основных классов фреймворка этой системы и лишь потом переходить на архитектуру MVC. Более удобный для обучения подход применяется в книге [3]. Она строится от простого к сложному: сначала рассматривается разработка простого компонента без использования классов, реализующих MVC, а затем происходит переход на эту архитектуру. Поэтому в практической части данного курса мы будем следовать порядку изложения этой книги. Кроме того, большая часть программного кода, составляющего практическую часть данного курса, основана на листингах из этой книги. Однако исходные коды, взятые из книги [3], написаны под Joomla 1.5 и устарели. Для данного курса они были изменены для использования в Joomla 1.7 и перенесены на другую предметную область. Переход на Joomla 1.7 потребовал расмотрения в практической части курса таких отсутствовавших в [3] вопросов, как создание пунктов меню в панели управления, использование языковых файлов. Большее внимание уделено работе с навигационной цепочкой сайта.

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

Следует отметить отсутствие литературы о программировании под Joomla на русском языке. Исключением является небольшое руководство [6], написанное тем же Джозефом ЛеБланком и опубликованное в русском переводе в электронном журнале PHPInside за ноябрь – декабрь 2005 г.

Отметим также книгу [2], которая тоже рассматривает программирование для старой версии Joomla.

В начале 2012 г. вышла книга [1], восполняющая недостаток сведений о программировании под Joomla 1.6/1.7/2.5.

Введение

Для системы управления контентом Joomla созданы тысячи расширений. Тем не менее, использовать готовое решение не всегда целесообразно. Стороннее расширение может быть слишком дорогим или перегружать сервер ненужными для конкретной задачи функциями. Для нестандартной задачи готового решения может вовсе не найтись.

Иногда достаточно воспользоваться одним из конструкторов контента (CCK) для Joomla, позволяющих создавать свои шаблоны для материалов. Однако и CCK - не панацея, и возможно, что и он окажется бессилен. В таком случае возникает необходимость написать собственное расширение.

Может случиться, что готовое решение начнет работать некорректно и придется искать в нем ошибку. Тогда, чтобы разобраться в его коде, программисту понадобится знание принципов построения расширений под Joomla.

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

Архитектура Joomla

Фреймворк Joomla состоит из трех уровней (рис. 1.1):

  1. уровень фреймворка;
  2. уровень приложения;
  3. уровень расширений.



01 01


Рис. 1.1.  Фреймворк JoomlaУровень фреймворка обеспечивает базовую функциональность Joomla с помощью набора библиотек и плагинов и собственно фреймворка Joomla:

  • фреймворк Joomla (или "ядро") - набор классов, обеспечивающих базовую функциональность Joomla. Названия этих классов начинаются с буквы "J" и говорят сами за себя: JDatabase, JUser, JForm, JEditor и т.д.;
  • библиотеки требуются для работы фреймворка или сторонних расширений;
  • плагины расширяют функциональность фреймворка.

Уровень приложения состоит из приложений, которые расширяют абстрактный класс JApplication. Приложение - глобальный объект, использующийся для обработки запросов.

В этот уровень входят следующие приложения:

  • JInstallation запускается при установке Joomla. После завершения установки необходимо удалить директорию installation, которая как раз и содержит данное приложение. В дальнейшем установка расширений выполняется с помощью приложения JAdministrator;
  • JAdministrator управляет всеми функциями для администрирования Joomla;
  • JSite отвечает за компоновку и отображение фронтенда;
  • XML-RPC позволяет администрировать сайт Joomla удаленно.

Уровень расширений состоит из расширений фреймворка Joomla и приложений:

  • компоненты - основной тип расширений Joomla. При каждом обращении к Joomla происходит вызов соответствующего компонента. Например, при отображении какой-либо страницы сайта происходит вызов компонента com_content;
  • модули используются для отображения небольших фрагментов контента, обычно в левой или правой колонке или верхней или нижней областях страницы;
  • плагины позволяют зарегистрировать функции и классы для обработки каких-либо событий, вызванных Joomla, например, поиск по сайту;
  • языковые файлы позволяют представить контент Joomla на нескольких языках;
  • шаблоны отвечают за внешний вид сайта.

Фронтенд и бэкенд

Joomla делится на фронтенд - часть сайта, доступная пользователю, и бэкенд - систему администрирования сайта. Соответственно, в Joomla всего две точки входа - index.php для фронтенда и /administrator/index.php для бэкенда. Чтобы вызвать какой-либо установленный на сайте компонент, необходимо передать его имя (с префиксом "com_") скрипту index.php или /administrator/index.php в переменной option в строке URL. Например, переход по ссылке http://localhost/joomla/index.php?option=com_banners приведет к вызову компонента banners.

Большинство компонентов для Joomla делятся на фронтенд и бэкенд, и их код распределяется по двум папкам, каждая из которых называется по схеме com_<имя компонента>. В каждой из этих папок должен находиться файл, являющийся точкой входа, и называющийся так же, как компонент, т.е. <имя компонента>.php. Схематически это можно изобразить так:

administrator
|- components
..|- com_mycomponent
....|- mycomponent.php
components
..|- com_mycomponent
....|- mycomponent.php

 

Предопределенные константы

В Joomla определен ряд констант, хранящих значения путей: JPATH_BASE - путь к корневой директории текущего приложения; JPATH_ROOT - путь к корневой директории сайта, JPATH_COMPONENT - путь к директории компонента, JPATH_COMPONENT_SITE - путь к фронтенду компонента, JPATH_COMPONENT_ADMINISTRATOR - путь к бэкенду компонента и т.д. Полный их список можно найти в документации. Все эти константы возвращают значения абсолютных путей в файловой системе. Если вам необходимо получить путь для использования в URL, следует воспользоваться методом JURI::base().

В файле index.php, расположенном в корневой директории Joomla, определена константа _JEXEC. Большинство PHP-файлов, написанных под Joomla, начинаются с выражения

defined('_JEXEC') or die('Restricted access');

 

Данное выражение осуществляет проверку, был ли файл, в котором оно записано, вызван из Joomla. Таким путем запрещается доступ к файлу извне, чтобы предотвратить взлом сайта.

Еще одна популярная константа Joomla - DS, разделитель директорий, принятый в конкретной операционной системе (например, прямой или обратный слеш).

Языковые файлы

Joomla позволяет создать мультиязыковый сайт, задавая для каждого пользователя язык сайта и панели управления. Данная возможность реализована следующим образом: в кодах расширений при необходимости вывести на экран какой-либо заранее известный текст (например, сообщение об успешном выполнении запроса пользователя) вместо этого текста записывается его эквивалент (ключ). Для каждого языка, поддерживающегося данным расширением, создаются языковые файлы, которые хранят переводы для всех ключей, встретившихся в кодах расширения. Например, для ключа "COM_MYCOMPONENT_HELLO_WORLD" перевод на английский язык может задаваться как "Hello, world!", на русский - "Здравствуй, мир!", на французский - "Bonjour le monde!" и т.д.

Языковые файлы фронтенда хранятся в папке /language/<ln-LN>, где <ln-LN> - код языка по стандарту RFC3066. Файл должен называться по схеме <ln-LN>.<префикс><имя расширения>.ini, где префикс зависит от вида расширения: "com_" (компонент), "mod_" (модуль), "tpl_" (шаблон) и т.д. Например, путь к языковому файлу компонента contact для русского языка следующий:/language/ru-RU/ru-RU.com_contact.ini

Языковые файлы бэкенда хранятся в папке /administrator/language/<ln-LN>.

Кроме файлов .ini, для расширения должен также быть создан файл *.sys.ini, в котором могут храниться переводы сообщений, выводящихся после установки расширения, переводы пунктов меню, создающихся для компонента в панели управления, переводы параметров компонента и переводы надписей, выводящихся в менеджере расширений. Например, путь к файлу .sys.ini компонента contact для русского языка выглядит так: /administrator/language/ru-RU/ru-RU.com_contact.sys.ini

Содержимое языкового файла состоит из пар "ключ-значение" и, при необходимости, комментариев. Пустые строки игнорируются. Комментарии начинаются с символа ";". Например:

; Это комментарий

 

Ключ - это строка для перевода, а значение - это перевод данной строки на заданный язык. Ключ отделяется от значения знаком равенства:

КЛЮЧ=Значение

 

Например:

COM_CONTACT="Контакты"

 

Ключ должен быть записан в верхнем регистре и не должен содержать пробелы. Все ключи во фронтенде должны начинаться со строки <префикс><имя расширения>_, например:

COM_CONTACT_CHANGE_CONTACT_BUTTON

 

Значение (перевод ключа) должно быть заключено в двойные кавычки. Если значение к тому же содержит двойные кавычки, то они должны быть записаны в виде HTML-сущности, например, &quot.

Для использования переводов применяются методы статического класса JText _(), sprint() и printf().

Простейший способ вывести перевод строки - использовать метод JText::_(), который просто переводит строку, переданную ему параметром. Например:

echo JText::_('COM_MYCOMPONENT_HELLO_WORLD');

 

Если перевод для заданной строки не будет найден в языковых файлах, то метод _() вернет саму эту строку. Перед поиском строка будет переведена в верхний регистр, поэтому не имеет значения, в каком регистре ее записать в коде.

Если в строку необходимо включить какие-либо значения, то используются методы JText sprintf() и printf(), аналогичные одноименным функциям в PHP. Их параметрами являются строка для перевода и любое количество аргументов для подстановки в переведенную строку. Сами параметры не будут переведены. Методы sprintf() и printf() различаются тем, что printf() выводит получившуюся строку на экран и возвращает ее длину, а sprintf() возвращает саму строку и ничего не выводит.

Например, если в языковом файле ru-RU.com_mycomponent.ini задано

COM_MYCOMPONENT_THANK_YOU="Спасибо за Ваше сообщение, %s!"

 

а в коде расширения имеется строка

echo JText::sprintf('COM_MYCOMPONENT_THANK_YOU', 'Вася');

 

то результатом будет вывод на экран строки "Спасибо за Ваше сообщение, Вася!".

Аргументы задаются так же, как в одноименных функциях PHP: %s означает строку, %d - целое число, %f - число с плавающей точкой и т.д.

Паттерн "фабрика" (класс JFactory)

В Joomla существует статический класс JFactory, реализующий паттерн "фабрика". Методы данного класса (getApplication(), getDate(), getDbo(), getDocument(), getLanguage(), getURI(), getUser(), getMailer(), getEditor() и др.) позволяют получить доступ к соответствующим глобальным объектам фреймворка (JApplication, JDate, JDatabase, JDocument, JLanguage, JURI, JUser, JMail, JEditor и др.), ряд которых будет рассмотрен далее.

Рассмотрим пример получения доступа к объекту JUser:

$user = JFactory::getUser();
if ($user->guest)
  echo "Вы не вошли на сайт";
else
  echo "Вы вошли на сайт как ".$user->name;

 

Обратите внимание на знак амперсанда перед вызовом метода getUser(). Мы получаем ссылку на объект-представитель текущего пользователя. Если пропустить амперсанд, то будет создана копия этого объекта и изменения, которые мы будем в ней производить, не затронут оригинал.

HTTP-запрос (класс JRequest)

В Joomla вместо непосредственного использования глобальных массивов $_GET, $_POST, $_FILES, $_COOKIE, $_ENV, $_SERVER и $_REQUEST удобнее применять класс JRequest. Его методы пропускают данные, введенные пользователем, через фильтр во избежание инъекций.

Для получения переменных запроса GET/POST используется метод 

mixed getVar(string $name, string $default=null, string $hash='default', string $type='none', int $mask=0)

где:

$name имя переменной;
$default значение по умолчанию, которое вернет метод getVar(), если значение переменной не задано;
$hash источник данных, по умолчанию они будут получены из массива $_REQUEST. Явное указание массива GET или POST повысит безопасность кода;
$type тип ожидаемого значения:
INT  
INTEGER  
FLOAT  
DOUBLE  
BOOL  
BOOL  
WORD  
ALNUM допускает только буквенно-цифровые значения;
CMD  
BASE64 допускает только те символы, которые могут быть представлены в кодировке base64 (т.е. a-z, A-Z, 0-9, /, + и =);
STRING  
ARRAY  
PATH исключает возможность атаки. Например, если исходное значение содержало /./ или /../, то вместо него метод вернет пустую строку;
USERNAME удаляет управляющие символы (0x00 - 0x1F), 0x7F, <, >, ", ', % и &;
$mask константа, задающая опции фильтрации:
JREQUEST_NOTRIM не удалять пробелы в начале и конце строки;
JREQUEST_ALLOWRAW без какой-либо фильтрации;
JREQUEST_ALLOWHTML не удалять HTML-код, но пропустить значение через фильтр (в частности, удалить опасные теги - script, applet, iframe и др.).

Эти константы не заключаются в кавычки, т.к. это не строки, а статические переменные. Если ни одной опции не задано, то HTML-теги, а также пробелы в начале и конце строки будут удалены.

Пример:

$answer = JRequest::getVar('answer', 'no answer', 'post', 'string', JREQUEST_ALLOWRAW);

 

Если нужно получить весь массив переменных запроса в отфильтрованном виде, используется

mixed get(string $hash='default', int $mask=0)

Например, получим массив $_POST:

$arr = JRequest::get('post');

 

Для присвоения переменным запроса значений используется метод

string setVar(string $name, string $value=null, string $hash='method', bool $overwrite=true)

Если $overwrite=false и в запросе уже задано значение переменной $name, то метод просто вернет само это значение. В противном случае переменной будет присвоено значение $value, а метод вернет старое значение $name.

Пример:

JRequest::setVar('var1', 'val1');

 

Класс JRequest содержит также методы, позволяющие получить значение определенного типа: getBool(), getCmd(), getFloat(), getInt(), getString(), getWord().

Приложение (класс JApplication)

Очередь сообщений

В Joomla существует очередь сообщений - массив строк, которые будут выведены на экран при следующей загрузке какой-либо страницы. Стандартными являются три типа сообщений (рис. 1.2): message (собственно сообщение), notice (предупреждение) и error (ошибка):



01 02


Рис. 1.2.  Типы сообщенийДля добавления сообщений в очередь используется метод 

void enqueueMessage(string $msg, [string $type = 'message'])

где:

$msg - текст сообщения;
$type - тип сообщения.

Например:

global $app;
$app->enqueueMessage('Message');
$app->enqueueMessage('Notice', 'notice');
$app->enqueueMessage('Error', 'error');

 

В данном примере $app - это глобальный объект JApplication.

Для получения копии очереди сообщений используется метод 

array getMessageQueue()

Например, для предыдущей очереди из трех сообщений он возвращает массив:

Array 
(
  [0]=>Array
   (
    [message]=>Message
    [type]=>message
  )
  [1]=>Array 
  (
    [message]=>Notice
    [type]=>notice
  )
  [2]=>Array
  (
    [message]=>Error
    [type]=>error
  )
)

 

Перенаправление

Для перенаправления пользователя к другому URL используется метод

void redirect(string $url, string $msg='', string $msgType='message', bool $moved=false)


где:

$url - URL, к которому перенаправляется пользователь;
$msg - сообщение, которое должно быть при этом выведено;
$msgType - тип сообщения;
$moved - при значении true браузер получит код состояния "301 Permanently Moved", в противном случае - "303 See Other".

Данный метод добавляет сообщение к очереди сообщений, перенаправляет браузер пользователя к заданному URL и завершает работу приложения Joomla. Например:

global $app;
$app->redirect('index.php', JText::_('NOTICE'), 'notice');

 

Второй способ организации перенаправления - использовать метод JController::setRedirect(), который будет рассмотрен ниже вместе с другими методами класса JController.

Получение параметров конфигурации сайта

В число параметров конфигурации сайта входят настройки базы данных, почты, сервера, FTP, метаданных, SEO и другие. Для получения значений этих параметров используется метод

mixed getCfg(string $varname, string $default=null)

 

где $varname - название параметра.

Для примера получим название сайта:

global $app;
echo $app->getCfg('sitename');

 



Определение типа запущенного приложения Joomla

Чтобы определить, откуда запущен код, можно использовать методы

int getClientId()
bool isAdmin()
bool isSite()

Метод getClientId() возвращает id запущенного приложения: 0 (сайт), 1 (панель управления), 2 (установщик).

Метод isAdmin() определяет, является ли запущенное приложение бэкендом, isSite() - фронтендом.

Панели инструментов (класс JToolBarHelper)

Joomla автоматически загружает в верхней правой части экрана бэкенда компонента файл, который называется toolbar.<имя компонента>.php. Таким образом можно отображать различные панели инструментов.

Класс JToolBarHelper содержит методы, которые генерируют HTML-код для построения кнопок панелей инструментов. Для отображения кнопок, которые часто используются в компонентах, - "Сохранить", "Отменить", "Удалить" - существуют готовые методы этого класса. Их список можно найти в документации Joomla: http://docs.joomla.org/JToolBarHelper.

Для методов addNew(), publish(), publishList(), makeDefault(), unpublish(), editList(), save(), apply() заданы по умолчанию два параметра - задача (об ее значении будет сказано ниже) и подпись. Например, значения этих параметров по умолчанию для метода editList() выглядят так: $task = 'edit', $alt = 'Edit'. Можно задавать свои задачу и подпись, передавая их как, соответственно, первый и второй параметры.

Метод для удаления объектов имеет прототип

void deleteList(string $msg =, string $task = 'remove', string $alt = 'JTOOLBAR_DELETE')

где $msg - это текст сообщения с просьбой подтвердить удаление объектов. Если этот параметр задан, то при нажатии кнопки для удаления будет выводиться окно с заданным сообщением и объекты будут удалены только после нажатия кнопки "ОК" в этом окне. Если же параметр $msg не задан, то объекты будут удаляться без предупреждения.

В сложных случаях, когда требуется не просто изменить задачу и подпись, а создать собственную кнопку, используется метод

void custom(string $task = '', string $icon = '', string $iconOver = '', string $alt = '', bool $listSelect = true)

где:

$task - задача, которая будет выполнена;
$icon - пиктограмма кнопки;
$iconOver - пиктограмма при наведении курсора мыши;
$alt - подпись под кнопкой;
$listSelect - нужно ли работать только с выбранными элементами списка.

Как правило, в URL Joomla присутствует переменная task, определяющая задачу, которую должен выполнить компонент. В коде компонента в зависимости от полученного значения task вызывается некоторая функция. Например, если URL выглядит как http://localhost/joomla/index.php?option=mycomponent&task=show, то компонент mycomponent будет обрабатывать задачу show.

Параметры $icon и $iconOver задают, как ни странно, не название файла изображения, а название класса CSS, для которого задано это изображение в качестве фонового. К названию класса автоматически добавится строка "icon-32-" и будет произведен поиск этого класса в подключенных файлах CSS. Например, если третий параметр функции JToolBarHelper::custom() задан как send.png, то будет найден класс .icon-32-send, а в результате картинка будет отображена с помощью кода:

<span class="icon-32-send"></span>

 

Если данная панель инструментов создана для одной-единственной записи, а не для списка, то параметру $listSelect следует задавать значение false. Если этот параметр имеет значение true, то для события кнопки onclick задается следующий код на Javascript:

if (document.adminForm.boxchecked.value==0)
{
  alert('Пожалуйста, выберите объект из списка');
}
else
{ 
  Joomla.submitbutton('myquestions_sendToExpert')
}

 

Если же $listSelect имеет значение false, то проверка того, выбраны ли в списке какие-либо элементы, не осуществляется:

Joomla.submitbutton('myquestions_sendToExpert')

 

Для вывода названия панели инструментов и пиктограммы служит метод void title(string $title, string $icon), где:

$title - название панели инструментов;
$icon - название класса CSS, для которого необходимое изображение задано в качестве фонового. К названию класса автоматически добавится строка "icon-48-".

Например, если вы хотите использовать в качестве пиктограммы файл /media/com_mycomponent/images/sample-48.png, то добавьте в CSS класс

.icon-48-sample {
  background: url('../images/sample-48.png') 0 0 no-repeat;
}
  

 

Теперь для отображения названия необходимо добавить в код строку:

JToolBarHelper::title('Мой компонент','sample');

 

Для вывода между кнопками вертикальной черты-разделителя служит метод divider():

void divider();

 

Практика

Описание учебного примера

Для примера будем создавать компонент системы "вопрос - ответ". Назовем его myquestions. С помощью этого компонента посетители сайта смогут задавать свои вопросы, по желанию помечая их как предназначенные для публикации на сайте или как скрытые. Функциональность, доступная администратору системы:

  • отправить уведомление о вопросе эксперту по электронной почте;
  • задать дату снятия вопроса с публикации;
  • скрыть от посетителей сайта отдельные поля вопроса;
  • присвоить вопросу категорию;
  • редактировать список категорий;
  • ответить на вопрос;
  • отправить ответ автору вопроса по электронной почте;
  • удалить вопрос.

Уведомление о каждом присланном вопросе автоматически отправляется модератору по электронной почте. Модератор либо пересылает вопрос эксперту, либо удаляет (например, в случае спама), а также присваивает вопросу какую-либо категорию. Если посетитель пометил свой вопрос как скрытый, но по каким-то причинам его необходимо опубликовать (например, указан некорректный e-mail и отправить ответ невозможно), то модератор задает дату снятия вопроса с публикации. Таким образом, отображаться на сайте будут вопросы, удовлетворяющие следующим условиям:

  • есть ответ;
  • либо вопрос не помечен как скрытый, либо дата снятия вопроса с публикации указана и больше текущей даты

Для каждого вопроса будем хранить следующие данные:

  • id;
  • имя автора;
  • дата вопроса;
  • собственно текст вопроса;
  • город;
  • e-mail автора;
  • IP автора;
  • id категории;
  • отображать ли вопрос на сайте;
  • дата снятия вопроса с публикации;
  • отправлен ли вопрос эксперту;
  • ответ на вопрос;
  • отправлен ли ответ автору вопроса.

Регистрация компонента в базе данных

Зарегистрируем наш компонент в базе данных, добавив запись в таблицу, содержащую данные о расширениях. Перейдите в phpMyAdmin (если вы работаете с Denwer, то для этого вам нужно ввести в адресной строке браузера http://localhost/tools/phpmyadmin>), зайдите в базу данных, в которую вы установили Joomla, и откройте вкладку "SQL" (рис. 1.3).



01 03sm


увеличить изображение
Рис. 1.3.  Выполнение SQL-запросаТеперь введите следующий SQL-запрос. Предполагается, что префикс таблиц вашей базы данных - "jos_". Если вы указали при установке Joomla другой префикс, замените "jos_" на него.

INSERT INTO `jos_extensions`(`name`, `type`, `element`, 
  `folder`, `client_id`, `manifest_cache`, `params`, `custom_data`, 
    `system_data`) 
VALUES('myquestions', 'component', 'com_myquestions', '', 1, 
'{"legacy":false, "name":"Моя система 
&laquo;вопрос &ndash; ответ&raquo;", "type":"component", 
"creationDate":"2012", "author":"me", 
"copyright":"(с) me", "authorEmail":"mymail@example.ru", "authorUrl":"http:\\/\\/www.example.ru",
 "version":"1.0", 
"description":"Мой первый компонент для Joomla",
 "group":""}', '{}', '', '');

 

Как видите, мы задали название расширения - "myquestions", тип расширения - компонент и некоторую информацию о нем и его авторе.

Первые папки и файлы. Добавление пунктов меню

Создайте две папки под названием com_myquestions:

  • в папке /components;
  • в папке /administrator/components.

Создайте файл /components/com_myquestions/myquestions.php следующего содержания:

<?php
defined('_JEXEC') or die('Restricted access');
echo 'Моя система &laquo;вопрос &ndash; ответ&raquo;';
?>

 

Как видите, пока наш компонент просто будет выводить надпись "Моя система "вопрос - ответ"".

Не забудьте, что Joomla работает в кодировке UTF-8 и, следовательно, ваши PHP-файлы должны быть в той же кодировке. Например, в популярном текстовом редакторе Notepad++ кодировка изменяется с помощью пункта меню "Кодировка", из подпунктов которого нужно выбрать "Преобразовать в UTF-8 без BOM".

Теперь сохраните файл и обновите страницу http://localhost/joomla/index.php?option=com_myquestions в браузере. Страница примет следующий вид (рис. 1.4).



01 04sm


увеличить изображение
Рис. 1.4.  Первый результат во фронтендеСоздайте файл /administrator/components/com_myquestions/admin.myquestions.php:

<?php
defined('_JEXEC') or die('Restricted access');
echo 'Моя система &laquo;вопрос &ndash; ответ&raquo;';
?>

 

Наберите в адресной строке браузера строку http://localhost/joomla/administrator/index.php?option=com_myquestions. Результат должен выглядеть так, как на рис. 1.5.



01 05sm


увеличить изображение
Рис. 1.5.  Первый результат в бэкендеДобавим эти ссылки в меню фронтенда и бэкенда. Для этого выясним, какой id был присвоен нашему компоненту в таблице jos_extensions. В phpMyAdmin войдите в эту таблицу и найдите расширение com_myquestions. Вероятно, оно находится в последней строке. Посмотрите, какое значение стоит в поле extension_id. Например, на рис. 1.6 видно, что в данном случае id равен 10006.



01 06sm


увеличить изображение
Рис. 1.6.  Определение id компонентаТеперь выполните SQL-запрос, не забыв заменить "10006" на найденный вами id:

INSERT INTO `jos_menu`(`menutype`, `title`, `alias`, `path`, `link`, `type`, 
  `level`, `component_id`, `access`, `img`,  `params`, `client_id`) 
VALUES('menu', 'com_myquestions_menu', 'My Questions', 'My Questions', 'index.php?
option=com_myquestions', 'component',  1, 10006, 1, 'class:component', '', 1);

 

После выполнения данного запроса в меню "Компоненты" бэкенда появится новый подпункт со ссылкой на наш компонент. Однако он будет называться "myquestions", так как мы еще не задали перевод для строки com_myquestions_menu. Чтобы задать его, создайте языковой файл /administrator/language/ru-RU/ru-RU.com_myquestions.sys.ini следующего содержания:

COM_MYQUESTIONS_MENU="Моя система &laquo;вопрос &ndash; ответ&raquo;"

 

Зайдите в бэкенд. В меню "Компоненты" появился пункт "Моя система "вопрос - ответ"" (рис. 1.7).



01 07


Рис. 1.7.  Пункт меню в бэкендеТеперь создайте пункт меню фронтенда. Для этого зайдите в "Меню" - "Менеджер меню", нажмите на ссылку "Главное меню", а затем на кнопку "Создать". Выберите тип пункта меню "Внешний URL", в поле "Заголовок меню" введите "Моя система "вопрос - ответ"", а в поле "Ссылка" - ссылку на фронтенд нашего компонента: http://localhost/joomla/index.php?option=com_myquestions и нажмите "Сохранить". Обновите любую страницу фронтенда и убедитесь, что появился новый пункт меню (рис. 1.8).



01 08sm


увеличить изображение
Рис. 1.8.  Пункт меню во фронтенде

Создание панелей инструментов

Вспомните приведенное выше описание функционала, доступного администратору нашей системы. Соответственно, на панели инструментов для управления списком вопросов необходимы следующие кнопки:

  • отправить уведомление о вопросе эксперту по электронной почте;
  • присвоить вопросу категорию;
  • отправить ответ автору вопроса по электронной почте;
  • редактировать вопрос (в том числе: задать дату снятия вопроса с публикации; скрыть от посетителей сайта отдельные поля вопроса; ответить на вопрос);
  • удалить вопрос.

Для начала создайте файл /administrator/components/com_myquestions/toolbar.myquestions.html.php:

<?php
defined('_JEXEC') or die('Restricted access');
class TOOLBAR_myquestions
{
  function _REPLY()
  {
    JToolBarHelper::title(JText::_('COM_MYQUESTIONS_TOOLBAR_TITLE'), 'generic.png');
    JToolBarHelper::custom('sendToExpert', 'send.png', '', 'COM_MYQUESTIONS_TOOLBAR_SEND_TO_EXPERT', false);
    JToolBarHelper::custom('sendAnswer', 'send.png', '', 'COM_MYQUESTIONS_TOOLBAR_SEND_ANSWER', false);
    JToolBarHelper::save();
    JToolBarHelper::apply();
    JToolBarHelper::cancel();
  }
  function _DEFAULT()
  {
    JToolBarHelper::title(JText::_('COM_MYQUESTIONS_TOOLBAR_TITLE'), 'generic.png');
    JToolBarHelper::editList('reply','COM_MYQUESTIONS_REPLY');
JToolBarHelper::deleteList(JText::_('COM_MYQUESTIONS_TOOLBAR_REMOVE_QUESTIONS_CONFIRMATION'));
  }
}
?>

 

Каждая функция класса TOOLBAR_myquestions соответствует отдельной панели инструментов. Как видите, мы задали две такие панели - первая из них будет отображаться над формой для ответа на вопрос, а вторая - над списком вопросов.

В коде, приведенном выше для ряда кнопок вместо стандартных подписей задаются собственные, которые необходимо перевести в языковом файле вместе с другими надписями. Поэтому создадим языковой файл /administrator/language/ru-RU/ru-RU.com_myquestions.ini:

COM_MYQUESTIONS_TOOLBAR_SEND_TO_EXPERT="Отправить эксперту"
COM_MYQUESTIONS_TOOLBAR_SEND_ANSWER="Отправить ответ"
COM_MYQUESTIONS_TOOLBAR_TITLE="Моя система &laquo;вопрос &ndash; ответ&raquo;"
COM_MYQUESTIONS_REPLY="Ответить / Редактировать"
COM_MYQUESTIONS_TOOLBAR_REMOVE_QUESTIONS_CONFIRMATION="Вы действительно хотите удалить эти вопросы?"

 

Добавим код, который будет выбирать, какую из определенных нами панелей инструментов отображать. Создайте файл /administrator/components/com_myquestions/toolbar.myquestions.php:

<?php
defined('_JEXEC') or die('Restricted access');
require_once(JApplicationHelper::getPath('toolbar_html'));
switch($task)
{
  case 'reply':
    TOOLBAR_myquestions::_REPLY();
    break;
  default:
    TOOLBAR_myquestions::_DEFAULT();
    break;
}
?>

 

Вызов функции getPath() класса JApplicationHelper позволяет обратиться к файлу toolbar.myquestions.html.php без указания имени компонента, что удобно, если впоследствии понадобится изменить это имя.

Выражение switch используется для выбора одной из панелей инструментов в зависимости от значений переменной $task.

Обратите внимание, что код распределен по двум файлам - toolbar.myquestions.php и toolbar.myquestions.html.php, чтобы отделить логику обработки от непосредственного вывода информации.

Обновите страницу в бэкенде и выберите в меню "Компоненты" пункт "Моя система "вопрос - ответ"". Результат должен быть таким же, как на рис. 1.9.



01 09sm


увеличить изображение
Рис. 1.9.  Первая панель инструментовЧтобы увидеть другую панель инструментов, добавьте строку &task=reply в конец URL: http://localhost/joomla/administrator/index.php?option=com_myquestions&task=reply (рис. 1.10).



01 10sm


увеличить изображение
Рис. 1.10.  Вторая панель инструментовКаждая кнопка панели инструментов соответствует некоторой задаче. Когда пользователь нажимает на какую-либо кнопку, соответствующая задача добавляется к форме, и эта форма автоматически отправляется. Поскольку самих форм мы еще не создали, кнопки не работают.

Чтобы использовать для кнопки свою картинку, необходимо создать файл CSS, содержащий подобное выражение:

.icon-32-myiconname
{    background-image: url(icon-32-myiconfile.png); 
}

 

Класс JToolBarHelper будет искать для заданного значения iconname класс .icon-32- iconname. Название файла должно начинаться с "icon-32-".

В таком случае вызов функции JToolBarHelper::custom() будет выглядеть так:

JToolBarHelper::custom('someFunction', 'myiconname.png', '', 'Альтернативный текст', false, false);

 

Ваш файл CSS необходимо подключить в файле admin.myquestions.php следующим образом:

JHTML::stylesheet('delete.css', 'administrator/components/com_myquestions/');

 

Предполагается, что файлы delete.css и icon-32-myiconfile.png находятся в папке /administrator/components/com_myquestions/.

Ключевые термины

JAdministrator - приложение, управляющее функциями для администрирования Joomla.
JApplication - класс, позволяющий работать с очередью сообщений, осуществлять перенаправление браузера, получать параметры конфигурации сайта, определять тип запущенного приложения Joomla.
JFactory - класс Joomla, реализующий паттерн "фабрика" и позволяющий получить доступ к глобальным объектам фреймворка.
JInstallation - приложение, которое запускается при установке Joomla.
JRequest - класс Joomla, использующийся для работы с переменными HTTP-запроса.
JSite - приложение, отвечающее за компоновку и отображение фронтенда.
JToolBarHelper - класс Joomla, содержащий методы, которые генерируют HTML-код для построения кнопок панелей инструментов.
XML-RPC - приложение, позволяющее администрировать сайт Joomla удаленно.
Библиотека - файл, который требуется для работы фреймворка или сторонних расширений.
Бэкенд - система администрирования сайта.
Ключ - эквивалент текста, подлежащего переводу.
Компонент - основной тип расширений Joomla, вызов которого происходит при каждом обращении к Joomla.
Модуль - расширение Joomla, использующееся для отображения небольших фрагментов контента, обычно в левой или правой колонке или верхней или нижней областях страницы.
Очередь сообщений - массив строк, которые будут выведены на экран при следующей загрузке какой-либо страницы.
Перевод - строка, содержащая перевод текста, соответствующего заданному ключу, на какой-либо язык.
Плагин - расширение Joomla, позволяющее зарегистрировать функции и классы для обработки каких-либо событий, вызванных Joomla, например, поиск по сайту.
Приложение - глобальный объект, использующийся для обработки запросов.
Уровень приложения - часть архитектуры Joomla, которая состоит из приложений, расширяющих абстрактный класс JApplication.
Уровень расширений - часть архитектуры Joomla, которая состоит из расширений фреймворка Joomla и приложений.
Уровень фреймворка - часть архитектуры Joomla, которая обеспечивает ее базовую функциональность с помощью набора библиотек и плагинов и собственно ядра Joomla.
Фреймворк Joomla ("ядро") - набор классов, обеспечивающих базовую функциональность Joomla (JDatabase, JUser, JForm, JEditor и т.д.).
Фронтенд - часть сайта, доступная пользователю.
Шаблон - расширение Joomla, отвечающее за внешний вид сайта.
Языковый файл - расширение Joomla, позволяющее представить ее контент на нескольких языках.

Краткие итоги

Фреймворк Joomla состоит из трех уровней: уровень фреймворка, уровень приложения и уровень расширений.

Уровень фреймворка обеспечивает базовую функциональность Joomla с помощью набора библиотек и плагинов и собственно фреймворка Joomla.

Уровень приложения состоит из приложений, которые расширяют абстрактный класс JApplication.

Уровень расширений состоит из таких расширений фреймворка Joomla и приложений, как компоненты, модули, плагины и т.д.

Joomla делится на фронтенд - часть сайта, доступная пользователю, и бэкенд - систему администрирования сайта. Большинство компонентов для Joomla также делятся на фронтенд и бэкенд, и их код соответственно распределяется по двум папкам.

В Joomla определен ряд констант, хранящих значения путей, а также константа _JEXEC, позволяющая проверить, был ли скрипт вызван из Joomla, и DS - разделитель директорий.

Для создания мультиязыкового сайта используются языковые файлы, хранящие пары "ключ-значение", где ключ - это эквивалент какого-то текста, а значение - перевод этого текста на какой-либо язык.

Статический класс JFactory реализует паттерн "фабрика" и позволяет получить доступ к глобальным объектам фреймворка.

Вместо непосредственного использования глобальных массивов $_GET, $_POST, $_REQUEST и др. удобнее применять класс JRequest. Его методы пропускают данные, введенные пользователем, через фильтр во избежание инъекций.

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

Глобальный объект JApplication позволяет работать с очередью сообщений, осуществлять перенаправление браузера, получать параметры конфигурации сайта, определять тип запущенного приложения Joomla.

Панели инструментов в бэкенде можно создавать с помощью класса JToolBarHelper, методы которого генерируют HTML-код для построения кнопок. Для отображения кнопок, которые часто используются в компонентах, существуют готовые методы этого класса. Можно также создать собственную кнопку.

Вопросы

  1. Опишите структуру фреймворка Joomla.
  2. Что такое фронтенд и бэкенд?
  3. Какие константы предопределены в Joomla?
  4. Каким образом реализована поддержка мультиязыковых сайтов?
  5. Для чего используется класс JFactory?
  6. В чем преимущество использования методов класса JRequest?
  7. Что такое очередь сообщений?
  8. Для чего используется глобальный объект JApplication?
  9. Каким образом создаются панели инструментов в бэкенде?