Все о Joomla 1.5

...заметки Котофеича

 
  • Increase font size
  • Default font size
  • Decrease font size
Home Статьи статьи Полное руководство по созданию плагинов в Joomla 1.5 (часть 1)

Полное руководство по созданию плагинов в Joomla 1.5 (часть 1)

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

Введение

Когда мы начинаем создавать новый плагин, мы разбиваем создание на несколько частей. Так нам будет проще вникать в суть и удобнее тестировать плагин. В идеале, мы должны иметь более одного сервера, чтобы тестировать плагин (в частности его установку).
Сначала мы создадим простейщий установщик. XML установщика опишит плагин, названный Foobar - My Extension.
 
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE install SYSTEM "http://dev.joomla.org/xml/1.5/plugin-install.dtd">
<install version="1.5" type="plugin" group="foobar">
<name>Foobar - My Extension</name>
<author>Имя автора</author>
<authorEmail>Email автора</authorEmail>
<authorUrl>Сайт автора</authorUrl>
<creationDate>Дата создания</creationDate>
<copyright>Копирайты</copyright>
<license>Лицензия</license>
<version>Версия плагина</version>
<description>Описание плагина</description>
<files>
<filename plugin="myextension">myextension.php</filename>
</files>
<params/>
</install>
 
Очень важно заметить параметр группы плагина. Вообще все плагины разделяются на логические группы. Вот список групп ядра Joomla:
- authentication
- content
- editors
- editors-xtd
- search
- system
- user
- xmlrpc
Также как вы заметили, мы можем указать свою группу.
Также в XMl-файле указывается очень важной информацией является параметр plugin. Этот параметр является уникальным в группе и идентифицирует наш плагин. Далее в таблице видны имена плагинов, которые уже заняты под ядро системы.
ГруппаЗарезервированные имена
authenticationgmail
joomla
ldap
openid
contentemailcloak
geshi
loadmodule
pagebreak
pagenavigation
sef
vote
editorsnone
tinymce
xstandard
editors-xtdimage
pagebreak
readmore
searchcategories
contacts
content
newsfeeds
sections
weblinks
systemcache
debug
legacy
log
remember
userjoomla
xmlrpcblogger
joomla

После того как вы создали XML файл myextension.xml, создайте файл myextension.php и положите их в каталог foobar. После чего заархивируйте в gz, .tar, .tar.gz, или zip (лучше все-так в zip).
Заметьте, что файлы одного плагина не делятся на каталоги, потому что плагины состоят всего из двух файлов. После этого вы можете установить плагин. Но пока он не выполняет никаких действий.

События

Итак у нас должно быть создано событие, которое в дальнейшем будет обрабатываться плагином.
Приложения Joomla используют глобальный объект, названный диспетчер событий (event dispatcher), для отправки событий зарегестрированным слушателям (listeners). Глобальный диспетчер событий - это объект JEventDispatcher, который является расширением абстрактного класса JObservable.
В Joomla, слушателем может быть класс или функция. Когда мы используем класс слушателя, то этот класс должен быть расширением класса JPlugin. Именно расширением, для того чтобы наследовать основные методы класса.
Итак, представьте что у нас есть компонент Foobar, отображающий некоторые записи из БД. Мы можем использовать событие onPrepareFoobar, которое происходит перед выводом записей.
Чтобы добавить событие, мы записываем его с помощью метода triggerEvent() в диспетчер событий, который уже передает его слушателям.
Метод triggerEvent() содержит два параметра: название события и массив аргументов переданных слушателям. Допустим мы добавляем событие onPrepareFoobar:
$dispatcher     =&amp; JDispatcher::getInstance();
JPluginHelper::importPlugin('Foobar');
$arguments = array(&amp;$foobarData);
$result = $dispatcher->trigger('onPrepareFoobar', $arguments);
Заметьте, что мы передаем $foobarData в виде ссылки, а второй параметр функции обязательно должен быть массивом. Теперь мы можем написать плагины, которые будут обрабатывать $foobarData.

Слушатель

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

Регестрирование слушателей

Когда мы создаем новый плагин, если мы используем функции, мы должны информировать приложение о каждой функции и событии. Для этого нужно использовать метод приложений registerEvent(). Метод содержит два параметра: имя события и имя обработчика.
Технически имя обработчика может быть именем класса.
Например, в ядре Joomla компонент поиска использует плагины для поиска результата. Этот плагин ищет в статьях с помощью функции plgSearchContent() которая обрабатывает событие onSearch:
$mainframe->registerEvent('onSearch', 'plgSearchContent');

Обработка событий

Как уже говорилось ранее, мы можем использовать как функции, так и классы для обработки событий. Начнем мы наше изучение обработки событий с использования функций.
Мы уже сделали заготовку плагина, названного My Plugin в группе Foobar и мы хотим обработать событие названное onPrepareFoobar.
Перед тем как мы начнем создавать нашу функцию, мы должны дать ей название. Важно использовать следующее правило именований: слово plg, группа плагина, имя плагина, событие. Например, наша функция будет называться plgFoobarMyPluginPrepareFoobar.
Например эту функцию мы можем использовать для обработки события:
$mainframe->registerEvent('onPrepareFoobar','plgFoobarMyPluginPrepareFoobar');
/**
* Переводит переданный параметр в верхний регистр.
*
* @param Foobar Reference to a Foobar object
*/
function plgFoobarMyPluginPrepareFoobar(&amp;$foobar) 
{
$foobar->name = strtoupper($foobar->name);
}
Самая важная часть в этой функции - это переданный параметр. Ранее мы передали параметр в виде массива. Каждый элемент массива обрабатывается плагином отдельно.
Плагин состоящий из функции, так же может обрабатывать множественные события.
Если мы хотим создать слушателя используя класс, для этого мы должны расширить класс JPlugin. Сначала мы должны разобраться как именовать класс слушателя. JPlugin требует специальное именование: слово plg, имя группы плагина, имя плагина.
Например, плагин с именем myplugin в группе foobar должен называться plgFoobarMyplugin.
Этот пример обрабатывает два события: onPrepareFoobar и onAfterDisplayFoobar.
// Импортируем класс JPlugin
jimport('joomla.event.plugin');
/**
* My Plugin event listener
*/
class plgFoobarMyplugin extends JPlugin
{
/**
* Обрабатываем событие onPrepareFoobar
*
* @param object Foobar to prepare
*/
function onPrepareFoobar(&$foobar)
{
$foobar->name = JString::strtoupper($foobar->name);
}
/**
* Обрабатываем событие onAfterDisplayFoobar
*
* @param object Foobar which is being displayed
* @return string XHTML to display after the Foobar
*/
function onAfterDisplayFoobar(&$foobar)
{
return '<p>'.JText::_('Foobar Name converted to upper case by
My Plugin').'<p>';
}
}
В этом примере, как видите, вам не приходится самим регестрировать события. За вас все сделает фрэймворк Joomla. Главное правильно назвать класс и события.
Когда мы импортируем плагин в Joomla, глобальный диспетчер событий автоматически смотрит классы слушателей и регестрирует их.
Метод onAfterDisplayFoobar() вернет значение. Вы должны помнить, что ранее мы передали на обработку плагину массив.
В этом примере видно как получить обратно уже обработанный массив.
$dispatcher     =& JDispatcher::getInstance();
JPluginHelper::importPlugin('Foobar');
$arguments = array(&$foobarData);
$result = $dispatcher->trigger('onPrepareFoobar', $arguments);
$foobar->onAfterDisplayFoobar = trim(implode("\n", $result));
Это очень простой пример. Далее мы рассмотрим более сложные вещи.

Группы плагинов

Плагины делятся на различные группы. Каждая группа плагинов обрабатывает определенный набор событий. В ядре Joomla содержится 8 групп: authentication
content
editors
editors-xtd
search
system
user
xmlrpc

Далее мы рассмотрим каждую группу подробнее.

Authentication

Joomla поддерживает 4 различных методов авторизации: GMail
Joomla!
LDAP
OpenID

Также можно создать свои методы авторизации пользователя.
В этой группе существует только один метод onAuthenticate.
В плагине мы можем установить значение следующих свойств:
СвойствоОписание
birthdateДата рождения пользователя
countryСтрана пользователя
emailE-mail адрес пользователя
error_messageСообщение об ошибке или отмена авторизации
fullnameФИО
genderПол
languageЯзык
postcodeПочтовый индекс
statusСтатус авторизации
timezoneЧасовой пояс
usernameЛогин

Свойство status используется для определения результата авторизации. Таблица содержит три константы, которые может содержать свойство status:

КонстантаОписание
JAUTHENTICATE_STATUS_CANCELАвторизация отменена
JAUTHENTICATE_STATUS_FAILUREОшибка авторизации
JAUTHENTICATE_STATUS_SUCCESSАвторизация прошла успешно

По-умолчанию в Joomla опубликован только один плагин авторизации - Joomla!. Также вы можете опубликовать LDAP, GMAIL и OpenId.


onAuthenticate
ОписаниеПроисходит, когда пользователь авторизируется на сайте
ПараметрыusernameЛогин
passwordПароль
responseСсылка на объект JAuthenticationResponse

Content

Плагины группы content, позволяют обрабатывать элементы контента, прежде чем вывести его на экран. Наиболее часто используемое событие - это onPrepareContent. Это событие запускается самым первым.
Поставим такую задачу- заменить все символы ":)" на картинку улыбающегося смайлика. Вот решение этой задачи:
 
defined('_JEXEC') or die('Restricted access');
// регестрируем обработчик
$mainframe->registerEvent('onPrepareContent',
'plgContentSmiley');
/**
* Заменим :) на смайлик.
*
* @param object Content item
* @param JParameter Content parameters
* @param int Page number
*/
function plgContentSmiley(&amp;$row, &amp;$params, $page)
{
$pattern = '/\:\)/';
$icon = '<img src="plugins/content/smiley.gif" />';
$row->text = preg_replace($pattern, $icon, $row->text);
}
 
Заметьте, что итоговые значения не нужно возвращаться, и параметр $row передается по ссылке.
Рассмотрим подробнее атрибуты контента:
АтрибутОписание
createdдата создания в формате 0000-00-00 00:00:00.
modifiedДата последнего изменения в формате 0000-00-00 00:00:00
textосновной контент элемента
titleзаголовок элемента контента
tocтаблица контента

Теперь рассмотрим происходящие события.

onAfterDisplayContent
ОписаниеСоздается xhtml строка после обработки контента
ПараметрыrowСсылка на объект контента
paramsссылка на объект JParameter контента
pageНомер страницы
ВозвращаетXHTML после отображения самого контента


onAfterDisplayTitle
ОписаниеСоздается xhtml строка после отображения заголовка страницы
ПараметрыrowСсылка на объект контента
paramsссылка на объект JParameter контента
pageНомер страницы
ВозвращаетXHTML после отображения заголовка страницы


onBeforeDisplayContent
ОписаниеСоздается xhtml строка перед отображением элемента text. Например плагин - рейтинг записи
ПараметрыrowСсылка на объект контента
paramsссылка на объект JParameter контента
pageНомер страницы
ВозвращаетXHTML перед выводом эелемента text


onPrepareContent
Описание Обрабатывает один элемент контента. Если вы собираетесь внести изменения в текст элемента, то вы должны использовать это событие.
ПараметрыrowСсылка на объект контента
paramsссылка на объект JParameter контента
pageНомер страницы
ВозвращаетИстина, если успешно


onPrepareContent
Описание Обрабатывает один элемент контента. Если вы собираетесь внести изменения в текст элемента, то вы должны использовать это событие.
ПараметрыrowСсылка на объект контента
paramsссылка на объект JParameter контента
pageНомер страницы
ВозвращаетИстина, если успешно

Editors

Пожалуй, самой сложный из всех основных плагинов - это редактор. Одним из основных редакторов является TinyMCE (http://tinymce.moxiecode.com/). TinyMCE это JavaScript редактор, который позволяет пользователю легко изменять данные в текстовом поле без знаний XHTML.
Очень важно здесь отметить что кнопки под редактором создаются отдельными плагинами editors-xtd группы, о которых расскажу чуть позже.
Приведу список самых популярных редактором за бугром:
- ASBRU Web Content Editor
- FCKeditor
- wysiwygPro
- XStandard
- Yahoo Rich Text Editor
Импортирование нового редактора задача не из легких. Зато если редактор уже встроен, то его очень просто подключать.
Yahoo Rich Text Editor подает большие надежды. Это очень навороченный редактор, созданный на основе YUI (Yahoo User Interface). Про интерфейс Yahoo скоро начну вести отдельную серию статей.
События плагинов:


onDisplay
Описание Получить XHTML поле элемента формы
ПараметрыnameУникальное название редактора
contentИнициируемые контент
widthШирина редактора в пикселях
heightВысота редактора в пикселях
colШирина редактора в символах
rowВысота редактора в строках
buttonsБулево значение, служит чтобы скрыть или показать дополнительные кнопки; смотрите событие onCustomEditorButton из раздела editors-xtd этой статьи.
ВозвращаетXHTML форма редактора


onGetContent
Описание Некоторый Javascript код, который возвращает контент
ПараметрыeditorУникальное имя редактора
ВозвращаетЗапускает Javascript на стороне клиента, который вернет контент редактора. Код должен заканчиваться точкой с запятой.


onGetInsertMethod
Описание Запускаем javascript код, который определен функцией jInsertEditorText()
ПараметрыnameУникальное имя редактора
ВозвращаетВставляем в редактор заданный текст в позицию курсора


onInit
Описание Инициализация запускается один раз независимо от колличества выхванных редакторов.
ВозвращаетНеобходимые функции по запуску редактора


onSave
Описание Запускаем javascript код, который необходим для сохранения редактора
ПараметрыnameУникальное имя редактора
ВозвращаетJavascript строку, которая запускается перед сохранением контента.


onSetContent
Описание Запускаем javascript код, который установит заданный контент в редакторе
ПараметрыnameУникальное имя редактора
HTMLНовый контент редактора
ВозвращаетНовый контент в редакторе

Editors-xtd

Эта группа плагинов используется для расширения функциональности редакторов, путем добавления к ним кнопок. К сожалению встроенный редактор xStandart не поддерживает эту группу плагинов. Существует только одно событие, связанные с этой группой, onCustomEditorButton.
Поскольку существует только одно событие, связанное с этой группой, мы, будем использовать функции вместо работы с подклассами JPlugin. Этот пример показывает, каким образом мы можем добавить кнопку смайлика ":)" в редактор.

// no direct access
defined('_JEXEC') or die('Restricted access');
$mainframe->registerEvent('onCustomEditorButton',
'plgSmileyButton');
/**
* Кнопка смайликов
*
* @name string Name of the editor
* @return array Array of three elements: JavaScript action,
Button name, CSS class.
*/
function plgSmileyButton($name)
{
global $mainframe;
// get the image base URI
$doc =& JFactory::getDocument();
$url = $mainframe->isAdmin() ? $mainframe->getSiteURL() : JURI::base();
// get the JavaScript
$js = "
function insertSmiley()
{
jInsertEditorText(' :) ');
}
";
$css = " .button1-left .smiley { background:
url($url/plugins/editors-xtd/smiley1.gif)
100% 0 no-repeat; }";
$css .= "\n .button2-left .smiley { background:
url($url/plugins/editors-xtd/smiley2.gif)
100% 0 no-repeat; }";
$doc->addStyleDeclaration($css);
$doc->addScriptDeclaration($js);
$button = array("insertSmiley()", JText::_('Smiley'),
'smiley');
return $button;
}
В этом коде мы делаем два важных действия: мы определяем обработчик функции, и регистрируем ее в глобальном диспетчере событий.
Переходя к функции plgSmileyButton() обратим внимание, что у нее есть параметр $name, который указывает на имя редактора. Он нужен для определения с каким редактором мы работает, так как их может быть несколько на одной странице. В самой функции мы этот параметр никак не используем.

Мы создаем JavaScript и CSS код. Клиент будет выполнять JavaScript при нажатии кнопки. Также мы определяем два стиля CSS, чтобы сделать кнопку в разных местах (в админке и во фронте).

В массиве $button мы возвращаем три элемента. Первый элемент - это JavaScript, который будет выполнен при нажатии кнопки. Вторым элементом является название кнопки. Третьим элементом является название класса CSS для кнопки.

Также в плагине мы используем картинки, которые должны быть добавлены в xml файле:
<files>
<filename plugin="smiley">smiley.php</filename>
<filename>smiley1.gif</filename>
<filename>smiley2.gif</filename>
</files>
Перед тем как мы задействуем нашу кнопку в редакторе, обратим внимание на особо полезные методы редактора:

Метод Описание
getContentJavaScript возвращает текст в редакторе
saveJavaScript сохраняет содержимое редактора (используется не во всех редакторах)
setContentJavaScript устанавливает определенный контент


Все эти методы возвращают JavaScript строку. Мы можем использовать эти строки для создания скриптов, которые взаимодействуют с редактором.
Покажу на примере, как пользоваться этими методами:
// получаем редактор
$editor =& JFactory::getEditor();
// вызываем javascript, который вызвращает контент
$getContent = $editor->getContent($name);
// строим javascript, который в окне отображает контент
$js = 'var content = '.$getContent."\n"
.'alert(content);';

onCustomEditorButton
Описание Добавляет кнопку в редактор
ПараметрыnameУникальное имя редактора
ВозвращаетМассив из трех элементов: javascript, имя кнопки и css стиль

Search

Плагины группы search использюется для расширения основного компонента поиска и получения результатов поиска. Есть два события, связанные с этой группой, onSearch и onSearchAreas. Цель onSearchAreas трудновато понять.

Приведу скриншот поиска:

В рамках поиска, пользователь может выбрать, где он хочет искать. В данном случае можно выбрать "Статьи", "Ссылки", "Контакты", "Категории", "Разделы", и "Ленты'. Когда мы инициируем onSearchAreas, мы выбираем в каком компоненте будет произведен поиск.
Важно: Один плагин может искать в нескольких компонентах.
Событие onSearch более косвенно, и срабатывает только когда происходит поиск. В итоге должен вернуться массив результатов. Реалзиция поиска будет зависеть от того, что вы ищете.


onSearch
Описание Выполняет поиск и возвращает результаты
ПараметрыtextИскомая строка
phraseТип поиска 'any', 'all', или 'exact'.
orderingВиды сортировки: 'newest', 'oldest', 'popular', 'alpha' (alphabetical), or 'category'.
areasРаздел в котором ищем (основано на onSearchArea).
ВозвращаетАссоциативный массив со следующими полями: 'title', 'text', 'created', 'href', 'browsernav' (1 = открывать в новом окне), и 'section' (необязательное).


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


System Есть четыре важных системных события. Вот их порядок:
- onAfterInitialize
- onAfterRoute
- onAfterDispatch
- onAfterRender


onAfterDispatch
ОписаниеПроисходит после того, как была отправлена заявка


onAfterRoute
ОписаниеПроисходит после того как приложение инициализировано


onAfterDispatch
ОписаниеПроисходит когда приложение отрендерено, но еще не отправлено пользователю


onAfterRender
ОписаниеПроисходит после применения роутера

User

Плагины группы user позволяют выполнить дополнительную обработку в конкретных событиях связанных с пользователем. Это особенно полезно, когда эти плагины используются в сочетании с компонентом, который связан с таблицей # __users.

Рассмотрим на примере событие onAfterUserStore. Это событие срабатывает после того, пользователь соханяет свои данные (срабатывает для новых и уже существующих пользователей).

Этот пример показывает, как мы можем поддерживать другую таблицу, # __some_table, когда создан новый пользователь:

$mainframe->registerEvent('onAfterStoreUser',
'plgUserMaintainSomeTableStoreUser');
/**
* Add new rcord to #__some_table when a new user is created
*
* @param array User attributes
* @param boolean True if the user is new
* @param boolean True if the user was successfully stored
* @param string Error message
* @return array Array of three elements: JavaScript action, Button
name, CSS class.
*/
function plgUserMaintainSomeTableStoreUser($user, $isnew, $success,
$msg)
{
// if they are a new user and the store was successful
if ($isnew && $success)
{
// add a record to #__some_table
$db = JFactory::getDBO();
$query = 'INSERT INTO '.$db->nameQuote('#__some_table')
.' SET '.$db->nameQuote('userid').' = '.$user['id'];
$db->setQuery($query);
$db->query();
}
}
onBeforeStoreUser
Описание Позволяет модифицировать данные пользователя перед сохранением
ПараметрыuserАссоциативный массив с данными пользователя
isnewИстина если пользователь новый


onAfterStoreUser
Описание Позволяет выполнять код, после того как данныен пользователя были сохранены
ПараметрыuserАссоциативный массив с данными пользователя
isnewИстина если пользователь новый
successИстина в случае успешного сохранения
msgСообщение об ошибке если она имеется


onBeforeDeleteUser
Описание Позволяет нам выполнять дополнительную обработку до того, как пользователь будет удален. Это полезно для обновления неосновных таблиц, которые имеют отношение к ключевым таблицам #__users
ПараметрыuserАссоциативный массив с данными пользователя


onAfterDeleteUser
Описание Позволяет выполнять код, после того как пользователь удален
ПараметрыuserАссоциативный массив с данными пользователя
successИстина в случае успешного удаления
msgСообщение об ошибке если она имеется


onLoginFailure
Описание Если логин или пароль введен неверно
ПараметрыresponseJAuthenticationResponse обьект


onLoginUser
Описание Происходит при успешной авторизации пользователя
ПараметрыuserJAuthenticationResponse обьект
rememberИстина если пользователь хочет быть "запомненным"
ВозвращаетБулево знчение ложь, если неуспешно


onLogoutUser
Описание Пользователь пытается выйти. В это время плагин "joomla" удаляет сессии.
ПараметрыuserJAuthenticationResponse обьект
ВозвращаетБулево знчение ложь, если неуспешно

XML-RPC

XML-RPC - стандарт/протокол вызова удалённых процедур, основанный на XML, является прародителем SOAP, отличается исключительной простотой применения. XML-RPC, как и любой другой интерфейс RPC, определяет набор стандартных типов данных и команд, которые программист может использовать для доступа к функциональности другой программы, находящейся на другом компьютере в сети. Joomla! включает в себя XML-RPC сервер, который, как мы можем расширить с помощью плагинов.

Плагины XML-RPC состоят из двух частей: обработчик события onGetWebServices, который возвращает массив поддерживающий веб-сервис вызовов, и статический класс или набор функций, которые управляют удаленным вызовом процедур. Если руки дойдут, расскажу об использовании XML-RPC в Joomla в отдельной статье.
onGetWebServices
Описание Получить ассоциативный массив с описанием доступных методов веб-службы.
ВозвращаетАссоциативный массив в ассоциативном массиве, который определяет доступен ли сервис вызова.

Продолжение следует..