Переходимо на Друпал 8: допомога Друпал-розробнику

24.09.2015
Переходимо на Друпал 8: допомога Друпал-розробнику
Автор:

Цей блог написаний розробниками для розробників. Якщо ви
хочете почитати про Drupal 7 в 8 у більш "легкому" стилі,
пропонуємо вам перейти на інший блог із презентацією.

Всім привіт! Ще зовсім недовго лишилося чекати до виходу Drupal 8, але вже зараз є можливість використовувати його бета версію. Отож, давайте разом вивчати Drupal 8.

Створення сторінок та пунктів меню

Мабуть, у кожного першим хуком, який прийшлось реалізовувати, був hook_menu(). Але, як би не було важко в це повірити, hook_menu() вилучений із Drupal 8. Основним завданням hook_menu() є створення пунктів меню і сторінок. У новій версії на зміну hook_menu() прийшла нова система маршрутизації. Для створення сторінки у Drupal 8 необхідно створити у папці модуля файл your_module.routing.yml. Вміст цього файлу виглядає приблизно так:

example_mod.mypage:
path: '/cust-page'
defaults:
_controller: '\Drupal\example_mod\Controller\ExampleModuleController::pagecontent'
_title: 'My page'
requirements:
_permission: 'idevels example conf'


  • example_mod.mypage - назва маршруту
  • path - шлях сторінки. Можна використовувати динамічні властивості за допомогою фігурних дужок (наприклад, path: '/cust-page/{node}' )
  • _controller - метод, що відповідає за відображення сторінки
  • _title - заголовок сторінки
  • permission - права, які необхідні для доступу

Наступним кроком є створення контролера сторінки. Для цього створюємо файл src/Controller/ExampleModuleController.php

Вміст файлу:

 'markup',
     '#markup' => t('My first page!!!'), 
   );
   return $build;
 }
}


Ось таким буде результат:

Варто зауважити, що назва класу контролера та його методу має співпадати із тими, які вказані в your_module.routing.yml.

У Drupal 7 для створення пункту меню у hook_menu потрібно було додати такий рядок: 'type' => MENU_NORMAL_ITEM . Виглядало це приблизно так:

function your_module_menu(){
    $items = array(); 
    $items['page_example'] = array( 
      'title' => 'Title',
      'description' => '', 
      'page callback' => '_page_example',
      'access callback' => TRUE,
      'type' => MENU_NORMAL_ITEM, 
      'menu_name' => 'main-menu', // вказуємо меню у якому буде створено посилання на сторінку
  );    
    return $items; 
}


Щоб створити пункт меню для сторінки у Drupal 8, необхідно створити файл із назвою your_module.links.menu.yml.

Вміст цього файлу виглядає приблизно так:

example_mod.mypage:
 title: 'Link to my page'
 description: 'example'
 route_name: example_mod.mypage
 weight: 100
 #If menu_name is omitted, the "Tools" menu will be used.
 menu_name: main


Результат вищевказаних дій:

Створення блоків

У Drupal 7 для створення блоків використовувались хуки hook_block_info та hook_block_view. Виглядало це приблизно так:

/**
* Implements
hook_block_info(). */ function your_module_block_info() { $blocks = array(); $blocks['BLOCK1'] = array( 'info' => t('BLOCK NAME'), ); return $blocks; } /** * Implements hook_block_view(). */ function your_module_block_view($delta = '') { $block = array(); switch ($delta) { case 'BLOCK1': $block['subject'] = ''; $block['content'] = t(‘Block content’); break; } return $block; }

У Drupal 8 ці хуки видалено. Отож, щоб створити блок, необхідно створити файл your_module/src/Plugin/Block/MyBlock.php. Вміст файлу виглядає так:

 <?php
/**
* @file
* Contains \Drupal\internetdevels\Plugin\Block\AboutLvivBlock.
*/

namespace Drupal\example_mod\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
* @Block(
*   id = "myblock",
*   admin_label = @Translation("MyBlock")
* )
*/
class MyBlock extends BlockBase {

 public function build() {
   return array(
     '#markup' => '<div class="myblock1">
<b><p>Creating a custom block defined by your module involves the following steps:</p></b>
<li>Create a block plugin using annotations</li>
<li>Extend the Drupal\Core\Block\BlockBase class.</li>
<li>Implement the necessary methods from the Drupal\Core\Block\BlockPluginInterface interface depending on your use case</li>
       </div>',
   );
 }
}

Отже, для створення блоку необхідно:

  • створити плагін блоку, використовуючи анотації
  • у класі блоку зробити наслідування від класу Drupal\Core\Block\BlockBase
  • реалізувати необхідні методи інтерфейсу Drupal\Core\Block\BlockPluginInterface залежно від вашого випадку

Необхідно звернути увагу на рядки 13-14. В них вказуємо ідентифікатор та заголовок блоку.

Програмне виведення блоку на сторінці можливе таким способом:

 'markup',
     '#markup' => $block['#markup'],
   );
   return $build;
 }
}


Реалізація функціоналу hook_init() на Drupal 8 за допомогою EventSubscriber

У Drupal 8 вилучено hook_init(). Якщо модуль повинен виконувати зміни досить рано у відповідь на запит, потрібно використовувати обробники подій.

Ось список подій ядра Drupal 8:

  • KernelEvents::CONTROLLER - подія контролера, що відбувається один раз, коли контролер був знайдений для обробки запиту.
  • KernelEvents::EXCEPTION - подія винятків, що відбувається, коли з'явиться неперехоплений виняток.
  • KernelEvents::FINISH_REQUEST - відбувається, коли згенерована відповідь для запиту.
  • KernelEvents::REQUEST - подія, яка відбувається на початку відправлення запиту.
  • KernelEvents::RESPONSE - відбувається, коли створена відповідь на запит.
  • KernelEvents::TERMINATE - подія припинення, що відбувається, коли запит відправлений.
  • KernelEvents::VIEW - відбувається, коли значення, яке повертається контролером, не є об’єктом відповіді.

Давайте зробимо редірект із сторінки My page (/cust-page) на сторінку My page (/pagewithblock), щоб подивитися, як це все працює.

Спочатку потрібно створити файл сервісів your_module.services.yml:

services:
 example_mod_subscriber:
   class: Drupal\example_mod\EventSubscriber\ExampleSubscriber
   tags:
     - { name: event_subscriber }


Потім створити файл your_module/src/EventSubscriber/MyExampleSubscriber.php, у якому будемо обробляти події.

Вміст цього файлу виглядає наступним чином:

getRequest()->getPathInfo() == '/cust-page') {
     $url = \Drupal::url('example_mod.mypage2');
     $event->setResponse(new RedirectResponse($url));
   }
 }
 /**
  * {@inheritdoc}
  */
 static function getSubscribedEvents() {
   $events[KernelEvents::REQUEST][] = array('checkForRedirection');
   return $events;
 }
}




Метод getSubscribedEvents() повертає масив імен подій. Ключами масиву є імена подій, а значеннями можуть бути:

  • ім'я методу для виклику (за замовчуванням пріоритет 0)
  • масив, який складається з імені методу для виклику і пріоритету масив
  • масивів з імен методів і їхніх пріоритетів, або пріоритет = 0, якщо не встановлено

Метод checkForRedirection(GetResponseEvent $event) - метод, який викликається відповідно на встановлену подію.

У рядку 16 провіряємо адресу сторінки, на яку здійснюємо перехід. За допомогою стрічки 17 формуємо url сторінки, на яку хочемо зробити редірект (example_mod.mypage2 - назва маршруту сторінки, на яку здійснюємо редірект). У рядку 18 встановлюємо відповідь на подію, у нашому випадку це об’єкт класу RedirectResponse з посиланням у якості параметра.

Підключення файлів скриптів та стилів css у Drupal 7 зручно здійснювати через hook_init(). Виглядає це так:

function your_module_init() {
  drupal_add_js(drupal_get_path('module','module_name') . '/script.js');
  drupal_add_css(drupal_get_path('module','module_name') . '/style.css');
}




У Drupal 8 підключення скриптів, стилів та бібліотек можна здійснити за допомогою hook_page_attachments(). Спочатку треба створити файл з описом бібліотек your_module/your_module.libraries.yml

my_lib:
 version: 1.x
 css:
   theme:
     css/example-style.css: {}

my_lib: - назва бібліотеки
version: 1.x - версія
css: - вказуємо, що підключаємо css
css/example-style.css: {} - шлях до необхідного файлу


Потім реалізуємо hook_page_attachments():

function example_mod_page_attachments(array &$attachments) {
 $attachments['#attached']['library'][] =  'example_mod/my_lib';
}



Як бачимо, бібліотека успішно підключилась. Також можна об’єднувати в одну бібліотеку скрипти та файли стилів.

Приклад:

my_lib:
 version: 1.x
 css:
   theme:
     css/example-style.css: {}
 js:
   your_script.js: {}


Детальнішу інформацію можна знайти тут.

Створення форм

Для створення форм у Drupal 7 використовувався hook_form(). Виглядало це якось так:

function example_form($form, &$form_state) {
  $form['fieldset'] = array(
    '#type' => 'fieldset',
    '#title' => t('firstcolumn'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#description' => t('Field description'),
  );
  $form['fieldset']['field1'] = array(
    '#type' => 'textfield',
    '#title' => t('Field title'),
    '#size' => 40,
    '#maxlength' => 50,
    '#required' => TRUE,
    '#element_validate' => array('example_form_validate'),
  );
  $form['submit'] = array('#type' => 'submit',
    '#value' => t('Submit'),
    '#prefix' => '<div class="form-actions"> ',
    '#suffix' => '</div>',
    '#tree' => TRUE,
  );
  return $form;
}

У Drupal 8 форми створюються іншим шляхом. Отож давайте розглянемо, як створити форму у Drupal 8.

Спочатку потрібно створити файл your_module/src/Form/MyExampleForm.php, у якому власне і буде створюватися форма:

 'email',
     '#required' => TRUE,
   );
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Submit'),
     '#name' => 'form-submit',
   );
   return $form;
 }

 /**
  * {@inheritdoc}
  */
 public function validateForm(array &$form, FormStateInterface $form_state) {
//тут відбувається валідація введених даних
 }
 /**
  * {@inheritdoc}
  */
 public function submitForm(array &$form, FormStateInterface $form_state) {
//дії при відправленні форми
 }
}



У методі getFormId() повертаємо ідентифікатор форми. За створення форми відповідає метод buildForm(), де саме й відбувається створення її елементів. Валідацію форми потрібно здійснювати у методі validateForm().

Далі в файл your_module.routing.yml додаємо наступні рядки:

example_mod.form:
 path: '/myform'
 defaults:
   _form: '\Drupal\example_mod\Form\MyExampleForm'
   _title: 'Example form'
 requirements:
   _permission: 'idevels example conf'



Детальнішу інформацію по створенню форм у Drupal 8 можна знайти тут і тут.

hook_cron() у Drupal 8

Також хотілося б привести простий приклад роботи hook_cron() на Drupal 8. Нехай крон усім новим нодам до тайтла додає в дужках nid цієї ноди. Такий приклад я обрав, щоб вбити двох зайців одразу. По-перше, побачимо, як працює крон, а по-друге — навчимося отримувати і змінювати значення полів нод.

Ось такий вигляд має реалізація хуку:

function example_mod_cron() {
 $nodes[] = node_load_multiple();
 $expires = \Drupal::state()->get('example_mod.cron_last_run', REQUEST_TIME);
 foreach ($nodes[0] as $node) {
   $nid = $node->nid->value;
   $time = $node->created->value;
   $title = $node->title->value;
   if ($time > $expires) {
     $new_title = $title . '(' . $nid . ')';
  $node->setTitle($new_title);
  $node->save();
   }
 }
 \Drupal::state()->set('example_mod.cron_last_run', REQUEST_TIME);
}



Давайте детальніше розберемося, який рядок за що відповідає. У рядку (2) створюємо масив, у який за допомогою функції node_load_multiple() завантажуємо усі ноди. За допомогою стрічки (3) отримуємо час останнього запуску крона. У стрічках (5), (6), (7) отримуємо значення потрібних полів. За допомогою стрічки (10) встановлюємо потрібне значення тайтла ноди, у рядку (11) зберігаємо ноду за допомогою методу save(). І, нарешті, встановлюємо в значення останнього запуску крона поточний час. Як бачимо, все дуже просто!

Детальнішу інформацію про hook_cron() у Drupal 8 можна знайти тут.

Використовуємо власний twig шаблон з допомогою hook_theme()

Як відомо, у Drupal 8 замість шаблонів Phptemplate використовуються Twig шаблони. Отож, розглянемо, як з допомогою hook_theme() змусити Друпал використовувати власний шаблон. Для прикладу давайте замінимо шаблон 'block__system_menu_block на свій, назвемо його custom-menu-template.html.twig. Виглядає встановлення власного шаблону наступним чином:

function bartik_theme($existing, $type, $theme, $path) {

 return array(
   'block__system_menu_block' => array(
     'template' => 'custom-menu-template',
   ),
 );
}



За замовчуванням вимкнена можливість дебажити файли шаблонів. Щоб увімкнути цю можливість, необхідно у файлі sites/default/services.yml встановити:

twig.config:
    debug: true



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

Сподіваємось, ці поради допоможуть вам у роботі з Drupal 8 та зроблять процес написання коду легшим та ефективнішим!

PS. Приклади модулів ви можете знайти в доданому файлі.

Голосів: 7 Рейтинг: 4

Також по темі

1

Він популярний, безкоштовний, гнучкий, потужний. Він — це Drupal! В цієї системи управління контентом (CMS) було вже 7 офіційних основних релізів, і 8-й відбудеться дуже скоро. Всіх цікавлять нові...

2

Бета-версія Drupal 8 вже побачила світ. Зараз команда InternetDevels розробляє перший проект на «вісімці». Працюючи з Drupal 8, ми дізналися багато цікавого і підготували огляд його інновацій.

Subscribe to our blog updates