Создание компонента для Joomla

Часть 2 - добавление MVC и логирования

Joomla
Добавление в избранное
Сохранить
1

Часть 2 - добавление 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

Dmitry Rekun
Работаю в банковской сфере, а с веб-разработкой (непосредственно с Joomla) столкнулся в 2007 году. Теперь это моё хобби, а в редких случаях и вторая работа. Какое-то время вёл свой блог, но решил попробовать работать в команде. И вот c 2012 года я здесь :)

Подпишитесь на рассылку новостей CMScafe