Практические решения

Расширение MVC архитектуры Joomla!

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

Расширение MVC архитектуры Joomla!

А вы когда-нибудь замечали, что при разработке расширений для Joomla! вам приходится повторять одни и те же действия? Это вполне обычная ситуация при работе с фреймворками. Но у этого есть и оборотная сторона - возможность создания блоков кода для их повторного использования при разработке. Если вы разработчик, использующий Joomla!, то не стоит воспринимать ее как систему управления содержимым. Прямо сейчас забудьте про то, что вы разрабатываете расширение для CMS. Забыли? Отлично, едем дальше.

При работе с Joomla фреймворком вы можете использовать его возможности для создания сложных веб-приложений, которые не имеют никакого отношения к CMS. Будучи свободным разработчиком, я (Jarrod Nettles, прим. автора) зарабатываю на создании расширений для веб-сайтов, работающих на движке Joomla! Мои расширения представляют собой полноценные приложения, обеспечивающие работу самых загруженных и процессоемких областей сайта нашей компании. Все это делается в рамках фреймворка Joomla!

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

  • прикрепление файлов Javascript и CSS;
  • создание форм;
  • валидация полей для ввода информации;
  • получение доступа к веб-службам;
  • получение путей файлов;
  • обработка Ajax запросов.

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

Так как же убедиться, что мы не повторяемся?

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

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

Схема «Модель-представление-контроллер» (MVC)

Расширения Joomla! Работают по схеме "Модель-представление-контроллер", а в частности, классы JModel, JView и JController. Почти все, что отображается на экране, управляется при помощи этих основных классов. Другие классы тоже важны, но эти – ключевые, наша "большая тройка", которая заставляет работать все остальное. К сожалению, сфера их использования довольно ограничена.

Не поймите меня неправильно, как бы ни были хороши эти классы, ваши потребности отличаются от потребностей команды разработчиков Joomla!. Признаем, что они созданы для облегчения разработки системных расширений, а мы не переделываем системные расширения. Мы занимаемся разработкой своих расширений потому, что для решения наших задач нет необходимого функционала.

Для наглядного примера сделаем простую вещь – прикрепим файл Javascript к заголовку документа. Дело нехитрое, но возможно, эту процедуру придется повторять не единожды. Вот способ, которым я прикрепляю файл Javascript:

defined( '_JEXEC' ) or die( 'Restricted access' );
 
jimport( 'joomla.application.component.view' );
 
class TestViewExample extends JView
{
    public function display($tpl = null)
    {
        $document = JFactory::getDocument();
        $document->addScript('/components/com_test/assets/javascript/popup_ads.js');
 
        parent::display($tpl);
    }
}

С помощью текущего примера мы добавляем Javascript файл, котрый расположен в нашем компоненте (лично я храню скрипты и таблицы стилей, относящиеся к конкретному расширению, в его папке - но это лично мой выбор). Однако, если нам понадобится десять Javascript файлов, плюс несколько файлов CSS?

defined( '_JEXEC' ) or die( 'Restricted access' );
 
jimport( 'joomla.application.component.view' );
 
class TestViewExample extends JView
{
    public function display($tpl = null)
    {
        $document = JFactory::getDocument();
        $document->addScript( '/components/com_test/assets/javascript/popup_ads.js' );
        $document->addScript( '/components/com_test/assets/javascript/grid.js' );
        $document->addScript( '/components/com_test/assets/javascript/maphighlight.js' );
        $document->addScript( '/components/com_test/assets/javascript/email.js' );
        $document->addScript( '/components/com_test/assets/javascript/validate.js' );
        $document->addScript( '/components/com_test/assets/javascript/tokenizer.js' );
        $document->addScript( '/components/com_test/assets/javascript/tooltips.js' );
        $document->addScript( '/components/com_test/assets/javascript/ajaxlib.js' );
        $document->addScript( '/components/com_test/assets/javascript/header.js' );
        $document->addStyleSheet( '/component/com_test/assets/css/main.css', 'text/css');
        $document->addStyleSheet( '/component/com_test/assets/css/grid.css', 'text/css');
        $document->addStyleSheet( '/component/com_test/assets/css/ui.css', 'text/css');
 
        parent::display($tpl);
    }
}

Все вполне предсказуемо. У интерактивных веб-страниц очень часто есть потребность подключения Javascript и CSS. Эта информация с небольшими отличиями может повторяться десятки раз. И не только это - представьте, что у каждого вашего расширения будет похожая структура assets/javascript/file.js. Было бы значительно удобнее просто напечатать tokenizer.js и не париться. Это возможно!

Создайте основную папку и начните работу

Если вы еще этого не сделали, то создайте новую папку в директории /libraries установленной Joomla!. Это будет папка для ваших основных классов. Так будет легче импортировать файлы во время работы. Эта структура поможет использовать функцию jimport для того, чтобы оперативно подключать классы, но также можно использовать более продвинутый класс JLoader, и вам не понадобится хранить библиотеку в дереве файлов Joomla!

Назову свою библиотеку Custom, но вы можете использовать любое имя. Внутри этой новой папки создадим файл customview.php и вставим в него следующий код:

defined( '_JEXEC' ) or die( 'Restricted access' );
 
jimport( 'joomla.application.component.view');
 
class CustomView extends JView
{
    /**
    * Путь до папки с ассетами компонента.
    *
    * @var string
    */
    protected $assetpath;
 
    /**
     * Ссылка на экземпляр JDocument.
     *
     * @var object
     */
    protected $document;

    
    public function __construct($config = array())
    {
        // Автоматически подключаем экземпляр JDocument.
        $this->document = JFactory::getDocument();

        // Сохраням путь до папки с ассетами.
        $this->$assetpath = JURI::base(true).'/components/' . JRequest::getCmd('option') . '/assets/';
 
        parent::__construct($config);
    }
 
    /**
     * Добавляет Javascript файл из папки assets/javascript нашего компонента.
     *
     * @param $filename Имя файла.
     */
    public function addScript($filename)
    {
        $this->document->addScript($this->assetpath . 'javascript/'.$filename);
    }
}

Мы только что создали класс, который обладает всеми свойствами JView и добавили наш собственный метод addScript, который поможет нам с легкостью добавлять файлы Javascript, находящиеся в com_mycomponent/assets/javascript/. Это общий класс, не привязанный ни к какой части компонента, а $assetpath, который мы создали и описали, адаптируется к любому компоненту. Подключение файлов значительно облегчилось, так как этот компонент использует стандартную структуру директорий, которую вы задали.

Заметьте что мы определили магический метод __construct(). Если взглянуть на класс JView, можно заметить, что он определяет __construct() и выполняет множество других рутинных задач необходимых для процессов запроса. Это позволяет нам не повторяться - часть работ берет на себя JView, так как мы возложили на него эти работы при помощи parent::__construct(). Это позволяет нам делать свою работу без повторения всего того, о чем JView итак заботится за нас.

Важно помнить, что расширяя основные классы MVC, вам часто нужно будет отдавать контроль "в руки" родительского класса. Неплохо было бы освоить принципы работы JModelJView и JController прежде чем браться за их расширение.

Теперь, когда у нас есть собственный View класс, как же можно его использовать? Если у вас его еще нет, создайте  новый компонент и давайте создадим для него представление (view). Вот как на примере выглядит использование класса CustomView:

defined( '_JEXEC' ) or die( 'Restricted access' );
 
jimport( 'Custom.customview' );
 
class TestViewExample extends CustomView
{
    public function display($tpl = null)
    {
        $this->addScript( 'popup_ads.js' );
 
        parent::display($tpl);
    }
}

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

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

Редакция и оформление статьи: Дмитрий Рекун aka b2z

Оригинальная статья: Jarrod Nettles
Katerina Vorobyova
Переводчик, IT любитель, фотомодель.

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