xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Drupal 8 FAQ

Опубликовано в

Обновляемый список простых вопросов и ответов по Drupal 8.

Все консольные команды рассчитаны на выполнение из корня друпала. Windows пользователям перед выполнением команд нужно заменить разделитель директорий с / на \, т.е. вместо vendor/bin/drush писать vendor\bin\drush.

Общие вопросы

Как установить Drush?
$ composer require drush/drush

Подробнее.
Как обновить ядро друпала?
Если друпал установлен с помощью composer и стоит пакет webflo/drupal-core-strict:
$ composer update drupal/core webflo/drupal-core-strict --with-dependencies
$ vendor/bin/drush updb

Если пакета webflo/drupal-core-strict нет, то просто:
$ composer update drupal/core --with-dependencies
$ vendor/bin/drush updb

Подробнее.

Перед обновлением обязательно делаем бэкап файлов и базы!

Как узнать, какие composer пакеты зависят от определённого пакета?
Команда выдаст список пакетов, которые зависят от symfony/process
$ composer prohibits symfony/process
Как установить модуль?
# Последняя стабильная версия
$ composer require drupal/devel
 
# Dev версия
$ composer require drupal/devel:1.x-dev

Подробнее.
Как создать модуль?
$ vendor/bin/drush generate module

Или вручную
Как создать html ссылку?
Как программно создать страницу?
src/Controller/ModulenameController.php:
<?php
namespace Drupal\modulename\Controller;
 
use Drupal\Core\Controller\ControllerBase;
 
class ModulenameController extends ControllerBase {
  public function helloWorld() {
    return [
      '#markup' => 'Hello, World!',
    ];
  }
}

modulename.routing.yml:
modulename.hello_world:
  path: '/hello/world'
  defaults:
    _controller: '\Drupal\modulename\Controller\ModulenameController::helloWorld'
    _title: 'Hello, World!'
  requirements:
    _permission: 'access content'

Подробнее.

Или с помощью drush:

$ vendor/bin/drush generate controller

Как программно создать блок?
src/Plugin/Block/HelloWorldBlock.php:
<?php
namespace Drupal\modulename\Plugin\Block;
 
use Drupal\Core\Block\BlockBase;
 
/**
 * @Block(
 *   id = "hello_world_block",
 *   admin_label = @Translation("Hello world block"),
 * )
 */
class HelloWorldBlock extends BlockBase {
  public function build() {
    return array(
      '#markup' => 'Hello, World!',
    );
  }
}

Подробнее.

Или с помощью drush:

$ vendor/bin/drush generate block

Как создать пункт меню без ссылки?
Как добавить свою ссылку на странице admin/config?
modulename.links.menu.yml:
modulename.settings:
  title: 'Modulename settings'
  description: 'Settings for modulename.'
  parent: system.admin_config_system
  route_name: modulename.settings

При этом роут modulename.settings уже должен существовать. Подробнее.
Как очистить кэш?

На странице admin/config/development/performance нажать кнопку "Clear all caches".

Или выполнить в консоли:

$ vendor/bin/drush cache-rebuild

Или выполнить php функцию:

drupal_flush_all_caches();

Как правильно форматировать php код?
// Для отступов используется два пробела
function example() {
  $foo = 'bar';
}
 
// Между бинарными операторами ставится пробел
$a = 1 + 2; // Good
$a=1+2; // Bad
 
// Блок elseif/else начинается с новой строки
if (...) {
  ...
}
elseif (...) {
  ...
}
else {
  ...
}
 
// Массивы создаются с помощью короткого синтаксиса
$array = ['foo', 'bar']; // Good
$array = array('foo', 'bar'); // Bad
 
// Строки заключаются в одиночные кавычки
$string = 'foo'; // Good
$string = "foo"; // Bad
 
// Переменные именуются с помощью нижнего подчёркивания
$my_variable = 'foo'; // Good
$myVariable = 'foo'; // Bad
 
// Названия классов именуются в CamelCase
class MyFirstClass { }
 
// Переменные класса именуются в camelCase
class MyFirstClass {
  public $myFirstVariable;
}

Подробнее.
Как проверить, есть ли у сущности определённое поле?
if ($node->hasField('field_example')) {
  ...
}

hasField() проверяет наличие поля у сущности, а не на наличие значения в поле.
Как получить адрес текущей страницы? Аналог current_path(), request_path() и request_uri()?
// Системный адрес. Аналог current_path().
$current_system_path = \Drupal::service('path.current')->getPath();
 
// Синоним адреса. Аналог request_path().
$current_system_path = \Drupal::service('path.current')->getPath();
$current_path_alias = \Drupal::service('path.alias_manager')->getAliasByPath($current_system_path);
 
// Полный путь из строки браузера, с GET параметрами. Аналог request_uri().
$current_request_uri = \Drupal::request()->getRequestUri();
Как замерить время выполнения участка кода? Какой аналог timer_start() и timer_read()?
use Drupal\Component\Utility\Timer;
 
Timer::start('test');
sleep(1);
$time = Timer::read('test') . ' ms';
Как в своём модуле подключить определённую library на все страницы сайта?
modulename.module:
/**
 * Implements hook_page_attachments().
 */
function modulename_page_attachments(array &$page) {
  $page['#attached']['library'][] = 'modulename/libraryname';
}

Подробнее.
Как получить текущего пользователя? Какой аналог $GLOBALS['user']?
/** @var \Drupal\Core\Session\AccountProxyInterface $current_user */
$current_user = \Drupal::currentUser();

Функция \Drupal::currentUser() возвращает прокси-объект AccountProxy, которого для большинства случаев будет достаточно, но если нужна именно сущность пользователя, то:
$current_user_uid = \Drupal::currentUser()->id();
/** @var \Drupal\user\Entity\User $current_user */
$current_user = \Drupal\user\Entity\User::load($current_user_uid);
Как проверить права текущего пользователя? Какой аналог user_access()?
if (\Drupal::currentUser()->hasPermission('administer site configuration')) {
  ...
}
Как получить данные из $_GET, $_POST и $_COOKIE?
// $_GET
$nid = \Drupal::request()->request->get('nid');
$all_get_params = \Drupal::request()->request->all();
 
// $_POST
$nid = \Drupal::request()->query->get('nid');
$all_post_params = \Drupal::request()->query->all();
 
// $_COOKIE
$nid = \Drupal::request()->cookies->get('nid');
$all_cookie_params = \Drupal::request()->cookies->all();
Как экранировать html код? Что использовать вместо check_plain()?
$string = \Drupal\Component\Utility\Html::escape('<b>Hello</b>'); // Переменная будет содержать "&lt;b&gt;Hello&lt;/b&gt;"

Подробнее.
Что использовать вместо format_string()?
$string = new \Drupal\Component\Render\FormattableMarkup('My name is: @name', [
  '@name' => $name,
]);
@variable — текст будет пропущен через Html::escape().
%variable — текст будет пропущен через Html::escape() и обёрнут в <em></em>.
:variable — текст будет пропущен через Html::escape() и UrlHelper::stripDangerousProtocols().

Подробнее.

Чтобы запретить обрабатывать текст с помощью Html::escape() нужно передать в плэйсхолдер объект MarkupInterface:

$string = new \Drupal\Component\Render\FormattableMarkup('My name is: @name', [
  '@name' => \Drupal\Core\Render\Markup::create('<b>Dries</b>'),
]);

Как склонять строки с числом? Какой аналог format_plural()?
$string = \Drupal::translation()->formatPlural(123, '@count day', '@count days');

Подробнее.
Как вычислить число дней между датами в поле типа Date range?
$date_start = $node->field_daterange->start_date;
$date_end = $node->field_daterange->end_date;
$days_between_dates = $date_end->diff($date_start)->format('%d');
Как сделать необязательным второе значение в поле типа Date range?
До того, как не закрыта соответствующая issue, можно поставить модуль Optional End Date.
Как проверить тип поля на базовое/настраиваемое?
if ($node->title->getDataDefinition() instanceof BaseFieldDefinition) {
  // Поле title является базовым
}
if ($node->field_example->getDataDefinition() instanceof FieldConfigInterface) {
  // Поле field_example является настраиваемым
}

Темизация

Как переопределить шаблон в своей теме?
Скопировать нужный файл *.html.twig в папку templates своей темы, очистить кэш. Подробнее.
Как переопределить шаблон определённого блока?
У каждого блока есть машинное имя, которое прописывается в настройках блока при его добавлении в регион. Чтобы переопределить шаблон определённого блока, нужно скопировать файл core/modules/block/templates/block.html.twig в папку templates вашей темы, переименовать этот файл по шаблону block--machine-name.html.twig (где machine-name машинное имя нужного блока, нижние подчёркивания заменяются на тире) и сбросить кэш. Подробнее, раздел "Blocks".
Как переопределить шаблон определённого поля?
Скопировать файл core/modules/system/templates/field.html.twig в папку templates своей темы, переименовать файл по шаблону field--field-name.html.twig, где field-name это машинное имя поля, сбросить кэш. Подробнее, раздел "Fields".
Как в шаблоне проверить, есть ли у поля сущности значение?
{% if not node.field_example.isEmpty() %}
   field_example is not empty
{% endif %}
Как в шаблоне ноды/сущности вывести отдельные поля?
Отформатированное значение поля, прошедшее через field.html.twig:
{{ content.field_example }}

Отформатированное значение поля, но без использования field.html.twig:
{{ content.field_example.0 }}

Сырое значение поля:
{{ node.field_example.value }}
 
{# Или так, если в значении поля есть html код (небезопасно!) #}
{{ node.field_example.value|raw }}

Подробнее.
Как из javascript получить папку текущей темы?
THEMENAME.theme:
/**
 * Preprocess function for html.html.twig.
 */
function THEMENAME_preprocess_html(&$vars) {
  $vars['#attached']['drupalSettings']['path']['currentThemePath'] = $vars['directory'];
}

THEMENAME.libraries.yml:
my-library-name:
  js: ...
  dependencies:
    - core/drupalSettings

После этого путь к папке темы будет находится в js переменной drupalSettings.path.currentThemePath

Как получить информацию о текущей теме?
$current_theme = \Drupal::service('theme.manager')->getActiveTheme();
$current_theme_name = $current_theme->getName();
Как получить название дефолтной темы?
$default_theme_name = \Drupal::config('system.theme')->get('default');
Как в своей теме подключить определённую library на все страницы сайта?
themename.info.yml:
libraries:
  - themename/libraryname

Подробнее.

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

Как в php получить отрендеренное поле сущности? Какой аналог field_view_field()?
$node = \Drupal\node\Entity\Node::load(123);
 
// Render-array поля, прошедшего через field.html.twig
$field_example_build = $node->field_example->view('full');
// Render-array первого значения поля, прошедшего через форматтер
$field_example_build = $node->field_example[0]->view('full');
Как в php получить отрендеренный материал? Какой аналог node_view()?
$node = \Drupal\node\Entity\Node::load(123);
$node_view_builder = \Drupal::entityTypeManager()->getViewBuilder('node');
$node_build = $node_view_builder->view($node, 'teaser');
Как создать свой шаблон?
MODULENAME.module или THEMENAME.theme:
/**
 * Implements hook_theme().
 */
function MYMODULE_theme() {
  return [
    'my_template' => array(
      'variables' => [
        'my_variable' => NULL,
      ],
    ),
  ];
}

my-template.html.twig:
<div class="my-template">{{ my_variable }}</div>

Подробнее.
Как передать в twig шаблон переменную с html разметкой?
$variables['my_html_var'] = \Drupal\Core\Render\Markup::create('<b>Hello</b> <i>World</i>');

Работа с формами

Как изменить определённую форму?
Пример изменения формы регистрации с идентификатором user_register_form:
// modulename.module
 
use Drupal\Core\Form\FormStateInterface;
 
/**
 * Implements hook_form_FORM_ID_alter(): user_register_form.
 */
function modulename_form_user_register_form_alter(&$form, FormStateInterface $form_state) {
  $form['terms_of_use'] = [
    '#type' => 'checkbox',
    '#title' => t('I agree with terms and conditions.'),
    '#required' => TRUE,
  ];
}

Подробнее.
Как создать свою форму?
src/Form/ExampleForm.php:
<?php
namespace Drupal\modulename\Form;
 
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
 
class ExampleForm extends FormBase {
  public function getFormId() {
    return 'example_form';
  }
 
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['example_text'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Text'),
    ];
    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];
    return $form;
  }
 
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $text = $form_state->getValue('example_text');
  }
}

Или:
$ vendor/bin/drush generate form-simple

Подробнее.
Как вывести форму в блоке?
/**
 * @Block(
 *   id = "my_block_with_form",
 *   admin_label = @Translation("My block with form"),
 *   category = @Translation("Forms")
 * )
 */
class MyBlockWithForm extends BlockBase {
  public function build() {
    return [
      'form' => \Drupal::formBuilder()->getForm('Drupal\modulename\Form\ExampleForm')
    ];
  }
}
Как обойти элементы формы? Какой аналог element_children()?
foreach (\Drupal\Core\Render\Element::children($form) as $key) {
  debug($form[$key]);
}

Подробнее.
Написанное актуально для Drupal 8
Похожие записи

Комментарии RSS

Спасибо! Ценный материал, и в одном месте.

Насколько люблю 7-ку настолько же ненавижу 8-ку. Может я его неправильно курю? Простой пример, но вместо одной строки в info файле 7-ки делать отдельный файл с кучей строк(https://www.drupal.org/docs/8/api/menu-api/providing-module-defined-menu...). Зачем так усложнять?

Из .info файла ссылку конечно не создать, нужен hook_menu, но то что писать теперь нужно больше это да. Усложнено в угоду масштабируемости, хоть большинству она и не нужна. Тут просто надо свыкнуться с мыслью, что семёрка мертва и придётся учить много нового.

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании