Немного истории

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

В старой системе шаблонизации, предшествовавшей JLayout (которая по большей части используется до сих пор для отображения представлений), для рендеринга приходилось копировать / вставлять одни и те же HTML-элементы каждый раз, когда нужно было отобразить теги. Это не сложно, не так ли? Но если у нас появляется баг, и кто-то исправляет его для материалов, но забывает исправить для категорий, а затем кто-то добавляет дополнительный функционал, но только для компонента обратной связи... Возникают проблемы, и становится сложнее поддерживать систему.

Для решения этой проблемы, Yannick Gaultier реализовал JLayout для CMS. Отличная и простая система повторно используемых элементов кода, которая позволяет рендерить HTML из объектов / массивов данных.

Преимущества использования макетов (layouts)

Благодаря системе JLayout мы можем рендерить теги элемента с помощью:

echo JLayoutHelper::render('joomla.content.tags', $itemTags);

По существу, этот код выводит содержимое файла /layouts/joomla/content/tags.php, где $itemTags является параметром для внутреннего использования. Единственное требование - объект $itemTags должен иметь одинаковую структуру для всех элементов.

В чем заключаются преимущества данного подхода?

  1. Повторное использование
    Нам нужно поддерживать только один макет. Верстальщику остается настроить его под свои нужды.
  2. Разделение данных и дизайна
    Другой замечательной возможностью JLayout является то, что он становится инструментом для разработчика, позволяющим отделить HTML код от PHP. В идеале, 100% разметки должно переопределяться верстальщиком без использования ядра Joomla! Это означает, что если вам нужно загрузить JS файл, вы подключаете его в том месте, в котором верстальщик может переопределить его загрузку - это нужно на случай, если верстальщик решит не использовать ваш JS файл и захочет заменить его другой библиотекой. Сейчас это является наиболее значимой проблемой в Joomla и является причиной, по которой разработчики бегут от страха после некоторого времени, проведенного с Joomla.
  3. Простая интеграция с 2.5.x
    Система макетов - всего 4 файла. Вы можете подключить их в свою библиотеку для поддержки 2.5 и /или расширить их с помощью своих классов.

Предыдущая система JLayout

В предыдущей системе JLayout вызов вроде этого:

$layout = new JLayoutFile('joomla.content.tags');
$layout->render($itemTags);

Будет искать макет в:

[0] => templates/mytemplate/html/layouts
[1] => layouts

Здорово! Это значит, что я могу его переопределить. Но можно также принудительно указать папку, из которой вы хотите загружать макеты:

$layout = new JLayoutFile('joomla.content.tags', JPATH_SITE . '/components/com_mycomponent/layouts');
$layout->render($itemTags);

Этот код будет искать макеты в:

[0] => templates/mytemplate/html/layouts
[1] => components/com_mycomponent/layouts

Прекрасно! Макеты по-прежнему переопределяются!

Новые требования

В предыдущей системе шаблонизации у нас по-прежнему остались следующие проблемы:

  • Разработчики, желающие использовать шаблонизацию внутри своих компонентов, должны указывать путь до макетов при каждом вызове или создавать собственные расширенные классы;
  • Что будет, если верстальщик захочет, чтобы вывод тегов в представлении материала отличался от вывода в представлении категории?
  • Если верстальщику нужно настроить отображение для одного конкретного компонента, как это сделать?
В своей работе я столкнулся с перечисленными выше проблемами и поэтому решил улучшить систему. Решение некоторых задач оказалось “крепким орешком”, т.к. в них использовалась старая система, но мне требовалась легкая автоматическая система, которая подходила бы для сложных решений.

Новые возможности

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

В качестве подсказки приведу пример того, как теперь можно вызывать макет:


$layout = new JLayoutFile('joomla.content.tags', null, array('debug' => true, 'client' => 1, 'component' => 'com_tags'));

1. Переопределение макета компонента

Теперь система автоматически ищет макеты в загруженном компоненте. Вызов, который мы использовали ранее:

$layout = new JLayoutFile('joomla.content.tags');
$layout->render($itemTags);

Будет автоматически искать макеты в следующих папках (в порядке очередности):

[0] => templates/mytemplate/html/layouts/com_mycomponent
[1] => components/com_mycomponent/layouts
[2] => templates/mytemplate/html/layouts
[3] => layouts

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

2. Принудительное задание компонента

Предыдущий пример автоматически определяет компонент, из которого вызвана разметка. Но что будет, если мне нужно вывести теги по такому же принципу, как и в com_tags? Это можно сделать с помощью следующего вызова:

$layout = new JLayoutFile('joomla.content.tags', null, array('component' => 'com_tags'));

3. Принудительное задание клиентской части

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

$layout = new JLayoutFile('joomla.content.tags', null, array('client' => 1, 'component' => 'com_tags'));

Параметр клиентской части поддерживает следующие значения:

  • 0, 'site' > frontend
  • 1, 'admin' > backend

4. Добавление включаемых путей

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

$layout = new JLayoutFile('joomla.content.tags');
$layout->addIncludePaths(JPATH_LIBRARIES . '/mylayouts');

Это добавит /libraries/mylayouts на верхний уровень при поиске макетов (максимальный приоритет). Мы также можем использовать массивы путей. Но помните, что в массиве последнее значение имеет самый высокий приоритет.

5. Суффиксы

Одним из предложений (в этом случае от Robert Deutz) было иметь возможность присваивать макетам суффиксы. Оригинальная идея заключалась в том, чтобы дать возможность расширениям искать характерный макет текущей версии Joomla! или использовать макет по умолчанию. Пример:

$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25')));
echo $layout->render($this->item->tags->itemTags);

Файлом макета в данном случае будет /layouts/joomla/content/tags.j3x.php или /layouts/joomla/content/tags.j25.php. Но это только один из примеров применения. Представьте, что вам нужен макет для RTL языков. Вы можете добавить макет в поиск для постоянного мониторинга, не подключен ли активный RTL язык. Или представьте почтовый индекс в адресе покупателя, который отображается в разных местах / в разном формате в зависимости от страны. Можно добавить проверку определенного макета для страны покупателя.

6. Субмакеты

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

Давайте рассмотрим другой пример: в redCOMPONENT мы хотели использовать настраиваемые инвойсы. Я сразу же подумал о макетах. Вот так мог бы выглядеть глобальный вызов:

JLayoutHelper::render('invoice', $invoiceData);

А внутри макета что-то типа:

<div>
    <div>
        <?php echo $this->sublayout('shopper', $displayData['shopper']); ?>
    </div>
    <div>
        <?php echo $this->sublayout('header', $displayData); ?>
    </div>
    <div>
        <?php echo $this->sublayout('products', $displayData['products']); ?>
    </div>
    <div>
        <?php echo $this->sublayout('footer', $displayData); ?>
    </div>
</div>

Это главный макет, который вызывает субмакеты. Таким образом, пользователи могли бы переопределить шапку инвойса и не затрагивать остальную систему.

При вызове субмакета система пытается найти папку, названную так же, как и этот макет, с субмакетами внутри. В этом примере у нас был бы главный макет invoice.php и в этой же папке была бы папка под названием invoice, которая содержит в себе субмакеты (shopper.php, header.php, products.php & footer.php).

Субмакеты будут наследовать любые настройки, переданные в родительский макет. Они будут искать по тем же включаемым путям, в той же клиентской части и с теми же суффиксами.

7. Режим отладки

Когда вы начинаете иметь дело с макетами в разных компонентах, клиентах и включаемых путях, вы можете легко запутаться и до конца не понимать, откуда же система загружает макеты. Именно поэтому мы включили отладочную систему UBU (Useful But Ugly :D – полезную, но ужасную). Для её включения необходимо передать параметр debug со значением true:

$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25'), 'debug' => true));
echo $layout->render($this->item->tags->itemTags);

Вы увидите что-то вроде этого:

jlayout-debug

Где не использовать макеты?

Макеты являются хорошей штукой, если их использовать по назначению, но если их использовать в неправильных местах, то это уже не то. Вот теперь все хотят перевести всё на макеты. Поэтому вы легко можете найти макеты, которые используются материалами, баннерами, контактами и т.д. Вы скажете: «Круто же, не? Мы не дублируем код!». Нет! Мы просто создаем один макет с кучей условий для различий между компонентами. По моему мнению, нет смысла использовать макет для отображения четырех полей. Это то, что должно быть сделано в шаблоне и никогда не использовать повторно вне ядра. И вот мой совет: если это может быть использовано вне ядра, тогда есть смысл делать макет. Пример таких макетов: отобразить список, кнопку, меню, поле, постраничную навигацию…Но в любом случае, макеты не панацея.

Итог

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