Часть 02 - добавление MVC и логирования
Во фреймворке Joomla 2.5 разработчики компонентов разделяют свой код на три основные части:
- модели - управляют данными;
- контроллеры - исполняют задачи, устанавливают и получают состояния моделей, а также указывают, какие представления необходимо отобразить;
- представления - отображают содержимое исходя из типа (error, feed, html, json, raw, xml) и шаблона (которые выбраны контроллером), а также получают данные из моделей.
Создаем точку входа
Первый файл, к которому обращается Jooma для запуска компонента - это его точка входа. Этот файл практически одинаков для всех компонентов. Меняем содержимое файла site/helloworld.php на следующие строки:
<?php // Запрет прямого доступа. defined('_JEXEC') or die; // Подключаем библиотеку контроллера Joomla. jimport('joomla.application.component.controller'); // Получаем экземпляр контроллера с префиксом HelloWorld. $controller = JControllerLegacy::getInstance('HelloWorld'); // Исполняем задачу task из Запроса. $input = JFactory::getApplication()->input; $controller->execute($input->getCmd('task', 'display')); // Перенаправляем, если перенаправление установлено в контроллере. $controller->redirect();
В ядре кода Joomla за управление контроллерами отвечает класс JController. Но для поддержки новой MVC структуры в Joomla 3 этот класс был переименован в JControllerLegacy
.
Итак, статический метод getInstance() класса JControllerLegacy
создает контроллер. В приведенном выше коде он создает объект контроллера, который принадлежит классу HelloWorldController
. Joomla будет искать объявление этого класса в файле, который называется controller.php (это поведение по умолчанию). Далее контроллер исполняет задачу, которая передается ему из переменных Запроса. В свою очередь запрос является публичным свойством, которое доступно нам из Приложения.
Добавляем контроллер
Настало время создать файл controller.php, объявить и определить в нем класс HelloWorldController
. Создайте файл site/controller.php содержащий следующий код:
<?php // Запрет прямого доступа. defined('_JEXEC') or die; // Подключаем библиотеку контроллера Joomla. jimport('joomla.application.component.controller'); /** * Контроллер сообщения компонента Hello World. */ class HelloWorldController extends JControllerLegacy { }
Уверен, что у вас сразу возник вопрос - почему контроллер не содержит код? На самом деле все довольно просто. Когда в переменных запроса задача не установлена, то исполняется задача по умолчанию. По умолчанию мы установили задачу display
, которая есть у родительского класса JControllerLegacy
. Поэтому на данный момент наш класс HelloWorldController
не содержит никакого кода и попытается отобразить представление с именем HelloWorld
.
Добавляем представление
Когда JControllerLegacy
хочет отобразить представление, он ищет определенные файлы в папке component/com_[имя_компонента]/views/[имя_представления]/.
Имя папки представления по умолчанию - это имя самого компонента. В нашем случае, путем к файлам будет component/com_helloworld/views/helloworld/.
Файл, который будет содержать код представления называется как view.[тип_представления].php. Тип представления по умолчанию (и наиболее часто используемый) - html тип. Все вместе это дает нам имя файла - view.html.php.
Создайте файл site/views/helloworld/view.html.php, который будет отображать представление:
<?php
// Запрет прямого доступа.
defined('_JEXEC') or die('Restricted access');
// Подключаем библиотеку представления Joomla.
jimport('joomla.application.component.view');
/**
* HTML представление сообщения компонента HelloWorld.
*/
class HelloWorldViewHelloWorld extends JViewLegacy
{
/**
* Сообщение.
*
* @var string
*/
protected $item;
/**
* Переопределяем метод display класса JViewLegacy.
*
* @param string $tpl Имя файла шаблона.
*
* @return void
*/
public function display($tpl = null)
{
// Получаем сообщение.
$this->item = 'Hello World';
// Отображаем представление.
parent::display($tpl);
}
}
Обратите внимание, что к классу JView тоже был добавлен суффикс Legacy (как и контроллеру). Это также сделано для поддержки новой MVC структуры в Joomla 3. Метод display
класса JViewLegacy
вызывается вместе с задачей display класса
JControllerLegacy
. В нашем случае, этот метод отобразит данные используя файл шаблона tmpl/default.php. Создайте файл site/views/helloworld/tmpl/default.php, который будет отображать представление по умолчанию:
<?php
// Запрет прямого доступа.
defined('_JEXEC') or die;
?>
<h2><?php echo $this->item; ?></h2>
Этот файл шаблона будет включен в класс JViewLegacy
. Поэтому $this
здесь относится к классу
HelloWorldViewHelloWorld
.
В результате наш компонент будет выводить сообщение, которое содержится в переменной $this->item
в файле view.html.php:
Hello World!
Добавляем модель
Маловероятно, что на практике вы будете использовать такое простое представление. Как правило, представление тесно связано с моделью, которая ответственна за управление данными. Обычно первая функция, которая пишется в модели - это get-функция. Её задача вернуть данные вызывающему (caller). В нашем случае, вызывающим является представление HelloWorldViewHelloWorld
. По умолчанию модель с именем HelloWorldModelHelloWorld
является главной моделью, которая ассоциируется с нашим представлением. Создайте файл site/models/helloworld.php со следующим кодом:
<?php // Запрет прямого доступа. defined('_JEXEC') or die; // Подключаем библиотеку modelitem Joomla. jimport('joomla.application.component.modelitem'); /** * Модель сообщения компонента HelloWorld. */ class HelloWorldModelHelloWorld extends JModelItem { /** * Получаем сообщение. * * @return string Сообщение, которое отображается пользователю. */ public function getItem() { if (!isset($this->_item)) { $this->_item = 'Hello World!'; } return $this->_item; } }
Класс JModelItem (который мы расширяем) является дочерним для класса JModel и используется для работы с одной определенной сущностью. В нашем случае сущностью является сообщение (приветствие). В родительском классе уже определено свойство $_item
, которое мы используем для хранения сообщения.
Теперь перенастроим класс HelloWorldViewHelloWorld
, чтобы он запрашивал у модели данные используя get-метод класса JViewLegacy
:
site/views/helloworld/view.html.php
<?php // Запрет прямого доступа. defined('_JEXEC') or die; // Подключаем библиотеку представления Joomla. jimport('joomla.application.component.view'); /** * HTML представление сообщения компонента HelloWorld. */ class HelloWorldViewHelloWorld extends JViewLegacy { /** * Сообщение. * * @var string */ protected $item; /** * Переопределяем метод display класса JViewLegacy. * * @param string $tpl Имя файла шаблона. * * @return void */ public function display($tpl = null) { // Получаем сообщение. $this->item = $this->get('Item'); // Отображаем представление. parent::display($tpl); } }
Обратите внимание, что метод get() выступает в роли прокси для get* методов модели по умолчанию, где * заменяется значением первого параметра, который передается в get()
. Например, в нашем случае $this->get('Item')
в представлении равно методу getItem()
в модели.
Добавляем логирование
Пока наш компонент прост, но он будет становится все сложнее, а значит возникает вероятность возникновения различного рода ошибок. Мы поговорим об ошибках в следующей части, а сейчас нам необходимо подготовить компонент к обработке этих ошибок. И поможет нам в этом логирование. Конечно можно его не использовать, а выводить сообщение или генерировать исключение в случае ошибки. Но такой вариант не совсем нам подходит, так как мы находимся в публичной части и нет смысла показывать ошибки нашего компонента пользователям.
Для того, чтобы мы могли использовать логирование, нам необходимо выполнить подключение логгера используя метод JLog::addLogger() в нашей точке входа site/helloworld.php:
<?php
// Запрет прямого доступа.
defined('_JEXEC') or die;
// Подключаем логирование.
JLog::addLogger(
array('text_file' => 'com_helloworld.php'),
JLog::ALL,
array('com_helloworld')
);
// Подключаем библиотеку контроллера Joomla.
jimport('joomla.application.component.controller');
// Получаем экземпляр контроллера с префиксом HelloWorld.
$controller = JControllerLegacy::getInstance('HelloWorld');
// Исполняем задачу task из Запроса.
$input = JFactory::getApplication()->input;
$controller->execute($input->getCmd('task', 'display'));
// Перенаправляем, если перенаправление установлено в контроллере.
$controller->redirect();
Так как мы не указали своего пути к файлу логов при подключении логгера, то логирование в нашем случае будет осуществляться в указанный файл com_helloworld.php, находящийся в папке логов, которая определена конфигурационной переменной log_path
установки Joomla (по умолчанию папка /logs/). Мы логируем все ошибки (JLog::ALL
) и категория этих ошибок должна быть com_helloworld
. Это позволит нам избежать записи в наш лог посторонней информации от других расширений или самой Joomla.
Собираем пакет установки компонента
Не забудьте поменять номер версии в файле helloworld.xml:
<version>0.0.2</version>
А также добавим указание на использование контроллера, моделей и представлений в раздел основных файлов сайта:
<filename>controller.php</filename> <folder>models</folder> <folder>views</folder>
helloworld.xml
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="2.5.0" method="upgrade">
<name>Hello World!</name>
<!-- Следующие элементы необязательны -->
<creationDate>Июль 2012</creationDate>
<author>Вася Пупкин</author>
<authorEmail>Ваш e-mail</authorEmail>
<authorUrl>Ваш сайт</authorUrl>
<copyright>Информация о копирайте</copyright>
<license>Информация о лицензии</license>
<!-- Версия записывается в таблицу компонентов -->
<version>0.0.2</version>
<!-- Описание необязательно -->
<description>Описание компонента Hello World! ...</description>
<!-- Запускается при обновлении -->
<update>
<schemas>
<schemapath type="mysql">sql/updates/mysql</schemapath>
</schemas>
</update>
<!-- Раздел основных файлов сайта -->
<!-- Обратите внимание на значение аттрибута folder: Этот аттрибут описывает папку нашего пакета-установщика из которой должны копироваться файлы.
Поэтому указанные в этом разделе файлы будут скопированы из папки /site/ нашего пакета-установщика в соответствующую папку установки. -->
<files folder="site">
<filename>index.html</filename>
<filename>controller.php</filename>
<filename>helloworld.php</filename>
<folder>models</folder>
<folder>views</folder>
</files>
<!-- Администрирование -->
<administration>
<!-- Раздел Меню -->
<menu>Hello World!</menu>
<!-- Раздел основных файлов администрирования -->
<!-- Обратите внимание на значение аттрибута folder: Этот аттрибут описывает папку нашего пакета-установщика из которой должны копироваться файлы.
Поэтому указанные в этом разделе файлы будут скопированы из папки /admin/ нашего пакета-установщика в соответствующую папку установки. -->
<files folder="admin">
<filename>index.html</filename>
<filename>helloworld.php</filename>
<!-- Раздел SQL файлов -->
<folder>sql</folder>
</files>
</administration>
</extension>
Содержимое директории с кодом:
helloworld.xml
site/index.html
site/controller.php
site/helloworld.php
site/models/index.html
site/models/helloworld.php
site/views/index.html
site/views/helloworld/index.html
site/views/helloworld/view.html.php
site/views/helloworld/tmpl/index.html
site/views/helloworld/tmpl/default.php
admin/index.html
admin/helloworld.php
admin/sql/index.html
admin/sql/updates/index.html
admin/sql/updates/mysql/index.html
admin/sql/updates/mysql/0.0.1.sql Запакуйте директорию в архивный файл (zip, tar, tar.gz, bz2) или скачайте его напрямую с GitHub. Далее установите его, используя менеджер расширений Joomla и снова протестируйте компонент. Как и прежде наш компонент будет выводить сообщение "Hello World!", но на этот раз фраза будет выглядеть как заголовок, так как мы обрамили её тегами H2.
В следущей части мы разберем поддержку пунктов меню.
Код для этой части
Скачать com_helloworld часть 2
Актуальный код части 2 на GitHub