12.2. Что такое hook в Drupal 8?

drupal 8 hooks

Drupal 8 это не монолитная система, в которой все идеально и ничего не нужно менять. Очень часто клиенты просят добавить ту или иную фичу на сайт. Для того чтобы можно было обслуживать код ядра друпала и наших дополнительных хотелок, в друпале мы используем модули. Модульная система позволяет расширять возможности друпала. Но что если нам нужно расширить возможности уже готового контрибного модуля? Мы, конечно, можем отправить запрос на доработку нужного нам функционала, создав issue на drupal.org и возможно через месяц, два.. год, два мы получим нужный нам функционал в том или ином модуле. Но мы можем поступить по другому и написать нужный нам код сами. Для того чтобы расширять возможности дополнительных модулей друпала, а также самого друпала мы будем применять hook'и и plugin'ы в своих собственных модулях.

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

Для взаимосвязи модулей и ядра Друпала, а также модулей между собой, в Друпале есть система хуков. Хук это обратный вызов функции, то есть когда выполнение кода доходит до хука, то происходит добавление кода нашей функции, которую мы дописываем в своем модуле. Таким образом мы можем обработать данные пользователя, меню, таксономии, нод различных контент типов в каждый момент из изменения, добавления, удаления или просто загрузки и отображения. Хуков для 8го друпала довольно много, но уже меньше по сравнению с 7ым друпалом, очень многие хуки были реализованы через сторонние компоненты symfony:

https://api.drupal.org/api/drupal/core%21core.api.php/group/hooks/8.2.x

Если посмотрите 7ую версию, то просто устанешь листать страницу хуков вниз:

https://api.drupal.org/api/drupal/includes%21module.inc/group/hooks/7.x

Но это не значит что 8ой Drupal стал менее мощным, просто все то что реализуется в 7ом друпале хуком, в 8ом нужно добавить для этого соответствующий плагин.

Если вы внимательно посмотрите на список хуков в 8ом друпале, то увидет в их название _alter на конце, это означает что этот хук предназначен для изменения значений переменных, например:

hook_form_alter() - позволяет изменить массив формы в процессе ее обработки в друпале. Позже мы разберем как генерируются формы из массивов в друпале. Чтобы применить этот хук в модуле, как и остальные хуки, мы просто пишем функцию:

function mymodule_form_alter() {
  // меняем массив формы
}

Я упростил пример, не написал аргументы функции, namespaces, с этим мы еще разберемся, пока мы должны вникнуть как в общем случае работают хуки. Mymodule это наш модуль, мы пишем вместо слова hook название нашего модуля и функция автоматически подхватается и изменяет массивы формы. Как это работает? В методе prepareForm вызывается другой метод alter():

$this->moduleHandler->alter($hooks, $form, $form_state, $form_id);

Это значит, что каждый модуль в друпале реализующий hook_form_alter(), вставляет свой код в это место. Таким образом если мы добавим код в какое-то место в друпале, то первым делом мы должны это делать через hook, потом через plugin и если уже совсем невозможно не изменить контрибный модуль, то мы патчим/хакаем/изменяем модуль (к сожалению, приходится делать и так). Пока перед нами не стоит задач, которые требуют изменять контрибные модули, поэтому давайте научимся писать свои модули.

Комментарии

Добавить комментарий

Войти, используя Loginza Google Account Yandex Mail.ru Vkontakte Facebook
(If you're a human, don't change the following field)
Your first name.
(If you're a human, don't change the following field)
Your first name.

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.

Добрый день!

Добрый день!

Скажите, пожалуйста, вот мне дебагер (Devel Kint) в месте вывода "views-view-list--slider.html.twig" пишет что я могу использовать хук 

<!-- THEME HOOK: 'views_view_fields__slider' -->

Как мне в bootstrap.theme обозначить этот хук, чтобы я мог добавить в шаблон переменные?

Вот это не работает:

<?
function bootstrap_theme() {
	return [
		'views_view_fields__slider' => [
			'variables' => [
				'items' => null
			]
		]
	];
}

Для каждого шаблона можно

Для каждого шаблона можно определить preprocess, то есть использовать хук и добавить переменные,

/**
 * Preprocess variables for html templates.
 */
function THEMENAW_preprocess_html(&$variables) {
  $variables['copyright_year'] = date('Y');
}

/**
 * Preprocess variables for page templates.
 */
function THEMENAME_preprocess_page(&$variables) {
  if (isset($variables['node']) {
    $variables['node_type'] = $variables['node']->getType();
  }
}

Соответсвенно этот код будет работать для шаблонов html.html.twig, page.html.twig.

Для препроцесса шаблона node.html.twig:

/**
 * Preprocess variables for node templates.
 */
function THEMENAME_preprocess_node(&$variables) {
  try {
    $variables['is_front'] = \Drupal::service('path.matcher')->isFrontPage();
  }
  catch (Exception $e) {
    $variables['is_front'] = FALSE;
  }
}

Все поля можно также препроцессить через hook_preprocess_field(), field.html.twig шаблона соотвественно:

/**
 * Preprocess variables for field templates.
 */
function THEMENAME_preprocess_field(&$variables) {

}

Для препроцесса шаблона блока используйте THEMENAME_preprocess_block():

/**
 * Create new variable for overriding site logo for old browsers.
 * @param $variables
 */
function THEMENAME_preprocess_block(&$variables) {
  switch ($variables['base_plugin_id']) {
    case 'system_branding_block':
      if ($variables['content']['site_logo']['#access'] && $variables['content']['site_logo']['#uri']) {
        $variables['site_logo_png'] = str_replace('.svg', '.png', $variables['content']['site_logo']['#uri']);
      }
      break;

  }

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

Тоже самое и с остальными шаблонами. 

Для хлебных крошек:

/**
 * Implements template_preprocess_breadcrumb().
 */
function THEMENAME_preprocess_breadcrumb(&$variables) {
  $route_match = \Drupal::routeMatch();
  if ($route_match->getRouteName() == 'entity.node.canonical') {
    $page_node = $route_match->getParameter('node');

    if (isset($variables['breadcrumb'][1]) && $variables['breadcrumb'][1]['text'] == 'Node') {
      unset($variables['breadcrumb'][1]);
    }

    if ($page_node->getType() == 'product') {
      if (isset($variables['breadcrumb'][1]['url']) && $variables['breadcrumb'][1]['url'] = '/products') {
        $variables['breadcrumb'][1]['text'] = t('Products');
      }
    }
  }
}

Вот список препроцессов для bootstrap темы для 8го друпала с одного из действующих сайтов:

16 * @see template_preprocess_views_view_list()
15 * @see template_preprocess_rdf_metadata()
31 * @see template_preprocess_links()
25 * @see template_preprocess_block()
36 * @see template_preprocess_field()
10 * @see template_preprocess_form()
10 * @see template_preprocess_radios()
10 * @see template_preprocess_datetime_form()
23 * @see template_preprocess_status_messages()
14 * @see template_preprocess_forum_submitted()
25 * @see template_preprocess_block()
25 * @see template_preprocess_block()
25 * @see template_preprocess_block()
25 * @see template_preprocess_block()
25 * @see template_preprocess_block()
37 * @see template_preprocess_field()
36 * @see template_preprocess_field()
36 * @see template_preprocess_field()
24 * @see template_preprocess_field()
25 * @see comment_preprocess_field()
37 * @see template_preprocess_field()
12 * @see template_preprocess_link_formatter_link_separate()
30 * @see template_preprocess_views_view()
18 * @see template_preprocess_views_view_summary_unformatted()
15 * @see template_preprocess_views_view_unformatted()
9 * @see template_preprocess_views_exposed_form()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
16 * @see template_preprocess_forum_icon()
31 * @see template_preprocess_links()
20 * @see template_preprocess_fieldset()
13 * @see template_preprocess_text_format_wrapper()
17 * @see template_preprocess_filter_tips()
9 * @see template_preprocess_file_upload_help()
16 * @see template_preprocess_filter_tips()
10 * @see template_preprocess_file_widget_multiple()
15 * @see template_preprocess_book_all_books_block()
10 * @see template_preprocess_menu_local_action()
20 * @see template_preprocess_toolbar()
28 * @see template_preprocess_book_navigation()
31 * @see template_preprocess_links()
23 * @see template_preprocess_taxonomy_term()
23 * @see template_preprocess_taxonomy_term()
23 * @see template_preprocess_taxonomy_term()
19 * @see template_preprocess_item_list()
16 * @see template_preprocess_aggregator_feed()
14 * @see template_preprocess_forums()
30 * @see template_preprocess_forum_list()
39 * @see template_preprocess_table()
19 * @see template_preprocess_item_list()
39 * @see template_preprocess_table()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
13 * @see template_preprocess_book_node_export_html()
56 * @see template_preprocess_search_result()
14 * @see template_preprocess_aggregator_item()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
23 * @see template_preprocess_taxonomy_term()
66 * @see template_preprocess_node()
67 * @see at_core_preprocess_node()
23 * @see template_preprocess_html()
12 * @see template_preprocess_region()
23 * @see template_preprocess_html()
16 * @see template_preprocess_book_export_html()
23 * @see template_preprocess_html()
23 * @see template_preprocess_html()
30 * @see template_preprocess_views_view_table()
15 * @see template_preprocess_views_view_rss()
18 * @see template_preprocess_views_view_summary()
11 * @see template_preprocess_views_view_opml()
14 * @see template_preprocess_views_view_grouping()
15 * @see template_preprocess_views_view_unformatted()
30 * @see template_preprocess_views_view()
9 * @see template_preprocess_views_view_mapping_test()
9 * @see template_preprocess_views_mini_pager()
13 * @see template_preprocess_views_view_row_rss()
9 * @see template_preprocess_views_view_row_opml()
24 * @see template_preprocess_views_view_grid()
18 * @see template_preprocess_time()
37 * @see template_preprocess_field()
11 * @see template_preprocess_file_link()
10 * @see template_preprocess_image()
36 * @see template_preprocess_field()
36 * @see template_preprocess_field()
36 * @see template_preprocess_field()
15 * @see template_preprocess_image_style()
12 * @see template_preprocess_image_formatter()
19 * @see template_preprocess_field_multiple_value_form()
10 * @see template_preprocess_select()

В вашем случае функция будет THEMENAME_preprocess_views_view_fields__slider(&$variables), THEMENAME замените на имя своей темы и скиньте всю функцию в файл THEMENAME.theme.

Как вывести переменные в hook

Как вывести переменные в hook?
Я нашел Хук, переменная передается и выводится как {{ newvar }}
Скажите, пожалуйста, как мне в этой функции узнать какие переменные существуют в $vars? 

function bearded_preprocess_views_view_unformatted__slaider(&$vars){
  $vars['newvar'] = 'testvar2';
}

Я пробовал: 
1. mail(.... print_r($vars)) - сервер отвечает ошибкой 500 (мало ОЗУ наверное)
2. print_r($vars); die(); - сервер падает с 500
3. Вывожу через {{ kint() }} - там СТОЛЬКО всего О.о

Обычно настраивают xdebug и

Обычно настраивают xdebug и смотрят переменные в PhpStorm:

http://drupalbook.ru/drupal/nastroyka-xdebug-v-open-server-dlya-phpstorm

По поводу ошибок во-первых нужно включить их вывод:

http://stackoverflow.com/questions/5438060/showing-all-errors-and-warnings

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