Портал Belkin-labs»PHP классы»Статья
welcome!

Отдельные блоки и виджеты включают свои стили и скрипты

Пытаемся сформулировать проблему

Документирование своей работы иногда наталкивает на мысли. Так, когда я занимался описанием своей системы подключения стилей и скриптов, я задумался. Предположим, мы строим сайт или движок. Сделали некий сервис для шаблонизации. Этот сервис шаблонизации включает построение тега head. Этот тег, по хорошему, должен быть единственным местом, где мы подключаем внешние стили (сосредоточимся пока на стилях, ибо со скриптами все очень похоже). Но любой, уважающий себя движок или тулбокс, как у меня, должен позволять достаточно гибкое подключение внешних блоков или виджетов, суть одно и то же.

Мы стараемся унифицировать наши блоки. Если шаблон включает блоки, значит сам шаблон тоже есть некий блок. Это не моя выдумка! Так происходит во всех известных мне на данный момент движках. Но это либо особый блок шаблона, либо вообще некий блок ядра (ядерный блок). У этого шаблона или блока есть некие, характерные для него одного, стили. Скажем, таблица стилей шаблона. У любого другого блока или виджета, например, категории товарного каталога, есть свои стили. Если мы заходим в каталог, они должны быть подключены. Если мы в другом месте, то подключать их ненужно. Логично? Мне кажется да. И вот он вопрос.

Где подключать стили отдельного блока ("ядерного", "неядерного", виджета и тп)?

Вариант 1. В самом блоке.

Вариант 2. В "ядерном" шаблоне.

И у обоих этих вариантов есть свои недостатки и свои достоинства. Попробуем их выявить.

Подключаем стили в самом блоке

Логика варианта очевидна! Блок - есть отдельный изолированный элемент. Черный ящик. Стиль блока - есть элемент блока, присущий только ему. Очень логично подключать стиль блока в самом блоке. Здесь мы соблюдаем важнейший принцип ООП - инкапсуляцию. Другими словами, не выносим мусор за пределы блока.

Но есть и сложности! Скажу сразу. Не хотелось бы включать элементы style и пуще того link в теге body. Положено использовать эти теги не в body, а в head. Тогда каждый блок должен передать информацию о своих стилях шаблонизатору. И это порождает не большие, а очень большие проблемы и узкие места. Дело в том, что глядя на свой собственный сайт (движок), мы не можем вот так сразу сказать, какие блоки подключены к некоторой странице. Нигде в программе нет их списка. Есть абстрактная функция, которая принимает информацию от блоков. Чего она там принимает? От какого блока? И как эта функция называется? И где она находится? Короче говоря, управление этими стилями крайне затруднено.

Вот возьмем, для примера cs-cart. Мы делаем дополнение. Для того, чтобы подключить стиль, нам надо сделать в этом дополнении специфический хук, который обратится в шаблон и сделает в нем либо link, либо style. И вот теперь я хочу узнать, какой блок ставит стиль под названием таким-то? И как мне это сделать? Стили слиты в один файл. У меня нигде нет списка функций или списка дополнений, которые этот хук реализуют. Все эти функции спрятаны в своих блоках и имеют в общем случае довольно сложное название. Мне приходится делать поиск по всему проекту. И не факт, что я еще чего-нибудь найду или сразу найду, ибо хук может обращаться за стилем еще дальше.

Есть движки, где нам приходится напрямую строить нужный тег и включать его в шаблон. Как говорится, те же яйца, только в профиль.

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

Подключаем стили в одном определенном месте

У этого варианта есть существенные логические недостатки. Блок в одном месте, а его стили в другом. Зато с другой стороны, мы точно знаем, где подключаются стили, и, глядя в это ЕДИНСТВЕННОЕ место, мы четко видим, какой конкретно блок какой стиль ставит. Стоит ли говорить о том, сколько это экономит времени на разработку?

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

А может быть все вообще не так уж и страшно с логикой? Может быть все дело в стиле программирования? ООП нам в этом случае может здорово помочь. Предположим, у нас есть класс шаблона и каждый блок сайта оформляется в виде отдельного класса. Это условие всегда выполнимо, кстати. Тогда в совершенно определенном месте шаблона мы имеем некий код на подобие следующего:

<?php
 
$head->add_css($block1->styles());
$head->add_css($block2->styles());
$head->add_css($block3->styles());
 
// Или вот так, что не принципиально
 
$head->add_css(BLOCK1::styles());
$head->add_css(BLOCK2::styles());
$head->add_css(BLOCK3::styles());
 
?>

Как видите, можно добиться хорошей, просто абсолютной читаемости кода. Более того! Зная, какие блоки работают на сайте, мы совершенно точно знаем, какой метод отвечает за подключение. Открываем файл класса, ищем там метод styles(). Все ясно и понятно.

Логичный шаг, который все может испортить

И вот тут, глядя на приведенный блок кода, приходит следующая мысль: а не стоит ли преобразовать этот код к более универсальному виду:

<?php
 
foreach ($all_connected_blocks => $block) {
 $head->add_css($block->styles());
}
 
?>

Я бы не стал так делать. Этот блок кода нам все портит, ибо для того, чтобы узнать, что же в конечном итоге происходит, надо ставить точку прерывания и смотреть, какие конкретно блоки срабатывают. Нет уж! Лучше все через запятую (через точку с запятой) написать. Время - самый главный ресурс программиста.

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

Что же выбрать?

Я выбираю второй вариант. Блоки сами по себе, стили блоков сами по себе. Повторю. И то и другое имеет достоинства и недостатки. Второй вариант, на мой личный взгляд имеет недостатков меньше, чем первый.

Автор php-тулбокса для создания сайтов
Дмитрий Белкин

Статья создана 13.02.2015