Содержание
Предупреждение

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

Дата релиза: декабрь 2021
Активная поддержка до: июнь 2022
Поддержка безопасности до: декабрь 2022

Маршруты ревизий нод теперь конвертируют параметры {node} и {node_revision} в сущности

Маршруты ревизий нод, такие, как /node/123/revisions/456/view, теперь возвращают объекты сущности Node при обращении к параметрам \Drupal::routeMatch()->getParameter('node') и \Drupal::routeMatch()->getParameter('node_revision').

Данное изменение касается следующих маршрутов:

  • entity.node.revision: /node/{node}/revisions/{node_revision}/view
  • node.revision_revert_confirm: /node/{node}/revisions/{node_revision}/revert
  • node.revision_revert_translation_confirm: /node/{node}/revisions/{node_revision}/revert/{langcode}
  • node.revision_delete_confirm: /node/{node}/revisions/{node_revision}/delete

Ранее:

$nid = \Drupal::routeMatch()->getParameter('node');
$node = \Drupal\node\Entity\Node::load($nid);
$vid = \Drupal::routeMatch()->getParameter('node_revision');
$node_revision = node_revision_load($vid);

До этого изменения, $nid и $vid возвращали целые числа, поэтому требовалось загружать сущность самостоятельно.

Теперь:

$node = \Drupal::routeMatch()->getParameter('node');
$nid = $node->id();
$node_revision = \Drupal::routeMatch()->getParameter('node_revision');
$vid = $node_revision->getRevisionId();

Параметры возвращают объекты сущности.

ThemeManagerInterface::getActiveTheme() теперь принимает параметр $route_match

Сигнатура метода ThemeManagerInterface::getActiveTheme() была обновлена следующим образом:

public function getActiveTheme(RouteMatchInterface $route_match = NULL) {

Отсутствие данного параметра было недосмотром при введении данного интерфейса в ядро. Все реализации данного интерфейса ядром ожидают данный аргумент.

Представлен новый метод Connection::lastInsertId(), опция запроса 'return' и константы Database::RETURN_* были помечены устаревшими

Опция запроса return и константы Database::RETURN_* помечены устаревшими. В Drupal 10 они будут удалены, а Connection::query() всегда будет возвращать объект StatementInterface.

В целом, Connection::query() не должен использоваться для операций манипулирования данных (INSERT, DELETE, UPSERT, MERGE, TRUNCATE). Для данных целей Drupal предоставляет API для построения динамических запросов, который позволяет абстрагироваться от базы данных.

Для крайних случаев, когда INSERT требуется использовать при помощи Connection:query(), добавлен новый метод Connection::lastInsertId() который возвращает ID последнего значения.

Для операций UPDATE и других, начиная с текущего изменения не следует использовать Database::RETURN_AFFECTED. Вместо этого используйте подсчёт строк, передав соответствующий аргумент в конструктор.

Ниже представлен пример использования Connection::nextId() для MySQL базы данных.

Ранее:

$new_id = $this->query('INSERT INTO {sequences} () VALUES ()', [], ['return' => Database::RETURN_INSERT_ID]);

Сейчас:

$this->query('INSERT INTO {sequences} () VALUES ()');
$new_id = $this->lastInsertId();

Drupal больше не поддерживает Opera Mini

Начиная с Drupal 9.3.0, Drupal ядро больше не гарантирует поддержку на Opera Mini.

Заметка

Не перепутайте Opera Mini с Opera Mobile — это два разных браузера. Второй будет поддерживаться корректно, так как он основан на Chromium.

Специфичные для Drupal теги были удалены со страниц нод и терминов таксономии.

В предыдущих версиях Drupal, на страницах материалов сущности node и taxonomy_term добавлялись <link> теги в шапку страницы:

<link rel="delete-form" href="https://example.com/node/1/delete" />
<link rel="delete-multiple-form" href="https://example.com/admin/content/node/delete?node=1" />
<link rel="edit-form" href="https://example.com/node/1/edit" />
<link rel="version-history" href="https://example.com/node/1/revisions" />
<link rel="revision" href="https://example.com/node/1" />

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

canonical и shortlink по-прежнему будут добавляться без изменений, дополнительно, данные <link> теги будут теперь добавляться на страницы всех типов сущностей, а не только node и taxonomy_term.

Сайты, которым требуется старое поведение, могут вернуть ссылки добавив следующий код в hook_entity_view() или hook_page_attachments():

foreach ($node->uriRelationships() as $rel) {
  $url = $node->toUrl($rel)->setAbsolute(TRUE);
  // Add link relationships if the user is authenticated or if the anonymous
  // user has access. Access checking must be done for anonymous users to
  // avoid traffic to inaccessible pages from web crawlers. For
  // authenticated users, showing the links in HTML head does not impact
  // user experience or security, since the routes are access checked when
  // visited and only visible via view source. This prevents doing
  // potentially expensive and hard to cache access checks on every request.
  // This means that the page will vary by user.permissions. We also rely on
  // the access checking fallback to ensure the correct cacheability
  // metadata if we have to check access.
  if ($this->currentUser->isAuthenticated() || $url->access($this->currentUser)) {
    // Set the node path as the canonical URL to prevent duplicate content.
    $build['#attached']['html_head_link'][] = [
      [
        'rel' => $rel,
        'href' => $url->toString(),
      ],
      TRUE,
    ];

  if ($rel == 'canonical') {
    // Set the non-aliased canonical path as a default shortlink.
    $build['#attached']['html_head_link'][] = [
      [
        'rel' => 'shortlink',
        'href' => $url->setOption('alias', TRUE)->toString(),
      ],
      TRUE,
    ];
  }
}

// Since this generates absolute URLs, it can only be cached "per site".
$build['#cache']['contexts'][] = 'url.site';

// Given this varies by $this->currentUser->isAuthenticated(), add a cache
// context based on the anonymous role.
$build['#cache']['contexts'][] = 'user.roles:anonymous';

Вы можете посмотреть на удалённые реализации в taxonomy_page_attachments_alter() и content_translation_page_attachments().

Авторы модулей, которые добавляли для своих сущностей canonical и shortlink теги, могут удалить их.

Модули и темы теперь могут указывать уровень стабильности

Информационные файлы модулей и тем теперь поддерживают два новых параметра lifecycle и lifecycle_link.

Поддерживаемые значения для lifecycle:

  • experimental: Что-то новое, не завершённое. Будет показано предупреждение при попытке включить подобное расширение, но оно будет работать.
  • stable: (по умолчанию) Стабильное расширение, никаких дополнительных предупреждений показано не будет.
  • deprecated: Что-то на пути к выводу из применения. Пользователь по-прежнему сможет устанавливать подобное расширение, но будут показываться предупреждения.
  • obsolete: Поддержка прекращена. Пользователь должен удалить данное расширение. Ранее установленные расширения продолжат работать, но будет показано предупреждение. Установить данное расширение будет невозможно.

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

Пример использования:

name: Some core module
type: module
description: '...'
package: Core
version: VERSION
core: 9.x.x
hidden: true
lifecycle: [experimental|stable|deprecated|obsolete] 
lifecycle_link: 'https://www.drupal.org/about/core/policies/core-change-policies/deprecated-and-obsolete-modules-and-themes#s-entity-reference'

В связи с изменением, добавлено новое исключение \Drupal\Core\Extension\Exception\ObsoleteExtensionException, которое выбрасывается при попытке установить obsolete расширение.

Добавлен класс с константами \Drupal\Core\Extension\ExtensionStatus в которых перечислены допустимые статусы.

Новый класс UpdateHookRegistry заменяет функции schema.inc

Константа SCHEMA_UNINSTALLED помечена устаревшей и была заменена Drupal\Core\Update\UpdateHookRegistry::SCHEMA_UNINSTALLED.

Следующие функции были помечены устаревшими и заменены соответствующими методами сервиса update.update_hook_registry:

  • drupal_get_schema_versions() заменена \Drupal::service('update.update_hook_registry')->getAvailableUpdates()
  • drupal_get_installed_schema_version() заменена \Drupal::service('update.update_hook_registry')->getInstalledVersion()
  • drupal_set_installed_schema_version() заменена \Drupal::service('update.update_hook_registry')->setInstalledVersion()

Стандартный профиль теперь предоставляет новую роль «Content Editor»

При установке стандартного профиля теперь добавляется новая роль — «Content Editor».

rel="shortcut icon" теперь rel="icon"

Исторически, иконка сайта (favicon) внедрялась в HTML следующим образом:

<link rel="shortcut icon" href="favicon.ico">

Данная разметка больше не соответствует HTML спецификации поэтому начиная с Drupal 9.3.0 разметка будет следующей:

<link rel="icon" href="favicon.ico">

Создание меню для страниц представлений больше не требует включения модуля menu_ui

Следующие плагины представлений больше не требуют активного модуля menu_ui:

  • \Drupal\node\Plugin\views\wizard\Node
  • \Drupal\views\Plugin\views\display\Page
  • \Drupal\views\Plugin\views\wizard\WizardPluginBase

Конструктор данных классов теперь требует опциональный аргумент с объектом, реализующий \Drupal\Core\Menu\MenuParentFormSelectorInterface (сервис menu.parent_form_selector).

Идентификатор раскрытой сортировки Views теперь может быть настроен

До текущего релиза, только идентификаторы раскрытых фильтров Views могли быть настроены. С текущего релиза также можно указать идентификаторы для раскрытых сортировок. Это позволяет указать более понятное значение в качестве идентификатора для sort_by.

В связи с данным изменением, метод \Drupal\views\Plugin\views\display\DisplayPluginBase::isIdentifierUnique() теперь требует третий параметр string $handler_type.

LayoutBuilderContextTrait::getAvailableContexts() помечен устаревшим в пользу LayoutBuilderContextTrait::getPopulatedContexts()

\Drupal\layout_builder\Context\LayoutBuilderContextTrait::getAvailableContexts() помечен устаревшим и будет удалён в Drupal 10. Вместо этого метода используйте новый метод \Drupal\layout_builder\Context\LayoutBuilderContextTrait::getPopulatedContexts().

Это сделано потому что метод ::getAvailableContexts() был предназначен, для того чтобы предоставить список доступных контекстов, но не предоставлял соответствующие значения для данных контекстов, так как некоторые значения вычисляются в рантайме. Это изменение позволяет Layout Builder использовать контексты, которые регистрируются в рантайме.

#date_time_callback и #date_date_callbacks должны реализовывать TrustedCallbackInterface

В Drupal 8.8.0 функции обратного вызова #access_callback, #lazy_builder, #pre_render и #post_render стали требовать реализации TrustedCallbackInterface. Начиная с текущей версии, это требование распространяется на функции обратного вызова для #date_time_callback и #date_date_callbacks.

Добавлены правила Eslint для ограничения использования jQuery в новом коде для дальнейшей совместимости

Для того чтобы ограничить использование jQuery в Drupal-ядре и улучшить совместимость с будущими версия, был добавлен плагин eslint-plugin-jquery в конфигурацию eslint core-jspassing.

В настоящее время включено только небольшое количество правил в eslint-plugin-jquery. В основном это правила проверяющие на использование возможностей jQuery которые не используются ядром. По мере того как ядро исключает использование той или иной функции jQuery, в связи с тем что современный ES6 JavaScript имеет аналогичные нативные возможности, дополнительные правила могут быть включены. Это предотвратит повторное использование этих функций jQuery.

Сервисам стало доступно автомонтирование

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

Сервисы могут быть автомонтированы, и ядро Drupal теперь включает тесты для этой функциональности. Это означает, что при определении сервиса в *.services.yml, во многих случаях аргументы могут быть автоматически выведены из подсказок типов аргументов конструктора. Чтобы активировать функцию автомонтирования, при определении сервиса необходимо указать autowire: true. (Включение autowiring по умолчанию для всех сервисов в файле пока не поддерживается).

Сервис будет создан точно так же, как и раньше, но нет необходимости явно указывать, какие сервисы требуются; интерфейсы, объявленные в конструкторе сервиса, будут использоваться для определения того, какие сервисы должны быть внедрены.

Хотя конструктор контейнеров/парсер файлов сервисов Yaml в Drupal теперь поддерживает автомонтирование, в ядре этот паттерн пока не реализован. Поскольку текущее соглашение Drupal об именовании сервисов использует строки, а не имена классов для идентификаторов сервисов, разработчики сайтов не сразу смогут использовать автомонтирование для сервисов из ядра. Для добавления уровня обратной совместимости псевдонимов сервисов существующих интерфейсов ядра существует последующий issue.

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

token:
  class: Drupal\Core\Utility\Token
  autowire: true
  arguments:
    $cache: '@cache.default'

В примере выше, аргумент $cache имеет тип \Drupal\Core\Cache\CacheBackendInterface, но у нас множество реализаций данного интерфейса и они имеют разные сервисы. В примере выше мы явно указали что данный параметр ожидает сервис @cache.default в качестве аргумента, а все остальные параметры будут автомонтированы, как и прежде.

Для более детальной информации об автомонтировании сервисов изучите документацию Symfony.

Модуль Update больше не зависит от модуля File

Модуль Update позволяет устанавливать модули и темы при помощи URL-адресов и загрузки файлов. Ранее, модуль File устанавливался как зависимость, хотя модуль Update может работать без него (загрузка на основе URL-адреса).

Теперь модуль File не является зависимостью для модуля Update, но всё также требуется если вы хотите включить установку модулей и тем при помощи загрузки архива.

Функции menu_list_system_menus() и menu_ui_get_menus() помечены устаревшими

Функции menu_list_system_menus() и menu_ui_get_menus() помечены устаревшими. Вместо них используйте систему сущностей.

Ранее:

$menu_list = menu_list_system_menus();

Сейчас:

Menu::loadMultiple();

Ранее:

$menu_list = menu_ui_get_menus();

Сейчас:

$menu_list = array_map(static function ($menu) {
  return $menu->label();
}, \Drupal\system\Entity\Menu::loadMultiple());
\asort($menu_list);

Несколько процедурных функций из модуля Taxonomy устарели в пользу прямого использования Entity API

Некоторые функции taxonomy.module устарели. Также, использование drupal_static_reset() c значением taxonomy_vocabulary_get_names в качестве параметра устарело.

Следующие функции устарели:

  • taxonomy_vocabulary_get_names()
  • taxonomy_term_uri()
  • taxonomy_term_load_multiple_by_name()
  • taxonomy_terms_static_reset()
  • taxonomy_vocabulary_static_reset()
  • taxonomy_implode_tags()
  • taxonomy_term_title()

Замены

taxonomy_vocabulary_get_names()

Ранее:

$vids = taxonomy_vocabulary_get_names();

Сейчас:

$vids = \Drupal::entityQuery('taxonomy_vocabulary')->execute();

taxonomy_term_load_multiple_by_name()

Ранее:

$terms = taxonomy_term_load_multiple_by_name(
  'Foo',
  'topics'
);

Сейчас:

$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary');
$terms = $storage->loadByProperties([ 
  'name' => 'Foo',
  'vid' => 'topics',
]);

taxonomy_term_uri()

Ранее:

$url = taxonomy_term_uri($term);

Сейчас:

$url = $term->toUrl();

taxonomy_terms_static_reset()

Ранее:

taxonomy_terms_static_reset()

Сейчас:

$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
$storage->resetCache();

taxonomy_vocabulary_static_reset()

Ранее:

taxonomy_vocabulary_static_reset($vids);

Сейчас:

$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary');
$storage->resetCache($vids);

taxonomy_implode_tags()

Ранее:

taxonomy_implode_tags()

Сейчас:

\Drupal\Core\Entity\Element\EntityAutocomplete::getEntityLabels();

taxonomy_term_title()

Ранее:

$name = taxonomy_term_title($term);

Сейчас:

$name = $term->label();

drupal_static_reset() + taxonomy_vocabulary_get_names

Ранее:

drupal_static_reset('taxonomy_vocabulary_get_names');

Сейчас:

$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_vocabulary');
$storage->resetCache();

Разрешения теперь могут объявлять зависимости

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

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

 * # The key is the permission machine name, and is required.
 * administer filters:
 *   # (required) Human readable name of the permission used in the UI.
 *   title: 'Administer text formats and filters'
 *   # (optional) Additional description fo the permission used in the UI.
 *   description: 'Define how text is handled by combining filters into text formats.'
 *   # (optional) Boolean, when set to true a warning about site security will
 *   # be displayed on the Permissions page. Defaults to false.
 *   restrict access: false
 *   # (optional) Dependency array following the same structure as the return
 *   # config entities dependencies.
 *   dependencies:
 *     config:
 *       - node.type.article

Добавление разрешений при помощи BundlePermissionHandlerTrait

Для того чтобы помочь вам добавлять подобные разрешения добавлен новый трейт Drupal\Core\Entity\BundlePermissionHandlerTrait с методом ::generatePermissions().

Например, Drupal\node\NodePermissions уже имеет метод ::buildPermissions(), который возвращает массив массивов. Ключами внешнего массива являются машинные имена разрешений, а внутренние массивы имеют ключи title (обязательно) и description (необязательно).

До Drupal 9.3.0:

  public function nodeTypePermissions() {
    $perms = [];
    // Generate node permissions for all node types.
    foreach (NodeType::loadMultiple() as $type) {
      $perms += $this->buildPermissions($type);
    }

    return $perms;
  }

В Drupal 9.3.0 и далее:

use Drupal\Core\Entity\BundlePermissionHandlerTrait;

class NodePermissions {
  use BundlePermissionHandlerTrait;
  // ...
  public function nodeTypePermissions() {
    return $this->generatePermissions(NodeType::loadMultiple(), [$this, 'buildPermissions']);
  }
  // ...
}

Функции file_create_url() и file_url_transform_relative() помечены устаревшими, добавлен новый сервис file_url_generator

Функции file_crete_url() и file_url_transform_relative() помечены устаревшими.

В качестве замены представлен новый сервис file_url_generator.

Ниже представлены примеры как старые вызовы заменить сервисом:

  • file_create_url($uri)\Drupal::service('file_url_generator')->generateAbsoluteString($uri)
  • file_url_transform_relative($file_url)\Drupal::service('file_url_generator')->transformRelative($file_url)
  • file_url_transform_relative(file_create_url($uri)\Drupal::service('file_url_generator')->generateString($uri)
  • Drupal\Core\Url::fromUri(file_create_url($uri))\Drupal::service('file_url_generator')->generate($uri)

Также были представлены следующие новые методы:

  • Метод ::generateString() генерирует URL относительно корня web-приложения (webroot, index.php).
  • Метод ::generateAbsoluteString() генерирует абсолютный URL.
  • Метод ::generate() URL-объект с относительным путём.
  • Метод ::transformRelative() который преобразует абсолютный URL локального файла в относительный.

Существующие сервисы asset.css.optimizer, asset.js.collection_renderer и asset.css.collection_renderer теперь принимают сервис file_url_generator в качестве аргумента.

Библиотека core/jquery.once помечена устаревшей

Изменения API:

  • Добавлена новая библиотека core/once использующая Drupal Once JavaScript API.
  • Библиотека core/jquery.once помечена устаревшей.
  • Добавлена новая глобальная переменная once в конфигурацию eslint.
  • Новая once библиотека предоставляет 4 функции:
    • once = $.once
    • once.filter() = $.findOnce()
    • once.remove() = $.removeOnce()
    • once.find() новая функция не имеющая аналога в jQuery.

Обратная совместимость

Если текущий код использует core/jquery.once из ядра, добавлен слой обратной совместимости который автоматически при использовании устаревшей библиотеки. Вызовы jQuery.once будут учитывать предыдущие вызовы once().

Для более детальной документации изучите Drupal Once JavaScript API.

// Core calls once()
once('once-id', '[data-drupal-selector="element"]');

// In a contrib or custom code, jQuery.once will work as expected: 
$('[data-drupal-selector="element"]').once('once-id') // will return an empty set.

Необходимые изменения в коде

Ранее:

# mymodule.libraries.yml
myfeature:
  js: 
    js/myfeature.js: {}
  dependencies:
    - core/drupal
    - core/jquery
    - core/jquery.once
# js/myfeature.js
(function ($, Drupal) {
  Drupal.behaviors.myfeature = {
    attach(context) {
      const $elements = $(context).find('[data-myfeature]').once('myfeature');
      // `$elements` is always a jQuery object.
      $elements.each(processingCallback);
    }
  };

  function processingCallback(index, value) {}
}(jQuery, Drupal));

После (удаляем jQuery зависимость):

# mymodule.libraries.yml
myfeature:
  js: 
    js/myfeature.js: {}
  dependencies:
    - core/drupal
    - core/once
# js/myfeature.js
(function (Drupal, once) {
  Drupal.behaviors.myfeature = {
    attach(context) {
      const elements = once('myfeature', '[data-myfeature]', context);
      // `elements` is always an Array.
      elements.forEach(processingCallback);
    }
  };

  // The parameters are reversed in the callback between jQuery `.each` method 
  // and the native `.forEach` array method.
  function processingCallback(value, index) {}
}(Drupal, once));

drupal_get_path() и drupal_get_filename() помечены устаревшими в пользу сервисов расширений

Функции drupal_get_path() и drupal_get_filename() помечены устаревшими. Вместо данных функций используйте, где это возможно, специальные методы \Drupal\Core\Extension\ExtensionList::getPath() и \Drupal\Core\Extension\ExtensionList::getPathname(). Вы можете использовать extension.path.resolver:getPath() и extension.path.resolver:getPathname() там где поддерживается Dependency Injection.

Данные методы выбрасывают следующие исключения:

  • \Drupal\Core\Extension\Exception\UnknownExtensionException если расширение не найдено.
  • \Drupal\Core\Extension\Exception\UnknownExtensionTypeException если тип расширения не найден.

Ниже представлен список того, как необходимо обновить свой код:

  • drupal_get_path()
    • drupal_get_path('module', 'node')\Drupal::service('extension.list.module')->getPath('node')
    • drupal_get_path('module', 'node')\Drupal::service('extension.path.resolver')->getPath('module', 'node')
    • drupal_get_path('theme', 'seven')\Drupal::service('extension.list.theme')->getPath('seven')
    • drupal_get_path('profile', 'standard')\Drupal::service('extension.list.profile')->getPath('standard')
  • drupal_get_filename()
    • drupal_get_filename('module', 'node')\Drupal::service('extension.list.module')->getPathname('node')
    • drupal_get_filename('module', 'node')\Drupal::service('extension.path.resolver')->getPathname('module', 'node')
    • drupal_get_filename('theme', 'seven')\Drupal::service('extension.list.theme')->getPathname('seven')
    • drupal_get_filename('profile', 'standard')\Drupal::service('extension.list.profile')->getPathname('standard')

Передача компилятора GuzzleMiddlewarePass была удалена

GuzzleMiddlewarePass отвечал за сбор сервисов с метками http_client_middleware и передавал их сервису с Guzzle (http_client).

TaggedHandlersPass выполняет ту же работу в общем виде - он работает для любого сервиса с меткой - поэтому теперь этот обработчик используется вместо него, а GuzzleMiddlewarePass был удален.

Если вы использовали или расширяли GuzzleMiddlewarePass, вам следует перейти на TaggedHandlersPass.

Функция file_build_uri() помечена устаревшей

Функция file_build_uri() была помечена устаревшей. Прямой замены данной функции не предоставлено.

Данная функция делает две вещи: объединяет схему по умолчанию (как правило public://) с предоставленным путём, а затем нормализует его.

Ранее:

$uri = file_build_uri($path);

Теперь:

$uri = \Drupal::config('system.file')->get('default_scheme') . '://' . $path;
/** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
$stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
$uri = $stream_wrapper_manager->normalizeUri($uri);

Однако нормализация пути не нужна, если это жестко заданная папка модуля, например file_build_uri('my_module') можно заменить лишь одной строкой \Drupal::config('system.file')->get('default_scheme') . '://my_module'.

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

Добавлена поддержка oEmbed-ресурсов которые не имеют явной высоты

Ранее система oEmbed требовала, чтобы все ресурсы без ссылок (т.е. фотографии, видео, текст) имели явную, ненулевую ширину и высоту, определенные в соответствии со спецификацией oEmbed.

Однако некоторые поставщики oEmbed, такие как Twitter и Instagram, не следуют этому правилу, потому что ресурсы, которые они обслуживают, содержат текст и могут быть адаптивными, поэтому они не могут иметь известную, заранее определенную высоту.

Для того чтобы Drupal мог работать с такими провайдерами, начиная с версии 9.3.0 высота ресурса, не являющегося ссылкой, теперь является необязательной, и если она не указана, то будет возвращаться к максимальной высоте, установленной в форматере.

oEmbed сервисы теперь запрашивают бэкенд кеша

Медиа система имеет три службы, которые вместе обеспечивают поддержку oEmbed:

  • \Drupal\media\OEmbed\ResourceFetcher
  • \Drupal\media\OEmbed\ProviderRepository
  • \Drupal\media\OEmbed\UrlResolver

Ранее каждый из этих сервисов принимал необязательный параметр $cache_backend, который мог быть NULL или экземпляром \Drupal\Core\Cache\CacheBackendInterface. Они использовали \Drupal\Core\Cache\UseCacheBackendTrait, чтобы вызывающий код мог включать/выключать кеширование.

Начиная с текущего изменения, бэкенд кеша всегда должен быть предоставлен, и сервисы больше не используют UseCacheBackendTrait. Чтобы отключить кеширование, передайте экземпляр \Drupal\Core\Cache\NullBackend. Подклассы должны напрямую вызывать $this->cacheBackend->get() и $this->cacheBackend->set() соответственно.

Типы ресурсов JSON:API теперь могут быть программно переименованы

Некоторые сайты могут захотеть раскрыть определенные типы ресурсов JSON:API под определенными именами.

В предыдущих версиях было невозможно переименовывать типы ресурсов, так как не было публичного PHP API, однако некоторые сторонние и пользовательские модули могли задекорировать класс Drupal\jsonapi\ResourceType\ResourceTypeRepository. Такой подход означал перезапись методов и приводил к сложному в поддержке решению. Например, jsonapi_extras значительно переопределяет класс, чтобы переименовать типы ресурсов.

JSON:API ResourceTypeBuildEvent теперь имеет новый метод: ::setResourceTypeName(string $resource_type_name). Подписчики этого события теперь могут переименовать ресурс, используя публично поддерживаемый PHP API.

Смотрите \Drupal\jsonapi_test_resource_type_building\EventSubscriber\ResourceTypeBuildEventSubscriber для примера того, как добавить синоним имени типа ресурса.

Была введена новая константа: Drupal\jsonapi\ResourceType::TYPE_NAME_URI_PATH_SEPARATOR. Эта константа представляет собой строку, которая используется в качестве разделителя путей в именах типов ресурсов. Функция Drupal\jsonapi\ResourceType::getPath() заменяет "--" на "/" в uri пути. Пример: node--articlenode/article.

Media Library будет передавать свое текущее состояние в hook_ENTITY_TYPE_create_access()

Модуль Media Library будет передавать в hook_ENTITY_TYPE_create_access() объект-значение, содержащий его текущее состояние (экземпляр Drupal\media_library\MediaLibraryState) в параметре $context при определении доступа к секции "add media" медиатеки. Это позволит сторонним и пользовательским модулям реализовать сложную логику доступа, например, для формы:

use Drupal\Core\Session\AccountInterface;

function mymodule_media_create_access(AccountInterface $account, array $context, $entity_bundle) {
  if (isset($context['media_library_state'])) {
    // $context['media_library_state'] is an instance of Drupal\media_library\MediaLibraryState. Use it as needed to
    // make an access decision.
  }
}

Для ясности, полученное решение о доступе будет применяться только к разделу медиатеки "Добавить медиа" (т.е. к той части, которая позволяет пользователю создавать новые медиа элементы), как в виджете поля, так и в CKEditor. Оно НЕ влияет на доступ к разделу медиатеки, позволяющему выбирать существующие медиафайлы, или на доступ к медиатеке в целом.

Сторонние JavaScript библиотеки теперь управляются через package.json

Для разработки ядра мы теперь используем package.json и дополнительный шаг сборки для добавления сторонних скриптов в ядро Drupal. Это сделано для того, чтобы облегчить обновление и упростить процесс обновления. В настоящее время все библиотеки управляются таким образом, кроме CKEditor и modernizr, для которых требуются пользовательские сборки, которые на данный момент не могут быть легко автоматизированы.

Ранее:

  1. Проверить страницу каждой библиотеки, чтобы узнать, доступна ли новая версия.
  2. Скачать последнюю версию библиотеки с github, npm или с сайта библиотеки.
  3. Обновить ядро и создать патч.

Теперь:

  1. Запустить yarn outdated чтобы проверить наличие обновлений.
  2. Запустить yarn upgrade <library> для каждой библиотеки что необходимо обновить.
  3. Запустить yarn vendor-update которая обновит библиотеку в core/assets/vendor директории, а также информацию в core.libraries.yml.
  4. Отправить изменения в ядро.

Drupal ядро больше не использует doctrine/reflection

Пакет doctrine/reflection больше не используется Drupal ядром потому что пакет заброшен и больше не поддерживается. Код из данного пакета на который опирается Drupal был скопирован в Drupal\Component\Annotation\Doctrine. Чтобы использовать этот код в сторонних и собственных модулях, вам требуется обновить пространства имён:

  • Doctrine\Common\Reflection\StaticReflectionParserDrupal\Component\Annotation\Doctrine\StaticReflectionParser
  • Doctrine\Common\Reflection\ClassFinderInterfaceDrupal\Component\ClassFinder\ClassFinderInterface

Пакет doctrine/reflection останется в зависимостях до Drupal 10 где и будет удалён. Однако, если вы хотите получить полную совместимость со всеми версиями PHP, код придется отрефакторить раньше, так как пакет не совместим с PHP 8.1.

Добавлен слой совместимости для InputBag Symfony

Symfony 5.2 представил Symfony\Component\HttpFoundation\InputBag для замены Symfony\Component\HttpFoundation\ParameterBag в некоторых случаях, и метод Symfony\Component\HttpFoundation\InputBag::get() был помечен устаревшим для нестроковых возвращаемых значений. Поэтому для получения нестрокового возвращаемого значения вместо него следует использовать Drupal\Core\Http\InputBag::all(). Класс Drupal\Core\Http\InputBag будет заменен классом Symfony\Component\HttpFoundation\InputBag, когда Symfony 4 перестанет поддерживаться Drupal.

Основное отличие в том что ::all() теперь может принимать параметр.

Ранее:

$ajax_page_state = $request->request->get('ajax_page_state', []);

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

Сейчас:

Вариант #1:

$ajax_page_state = $request->request->all('ajax_page_state');
  • Если значение по ключу не существует, метод вернёт пустой массив.
  • Если значение по ключу существует и не является массивом, тогда будет выброшено исключение UnexpectedValueException.

Вариант #2:

$ajax_page_state = $request->request->all()['ajax_page_state'] ?? NULL;
  • Вызывая метод таким способом, он никогда не приведёт к вызову исключения UnexpectedValueException.
  • Вызывая метод таким способом, у разработчика появляется возможность задать значение по умолчанию.

Шаблоны полей теперь учитывают настраиваемое отображение поля

Это изменение затрагивает только те сайты, которые включили настраиваемое отображение базовых полей типов материалов (title, uid и created) с помощью хука:

/**
 * Implements hook_entity_base_field_info_alter().
 */
function examplemodule_entity_base_field_info_alter(&$base_field_definitions, EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'node') {
    $base_field_definitions['created']->setDisplayConfigurable('view', TRUE);
  }
} 

Ранее

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

Это поведение можно было отменить следующим образом:

/**
 * Implements hook_theme_registry_alter().
 */
function mymodule_theme_registry_alter(&$theme_registry) {
  unset($theme_registry['field__node__title']);
  unset($theme_registry['field__node__uid']);
  unset($theme_registry['field__node__created']);
}

Сейчас

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

function mymodule_entity_type_build(array &$entity_types) {
  $entity_types['node']->set('enable_base_field_custom_preprocess_skipping', TRUE);
}

Изменения в шаблонах

В стандартных темах (Stable, Classy, Bartik) шаблоны полей типов материалов field--node--title.html.twig, field--node--created.html.twig, field--node--uid.html.twig были изменены для проверки новой переменной is_inline:

{% if not is_inline %}
  {% include "field.html.twig" %}
{% else %}
...

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

Константа FILE_STATUS_PERMANENT помечена устаревшей

Константа FILE_STATUS_PERMANENT помечена устаревшей.

  • Для проверки статуса файла используйте \Drupal\file\FileInterface::isPermanent() или \Drupal\file\FileInterface::isTemporary().
  • Чтобы сделать файл постоянным используйте \Drupal\file\FileInterface::setPermanent().
  • Константа \Drupal\file\FileInterface::STATUS_PERMANENT является внутренней заменой и не предназначена для использования сторонними разработчиками.

Ранее:

$fids = Drupal::entityQuery('file')
  ->condition('status', FILE_STATUS_PERMANENT, '<>')
...
if ($file->status->value !== FILE_STATUS_PERMANENT) {
  $file->status->value = FILE_STATUS_PERMANENT;
  $file->save();
}

Теперь:

use Drupal\file\FileInterface;
...
$fids = Drupal::entityQuery('file')
  ->condition('status', FileInterface::STATUS_PERMANENT, '<>')
if ($file->isTemporary()) {
  $file->setPermanent();
  $file->save();
}

Модуль Quick Edit больше не включен по умолчанию в стандартном профиле

Модуль Quick Edit планируется удалить из ядра в Drupal 10, основываясь на данных, которые указывают на то, что модуль нечасто используется целевой аудиторией, а также на многочисленных технических, юзабилити и ограничениях доступности текущего модуля.

В связи с этим Quick Edit был удален из «Стандартного» профиля в Drupal 9.3.0. Это изменение не затрагивает существующие сайты, только новые сайты, впервые устанавливающие профиль. Сайты Drupal 9.3.x могут продолжать использовать этот модуль, а для сайтов Drupal 10 он будет доступен как сторонний (contrib) модуль, хотя в долгосрочной перспективе рекомендуется рассмотреть альтернативные варианты.

Стандартный профиль будет продолжать предоставлять Contextual Links (модуль, который обеспечивает выпадающее меню с иконкой карандаша, позволяющее открыть форму редактирования фрагмента контента). Владельцы сайта могут также рассмотреть альтернативные решения для редактирования на месте, например, модуль Geysir.

PostgreSQL DB driver

  • #3230801 Драйвер больше не записывает NULL в blob поля.

ProviderRepository теперь запрашивает сервисы keyvalue и logger.factory

Начиная с этого изменения класс Drupal\media\OEmbed\ProviderRepository инициализируется с сервисами keyvalue и logger.factory. Он больше не принимает CacheBackendInterface и при попытке передачи такого аргумента будет выведено сообщение об устаревшем параметре.

Ранее, если вы инициализировали ProviderRepository передавая время истечения кеша, например 1000 секунд, вы могли сделать следующее:

new ProviderRepository($http_client, $config_factory, $time, $cache_backend, 1000);

Чтобы сделать то же самое сейчас:

new ProviderRepository($http_client, $config_factory, $time, $key_value_factory, $logger_factory, 1000);

ESLint теперь используется для валидации YAML

Плагин eslint-plugin-yml был добавлен в ESLint и скрипт прекоммита ядра, чтобы убедиться, что весь YAML в кодовой корректно отформатировано.

Запуск core/scripts/dev/commit-code-check.sh проверит все измененные файлы YAML.

Запуск yarn lint:yaml из каталога core проверит все YAML файлы в ядре.

Контроллеры, которые обращаются к $_SESSION, теперь принимают параметр Request

Контроллеры, которые ранее обращались к суперглобальному $_SESSION, теперь принимают параметр Symfony Request для своих методов контроллера. Теперь они получают доступ к сессии с помощью $request->getSession().

Ранее:

\Drupal\dblog\Controller\DbLogController::overview()
\Drupal\migrate_drupal_ui\Controller\MigrateController::showLog()
\Drupal\user\Controller\UserController::resetPassLogin()

Сейчас:

\Drupal\dblog\Controller\DbLogController::overview(Request $request)
\Drupal\migrate_drupal_ui\Controller\MigrateController::showLog(Request $request)
\Drupal\user\Controller\UserController::resetPassLogin(Request $request)

Настройка «Роль администратора» перемещена в новую форму «Настройки роли» по пути admin/people/role-settings

Новая форма «Настройки роли» теперь доступна по пути admin/people/role-settings как еще одна вкладка в разделе «Пользователи» (рядом с «Роли» и «Разрешения»), для доступа к которой требуется разрешение 'administer permissions'.

Это новый адрес для настройки «Роль администратора», которая раньше находилась по пути admin/config/people/accounts в форме «Настройки учетной записи». Эта настройка позволяет дать управление над правами доступа, поэтому для ее изменения пользователю теперь необходимо иметь права администратора.

Кеш-теги и контексты больше не всегда сортируются

Теги и контексты кеша всегда сортировались независимо от использования, чтобы сделать отладку и тестирование более удобными, однако это добавляло нагрузку на производительность при каждом HTML-запросе.

В целом это не повлияет на код во время выполнения, однако в некоторых тестах может потребоваться учитывать различные сортировки тегов/контекстов, в большинстве случаев изменения будут выглядеть следующим образом:

Ранее:

$this->assertEquals($expected_top_level_contexts, $element['#cache']['contexts'], 'Expected cache contexts found.');

Сейчас:

$this->assertEqualsCanonicalizing($expected_top_level_contexts, $element['#cache']['contexts'], 'Expected cache contexts found.');

Префиксы на уровне конкретных таблиц помечены устаревшими

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

Альтернативы:

  • Пользователи, сессии и/или пользовательские роли общие для нескольких сайтов. В качестве альтернативы можете использовать модули, которые позволяют организовать авторизацию в обход Drupal. Несколько примеров подобных модулей: Lightweight Directory Access Protocol (LDAP), CAS, simpleSAMLphp Authentication, OpenID Connect и Bakery Single Sign-On System.
  • Для более продвинутых сценариев, где таблицы должны копироваться или мигрировать, но вы хотите использовать API ядра: добавьте настройки подключения для глобального префикса, затем заинжектите эти подключения в необходимые классы.
  • Синхронизация содержимого и/или конфигураций. Синхронизация конфигураций поддерживается Drupal ядром, но синхронизация содержимого чуть сложнее. На данный момент существует инициатива для добавления синхронизации содержимого в ядро. Как альтернативу, вы можете рассмотреть модуль domain или deploy.

Bartik

  • #2725539 Улучшена контрастность различных состояний при наведении и фокусировке элементе.

Batch System

  • #2875279 Обновлён код в модулях Drupal-ядра который использовал batch_set(). Теперь для формирования пакетной обработки ядро использует BatchBuilder.

Block

  • #2268787 Для форм плагинов блоков в $form_state больше не передаётся block_theme значение, так как оно было крайне ненадёжно и приводило только к проблемам.
  • #2839558 Блокам добавлена контекстуальная ссылка «Удалить».

Book

  • #2412669 BookManager больше не использует drupal_static_reset(), вместо этого используйте \Drupal::service('book.manager')->resetCache();.

Bootstrap System

  • #2293257 Добавлены подсказки типов для переменных в DrupalKernel.

Claro

  • #3154539 Добавлена новые градации серого.

Comment

  • #2927874 Исправлена неполадка из-за которой предпросмотр комментария показывался в неположенном месте.

Composer

  • #3224000 Зависимости ядра обновлены на 27.07.2021.
  • #3225733 Удалены следующие зависимости ядра: fabpot/goutte и behat/mink-goutte-driver.
  • #3230562 Зависимости ядра обновлены на 31.08.2021.
  • #3232571 Зависимости ядра обновлены на 13.09.2021.

Configuration System

  • #2926729 ConfigManagerInterface::findConfigEntityDependents() и ConfigManagerInterface::findConfigEntityDependentsAsEntities() теперь ConfigManagerInterface::findConfigEntityDependencies() и ConfigManagerInterface::findConfigEntityDependenciesAsEntities() соответственно.
  • #2870874 EntityBase::getTypedData() теперь корректно возвращает данные для конфигурационных сущностей.

Content Moderation

  • #3211072 Плагин \Drupal\content_moderation\Plugin\Derivative\DynamicLocalTasks теперь требует передавать Router в конструктор.
  • #3226516 Удалён дублирующий вызов ::drupalGet() в ModerationStateNodeTypeTest.

Database System

  • #3211780 Connection::queryTemporary() помечен устаревшим.
  • #3224199 Свойство Connection::$temporaryNameIndex помечено устаревшим.
  • #838992 Поле UID для таблицы пользователей изменено с целого числа на последовательное.
  • #3230714 Тест ConnectionUnitTest пропускается если база данных не psql или mysql.

Entity Reference

  • #3225947 Удалён бесполезный файл entity_reference.install и simpletest_install().

Entity System

  • #3226487 Вкладка ревизий для материалов (node) теперь всегда показывается если у пользователя есть права на их просмотр и материал имеет больше одной ревизии.

Extension System

  • #3225779 Функция system_sort_modules_by_info_name() помечена устаревшей. В качестве замены используйте Drupal\Core\Extension\ExtensionList::sortByName().

Field System

  • #3184542 Максимальная длина для ввода метки поля увеличена со 128 до 255 символов.
  • #2226811 Исправлен тайпхинт для параметра $definition в FieldItemBase. Ранее он указывал что тип должен быть DataDefinitionInterface, но на самом деле ожидал ComplexDataDefinitionInterface.
  • #3218711 Добавлен тест покрывающий максимальный размер загрузки равный '300 0'. Данное значение невалидно и должно выдавать ошибку.
  • #2508866 Исправлена неполадка из-за которой описание поля не показывалось для полей с датой.

Field UI

  • #2726881 Удалена пагинация со страницы admin/reports/fields.

File System

  • #3224420 throw new FileTransferException() теперь возвращает 0 вместо NULL.
  • #2032893 Функция _views_file_status() помечена устаревшей.

Filter

Forms System

  • #3219541 Удалён избыточный вызов $this->requestStack->getCurrentRequest() в FormBuilder::buildForm().

Image

  • #3216106 Улучшено описание для плагина эффекта изображения image_convert.

Install system

  • #3185768 Из установщика удалены InlineServiceDefinitionsPass, RemoveUnusedDefinitionsPass, AnalyzeServiceReferencesPass и ReplaceAliasByActualDefinitionPass для того чтобы избежать бесполезную работу. Это позволяет ускорить установку (-19%) путём снижения количества вызовов функций.

JavaScript

  • #3212747 Удалено присвоение BABEL_ENV для скриптов сборки CSS и jQuery UI.
  • #3228351 В ядро добавлена новая библиотека — loadjs. На данный момент она будет использоваться в Drupal.ajax чтобы убедиться что библиотеки, запрошенные с AJAX ответом, подключились.

JSON:API

  • #3036593 ID сущности теперь содержится в meta.drupal_internal__target_id. Это позволяет фильтровать значения по данному свойству и получать внутренний ID, а не только UUID.
  • #3147244 Сервис jsonapi.field_resolver теперь принимает аргумент @current_user.

Language System

  • #3208373 Улучшено описание для LanguageNegotiationContentEntity. Теперь в нём говорится что за определение языка материала отвечают сервисы с метками language_content_entity.

Layout Builder

  • #3035174 Трейт SectionStorageTrait помечен устаревшим в пользу SectionListTrait.
  • #3230928 Удалена зависимость на Quick Edit из LayoutBuilderTest::testRemovingAllSections().

Media System

  • #3222486 Метки для удалённых видео (remote video) обновлены таким образом, что они теперь более последовательны и менее многословны.
  • #3222282 Из файла media_library.module удалён @todo на ишью #2964789.
  • #3028664 Ошибке oEmbed провайдера теперь логируются.
  • #3221493 Добавлены тесты покрывающие порядок меню в форме настроек типов материалов (node).
  • #3222465 MenuUiNodeTypeTest теперь использует специальную тестовую конфигурацию вместо системной.

Migration system

  • #3222168 Везде где в качестве сигнатуры использовался \GuzzleHttp\Client теперь используется \GuzzleHttp\ClientInterface.
  • #3215836 Добавлена новая константа MigrateSourceInterface::NOT_COUNTABLE которую необходимо использовать для неисчисляемых источников.
  • #3227549 \Drupal\migrate\Plugin\migrate\id_map\Sql::getRowByDestination() теперь всегда возвращает массив.

MySQL DB driver

  • #3224245 Подключение к MySQL теперь открывается с использованием \PDO::ATTR_STRINGIFY_FETCHES.

Node system

  • #3220956 Удалён @todo из шаблона node.html.twig напоминающий удалить id аттрибут, который был уже удалён.
  • #3037202 node_mark() больше не использует drupal_static(), соответственно, вызов drupal_static() с аргументом node_mark помечен устаревшим.
  • #3156244 SyndicateBlock теперь задаёт заголовок равный названию сайта.

Olivero

  • #3200370 Улучшено оформление drop-button элемента, для того чтобы он соответствовал новому оформлению форм.
  • #3174107 Добавлены тесты для темы Olivero.
  • #3223314 Библиотекам olivero.libraries.yml добавлены версии и отсортированы в алфавитном порядке.
  • #3226865 В шаблоне block--secondary-menu--plugin-id--search-form-block.html.twig <div> внутри <button> заменён на <span>.
  • #3226019 Протокол URL-адресов в block--secondary-menu.html.twig изменено на HTTPS.
  • #3216489 Исправлена неполадка из-за которой предзагрузка шрифта не работала если сайту задан base path.
  • #3228140 aria-label для кнопки мобильной навигации в page.html.twig изменено на «Main Menu».
  • #3212975 Селекторы в messages.es6.js заменены с классов на data-drupal-selector.
  • #3223332 Основная кнопка поиска теперь инициализируется с aria-expanded="false".
  • #3205597 Форме комментария добавлен заголовок.
  • #3224958 Раскрытые фильтры Views теперь отображаются в строке, а не в рядах.
  • #3226785 Поисковая форма теперь закрывается при потери фокуса.

Path

  • #3224592 \Drupal\path_alias\AliasManager::cacheClear() больше не вызывает предупреждения об устаревшем коде на PHP 8.1 и не пытается очистить кеш при NULL значении.

Plugin System

  • #1932810 Плагин-условия NodeType упразднён в пользу \Drupal\entity\Plugin\Core\Condition\EntityBundle, который был перенесён в ядро из модуля ctools.

Render System

  • #2794261 Функция render() помечена устаревшей. В качестве замены используйте сервис renderer.

REST

  • #3002352 CacheableHttpException теперь передаёт $headers аргумент в HttpException.

Routing System

  • #3183036 Сервисы проверки прав доступа, что не используются ни одним маршрутом, больше не инициализируются.

Serialization

  • #2997123 PrimitiveDataNormalizer теперь может передавать кеш-метаданные.

System

  • #778346 Функция system_sort_modules_by_info_name() помечена устаревшей и заменена идентичной system_sort_by_info_name(). Это переименование сделано так как старое название не совсем подходящее.

Taxonomy

  • #3039055 Удалён вызов drupal_static_reset('taxonomy_term_count_nodes'); так как данное значение никем не устанавливается.
  • #3056258 В форму добавления и редактирования термина таксономии добавлено новое действие «Сохранить и перейти к списку» — которое после сохранения материала перенаправит на страницу со всеми терминами словаря.
  • #3037157 Исправлена неполадка из-за которой переводы словаря игнорировались в заголовках страниц «entity.taxonomy_vocabulary.overview_form» и «entity.taxonomy_vocabulary.reset_form».
  • #3221149 Валидатор аргументов Views \Drupal\taxonomy\Plugin\views\argument_validator\Term помечен устаревшим. Вместо него используйте \Drupal\views\Plugin\views\argument_validator\Entity.
  • #2133215 Улучшена производительность плагина аргументов IndexTidDepth и плагина фильтра TaxonomyIndexTidDepth. Это на 98% сокращает время выполнения запроса!
  • #3229665 Исправлена неполадка в \Drupal\Tests\taxonomy\Functional\Views\TaxonomyTermFilterDepthTest которая могла приводить к непредсказуемым провалам тестирования.
  • #3229686 Произведены микро-оптимизации для тестов функциональных и Kernel тестов TaxonomyTermFilterDepthTest.

Text

  • #3067116 Функция text_summary() теперь корректно закрывает HTML теги когда используется фильтр filter_html.

Symfony 6

  • #3209617 Symfony\Component\HttpFoundation\RequestStack::getMasterRequest() помечен устаревшим, необходимо использовать ::getMainRequest(). Добавлен прокси-класс Drupal\Core\Http\RequestStack, который теперь возвращается сервисом request_stack.
  • #3231668 Добавлен тайпхинт Definition для Drupal\Core\DependencyInjection\ContainerBuilder::register().
  • #3231669 Добавлен тайпхинт Alias для Drupal\Core\DependencyInjection\ContainerBuilder::setAlias().
  • #3231672 Добавлен тайпхинт Definition для Drupal\Core\DependencyInjection\ContainerBuilder::setDefinition().
  • #3231676 Добавлены тайпхинты для Drupal\Core\TypedData\Validation\RecursiveValidator::inContext() и Drupal\Core\TypedData\Validation\RecursiveValidator::startContext().
  • #3209619 Передача NULL в качестве аргумента для исключения, помечено устаревшим. Там где передавался такой аргумент теперь передаётся пустая строка.

Umami demo

  • #3129666 В блоке брендирования для названия сайта больше не добавляется класс visually-hidden, который прятал заголовок даже если его необходимо показывать.
  • #3227513 QuickEdit удалён из установочного профиля Umami.
  • #3230554 Установщик демо-содержимого больше не использует сервис path_alias.manager.

Update

  • #3039074 drupal_static() больше не используется в функциях _update_manager_unique_identifier(), _update_manager_extract_directory() и _update_manager_cache_directory().
  • #3206293 Добавлен класс ProjectRelease, который является обёрткой для Update XML файла с релизами.
  • #2715145 Удалена конфигурация system.authorize.
  • #3180382 UpdateManagerUpdate.php больше не использует сервис renderer для элемента last_check.

User

  • #2819585 Исправлен дублирующий switch case в core/modules/user/user.js.
  • #2946 Теперь, при попытке авторизоваться с отключенными Cookies, будет показано соответствующее сообщение, что авторизация невозможна.
  • #3221258 Роль редактора присваивает только те права доступа, что доступны на момент установки.

Views

  • #2511892 Исправлена неполадка, приводящая к исключению MissingMandatoryParametersException при использовании вкладки меню и % в пути представления.
  • #2681947 Представления типа «Блок» теперь поддерживают настройку «Put the exposed form in a block».
  • #1551534 Views AJAX теперь поддерживают элемент <button> в качестве кнопки отправки, который может появиться в случае переопределения стандартного <input type="submit">.
  • #2560447 views_form_callback больше не поддерживается.

Workspaces

  • #3112783 Добавлены страницы для отображения изменений и их количества внесённых в рабочей области.

Тестирование

  • #3091870 Ошибки JavaScript выброшенные в FunctionalJavascript тестах теперь отлавливаются. Начиная с Drupal 10 они будут проваливать тесты.
  • #2758357 Добавлена документация о том, что core/phpunit.xml.dist должен быть скопирован в core/phpunit.xml для последующей модификации.
  • #3131900 Исправлены сравнения чьи результаты записываются в переменную.
  • #3196470 Доработан пустой тест KernelTestBaseTest::testOutboundHttpRequest().
  • #3226106 Из Drupal\Tests\node\Kernel\Migrate\d7\MigrateNodeTypeTest::assertEntity() удалён @dataProvider.
  • #3139409 Использование устаревшего AssertLegacyTrait::assertRaw() заменено на современные подходы.
  • #3227501 Удалены оставшиеся вызовы t().
  • #3130606 Использование MockBuilder::setMethods() заменено на современные аналоги, так как метод помечен устаревшим.

Прочие изменения

  • #3218968 Drupal теперь поддерживает NULL-сервисы. Например: Acme\Foo: ~.
  • #2902540 Исправлены ошибки стандарта кодирования Drupal.NamingConventions.ValidGlobal.
  • #1306624 Файл router_installer_test.install переименован router_installer_test.module.
  • #1884836 В DiffEngine вызовы md5() заменены на crc32b().
  • #2725435 Удалён устаревший @todo ведущий на #2364011.
  • #2830352 Обновлены ссылки ведущие на документацию Drupal 7.
  • #3127716 Исправлена опечатка в документации PathValidator.
  • #3228396 Актуализирована ссылка на ChromeDriver.
  • #3227386 Упрощен тест BaseThemeMissingTest.
  • #2639382 Исправлена неполадка из-за которой было невозможно перевести строки для некоторых относительных дат.
  • #3233015 Произведён рефакторинг \Drupal\Component\Utility\Random::image() чтобы не было уведомлений об устаревшем коде на PHP 8.1.
  • #3212498 Исправлены некорректные </br>.
  • #3224523 Для части методов добавлен аттрибут #[ReturnTypeWillChange].

🌱 Помогите нам сделать документацию лучше!

Вся документация Druki с отрытым исходным кодом. Нашли ошибку или неточность? Создайте pull request.

Редактировать текущий документ Обсудить улучшение

Или узнайте как контрибутить.

🤔 По-прежнему нужна помощь?

Не нашли ответа на свой вопрос? Попросите помощи у сообщества!

Задайте вопрос на GitHub Смотрите другие ресурсы сообщества