Ця стаття є другою з трьох частин серії про те, як побудувати модуль Drupal 8.
Як побудувати модуль Drupal 8:

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

У першій статті цього циклу ми почали з азів. Ми розглянули, які файли необхідні, щоб повідомити Drupal про нашому модулі, як працює процес маршрутизації і як програмно створити посилання меню в якості конфігурації.

У цій статті ми продовжимо роботу з нашим модулем, який ви можете переглянути в цьому сховищі, і розглянемо два інших важливих функціональних елементи: блоки і форми.

Для цього ми створимо власний блок, який повертає деякий настроюваний текст. Після цього, ми створимо просту форму, що використовується для виводу на екран введених користувачем даних.

Блоки Drupal 8

Крутим нововведенням в Drupal 8 стали більш наочні блоки, що практично перетворив їх у плагіни (нова концепція бренду). Тобто тепер вони являють собою функціональні елементи, які можна використовувати в різних місцях.

Ви можете створити в інтерфейсі блок і використовувати його по всьому сайту — ви більше не обмежені у використанні блоку тільки одним місцем застосування.

Давайте продовжимо і створимо простий тип блоку, який виводить на екран за замовчуванням «Привіт, Світ!«. Все, що нам знадобиться — це один файл класів, розташований в папці src/Plugin/Block кореневої директорії нашого модуля.

Давайте назвемо наш новий тип блоку DemoBlock, і, природно, він повинен буде міститися у файлі з іменем DemoBlock.php. В цей файл ми для початку можемо додати наступне:

$this->t(‘Привіт, Світе!’),
);
}
/**
* {@inheritdoc}
*/
public function access(AccountInterface $account) {
return $account->hasPermission(‘access content’);
}
}

Як і для будь-якого іншого файлу класів, ми починаємо з визначення імен нашого класу. Потім ми використовуємо клас BlockBase, так щоб ми могли розширити його, а також клас AccountInterface, так щоб ми могли отримати доступ до поточного активного користувача. Потім випливає те, з чим ви безумовно не зустрічалися в Drupal 7: анотації.

Анотації є інструментом пояснення PHP, вони розташовані в блоці коментарів того ж файлу, в якому визначається клас. Використовуючи анотації, ми повідомляємо Drupal, що ми хочемо зареєструвати новий тип блоку (@Block) з ідентифікатором demo_block і admin_label — Demo block (передаються через систему перекладу).

Далі, ми розширюємо клас BlockBase в наш власний DemoBlock, всередині якого ми реалізуємо два методи (найбільш поширені з них ми будемо розглядати докладно пізніше). Метод build() — найбільш важливий з них, так як він повертає відображається масив, який буде виводити блок. Метод access) контролює права доступу для перегляду цього блоку.

Параметр, який передається до нього, є екземпляром об’єкта класу AccountInterface, в якості якого в цьому випадку буде виступати поточний користувач.

Ще одна цікава річ, яку я хочу відзначити. Ми більше не використовуємо для перекладу глобально функцію t(), а посилаємося на метод t(), реалізований в батьківському класі.

От і все. Тепер ви можете очистити кеш і перейти на сторінку конфігурації Block layout. Здорово, що типи блоків розташовуються праворуч (де ви можете відфільтрувати), і ви можете розмістити один або декілька з цих типів блоків в різних місцях на вашому сайті.

Конфігурація блоку Drupal 8

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

Ми зробимо так, щоб ви могли змінити блок, вказати в полі ім’я, після чого блок буде говорити «Привіт» не світу, а цього імені.

По-перше, ми повинні визначити форму, що містить текстове поле. Так у нашому класі DemoBlock ми можемо додати новий метод blockForm():

/**
* {@inheritdoc}
*/
public function blockForm($form, &$form_state) {
$form = parent::blockForm($form, $form_state);
$config = $this->getConfiguration();
$form[‘demo_block_settings’] = array(
‘#type’ => ‘textfield’,
‘#title’ => $this->t(‘Who’),
‘#description’ => $this->t(‘Кому Ви хочете сказати «Привіт»?’),
‘#default_value’ => isset($config[‘demo_block_settings’]) ? $config[‘demo_block_settings’] : «,
);
return $form;
}

Ця форма реалізації API дуже схожа на Drupal 7. Однак є і певні нові елементи. По-перше, ми отримуємо масив $form з батьківського класу (так ми створюємо свою форму на базі існуючої, додаючи власне поле).

Це елементи стандарту OOP. Потім ми витягуємо і зберігаємо конфігурацію цього блоку.

Клас BlockBase визначає метод getConfiguration(), який робить це для нас. І в разі, якщо він був вже встановлений, ми встановлюємо для demo_block_settings значення #default_value.

Тепер настав час надати обробник цієї форми, який буде обробляти значення нашого поля і зберігати його в конфігурації блоку:

/**
* {@inheritdoc}
*/
public function blockSubmit($form, &$form_state) {
$this->setConfigurationValue(‘demo_block_settings’, $form_state[‘values’][‘demo_block_settings’]);
}

Цей метод також знаходиться всередині класу DemoBlock, і все, що він робить, це зберігає значення поля demo_block_settings в якості нового пункту блоку конфігурації (з ключем того ж імені для відповідності).

Нарешті, ми повинні налаштувати наш метод build(), так щоб включити в нього ім’я, яким блок повинен говорити «Привіт!«:

/**
* {@inheritdoc}
*/
public function build() {
$config = $this->getConfiguration();
if (isset($config[‘demo_block_settings’]) && !empty($config[‘demo_block_settings’])) {
$name = $config[‘demo_block_settings’];
}
else {
$name = $this->t(‘ніхто’);
}
return array(
‘#markup’ => $this->t(‘Привіт, @name!’, array(‘@name’ => $name)),
);
}

Досі все було досить просто. Ми отримуємо конфігурацію блоку і якщо значення нашого поля встановлено, ми використовуємо його в операторі виведення на екран. Якщо ні, то використовується загальне вираження. Ви можете очистити кеш і перевірити, чи працює блок.

Для цього відредагуйте блок, щоб призначити йому регіон, і додайте ім’я, яким блок повинен сказати «Привіт!»

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

Форми Drupal 8

Останнє, що ми сьогодні розглянемо, як створити просту форму. З-за обмежених можливостей цієї статті, я не зможу охопити управління її конфігурацією (збережені значення конфігурації, представлені через форми). Я тільки покажу, як визначаються форми, і як наведені значення виводяться на екран.

В Drupal 8 функції визначення форми згруповані всередині класу. Давайте визначимо простий клас DemoForm у файлі src/Form/DemoForm.php:

’email’,
‘#title’ => $this->t(‘Your .com email address.’)
);
$form[‘show’] = array(
‘#type’ => ‘submit’,
‘#value’ => $this->t(‘Submit’),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, array &$form_state) {
if (strpos($form_state[‘values’][’email’], ‘.com’) === FALSE ) {
$this->setFormError(’email’, $form_state, $this->t(‘This is not a .com email address.’));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
drupal_set_message($this->t(‘Your email address is @email’, array(‘@email’ => $form_state[‘values’][’email’])));
}
}

Крім елементів стандарту ТМР, все інше повинно виглядати для вас дуже знайомим по Drupal 7. Форма API залишилася значною мірою такий же (за винятком додавання деяких нових елементів форми і цього класу інкапсуляції). Так що ж відбувається у наведеному вище коді?

По-перше, ми оголошуємо область імен класу і використовуємо клас ядра FormBase, щоб ми могли розширити його нашим власним класом DemoForm. Після цього ми реалізуємо чотири методу, три з яких повинні бути вам знайомі. Метод getFormId() є новим. Його використання обов’язково. Він застосовується, просто щоб повертати машинне ім’я форми.

Метод buildForm() також обов’язковий, він створює форму. Як? Так само, як і в Drupal 7. Метод validateForm() є необов’язковим, і його призначення має бути вам зрозуміло з Drupal 7. І, нарешті, метод submitForm() виробляє обробку надання даних. Все дуже логічно і організовано.

Так чого ми намагаємося досягти за допомогою цієї форми? У нас є поле електронної пошти (новий елемент форми в Drupal 8), ми хочемо, щоб користувачі заповнювали його. За замовчуванням Drupal перевіряє, чи є вхідне значення в дійсності адресою електронної пошти.

Але наша функція перевірки визначає, чи належить ця адреса електронної пошти сервера з доменом .com, і якщо немає, то форма видає помилку. І в кінці обробник наданих даних просто виводить повідомлення на сторінці.

І останнє, що нам потрібно зробити, щоб використовувати цю форму, це надати для нього маршрут. Тому відредагуйте файл demo.routing.yml і додайте в нього наступне:

demo.form:
path: ‘/demo/form’
defaults:
_form: ‘DrupaldemoFormDemoForm’
_title: ‘Demo Form’
вимога:
_permission: ‘access content’

Цей код повинен виглядати для вас знайомим за попередній статті, в якій ми розглядали маршрутизацію для простої сторінки. Єдина відмінність полягає в тому, що замість _content в блоці defaults, ми використовуємо _form, щоб вказати, що метою є клас форми. І тому значенням є ім’я класу, який ми тільки що створили.

Очистіть кеш і перейдіть за адресою demo/form, щоб перевірити форму.

Якщо ви знайомі з drupal_get_form(), і ставите питанням, як вам завантажити форму способом, до якого ви звикли по Drupal 7, відповідь полягає у глобальному класі Drupal.

Таким чином, щоб отримати форму, ви можете використовувати його метод formBuilder() і зробити щось на зразок цього:

$form = Drupal::formBuilder()->getForm(‘DrupaldemoFormDemoForm’);

Після цього ви можете повернути $form, яка буде представляти собою відображається масив форми.

Висновок

У цій статті ми продовжили розгляд створення модуля Drupal 8. Ми вивчили два нових функціональних елементи: блоки і форми. Ми дізналися, як створити свій власний тип блоку, який ви можете використовувати для створення блоків в інтерфейсі.

Ми також дізналися, як додати для нього власну конфігурацію і як зберігати значення для подальшого використання. Що стосується форм, я показав вам просту реалізацію класу FormBase, який ми використовували, щоб вивести на екран значення, надані користувачем.

У наступній статті ми побіжно розглянемо форми конфігурації. Ми будемо зберігати значення, надані користувачем, за допомогою конфігурації системи Drupal 8. Крім того, ми розглянемо службовий контейнер і введення залежностей, і як вони працюють в Drupal 8. Побачимося.

Переклад статті «Build a Drupal 8 Module: Blocks and Forms» був підготовлений дружною командою проекту Сайтостроение від А до Я.