Разработка тем оформления для Drupal 8. Часть 6: Использование функций

В этой статье мы разберем работу с функциями в темах оформления. Система функций Drupal обладает большой гибкостью и позволяет существенно повысить эффективность разработки.

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

Функции темы оформления — это обычные функции Drupal, которые вызываются в определенные моменты рендера и позволяют влиять на этот процесс. Все функции пишутся на языке PHP и имеют определенный формат, что подразумевает более высокий порог знаний, необходимый для работы с ними. Однако с большинством задач, которые могут возникнуть в повседневной работе, можно разобраться с помощью примеров или рекомендаций на тематических ресурсах.

В теме оформления функции могут применяться для самых разных задач, например:

  • определение, переопределение или удаление шаблонов элементов;
  • управление атрибутами элементов;
  • управление библиотеками.

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

Система функций

Функции темы описываются в файле THEMENAME.theme, который должен располагаться в корневой папке вашей темы. Как и с шаблонами, можно воспользоваться как системными функциями, так и создавать собственные. В Drupal предусмотрены специальные точки в процессе рендера, в которых вызываются соответствующие функции — "хуки" (hook). В каждой такой точке будет доступен определенный контекст и переменные. В зависимости от элемента, на который мы хотим повлиять, нам нужно будет определить этот контекст и необходимый хук.

Функции должны иметь определенный формат названия, по нему Drupal определяет момент, когда функция должна быть вызвана. Все функции в вашей теме (модуле) должны начинаться с названия темы (модуля). Это сделано, чтобы избежать конфликтов имен. Остальная часть названия определяется используемым хуком.

Например, чтобы добавить класс тегу body, который фигурирует в шаблоне html.html.twig мы должны использовать хук hook_preprocess_html() и назвать функцию THEMENAME_preprocess_html().

Пример добавления классов для тега body в зависимости от выполнения условий:

<?php

use Drupal\Core\Template\Attribute;

/**
 * Implements hook_preprocess_HOOK() for HTML document templates.
 */
function THEMENAME_preprocess_html(&$variables) {
  // Add layout-wide class to all pages
  $variables['attributes']['class'][] = 'layout-wide';

  // Add page-front class to front page
  if (\Drupal::service('path.matcher')->isFrontPage()) {
    $variables['attributes']['class'][] = 'page-front';
  }

  // Add page-contacts class to front page
  $path = \Drupal::service('path.current')->getPath();
  $alias = \Drupal::service('path.alias_manager')->getAliasByPath($path);
  if ($alias == '/contacts') {
    $variables['attributes']['class'][] = 'page-contacts';
  }
}

В данном примере $variables — это массив данных, который передается в шаблон и используется при рендере каждой страницы. В зависимости от страницы, в него добавляются соответствующие элементы. В результате всем страницам добавится класс layout-wide, главной странице — класс page-front, а странице с синонимом /contacts — класс page-contacts. Возможно, вам не сразу удастся составить условия для определения нужных страниц, однако это эффективней, чем делать два дополнительных шаблона, которые будут отличаться лишь одним классом.

Темизация Форм

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

Допустим, нам нужно добавить в поля формы авторизации заполнители вместо заголовков и описаний полей.

Пример темизации формы авторизации пользователя:

<?php

use Drupal\Core\Template\Attribute;
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_alter().
 */
function THEMENAME_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Remove title and description for name and password and set placeholder instead
  if ($form_id == 'user_login_form') {
    $form['name']['#title'] = Null;
    $form['name']['#attributes']['placeholder'] = t('Login');
    $form['name']['#description'] = Null;
    $form['pass']['#title'] = Null;
    $form['pass']['#attributes']['placeholder'] = t('Password');
    $form['pass']['#description'] = Null;
  }
}

В этом примере мы использовали функцию THEMENAME_form_alter(), которая будет вызываться при рендере каждой формы. По идентификатору $form_id мы можем определить форму, в которую нужно внести изменения — форму авторизации пользователя. Идентификатор формы обычно можно узнать из кода страницы, проще всего это сделать поиском по ключевому слову form_id, в нашем случае это будет user_login_form.

Массив $form ничто иное как рендер-массив, содержащий всю информацию о форме. Чтобы узнать ключи элементов, которые нам нужно изменить, можно воспользоваться инструментом Kint модуля Devel.

Форма авторизации отображается только для неавторизованных пользователей, поэтому не забудьте добавить для них право "Access kint information".

Теперь мы можем использовать функцию kint() или ksm(), которые выводят содержимое переменной или массива, переданного в качестве аргумента. Добавим ее в нашу функцию темизации после проверки условия:

  if ($form_id == 'user_login_form') {
    kint($form);

Теперь, если зайти на страничку с формой авторизации, вверху будет выведен раскрывающийся список всех элементов массива $form.

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

Примечание

Воспользоваться Kint можно и в шаблонах. Вызов функции выглядит следующим образом: {{ kint() }}.

Для работы функции необходимо, чтобы был включен режим debug (см. Шаблоны Twig)

Предварительные итоги

Освоив методы темизации, описанные в этом цикле статей, вы сможете повысить эффективноть разработки тем оформления.

В проектах, где основной упор делается на стили, применение CSS препроцессоров и автоматической сборки в разы сокращает время разработки. В случае, когда в проекте используются уже готовые стили, например Bootstrap, умение применять шаблоны и функции темизиции поможет в создании необходимой разметки. Бывают и случаи, когда требуется интегрировать готовую тему с существующей разметкой и содержимым. Для таких проектов применение и комбинирование различных методов темизации просто необходимо.

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