Содержание

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

Объект исключения теперь передаётся в контексте в логер

При логировании исключения теперь можно получить объект самого исключения из контекста $context['exception'].

Данное изменение соответствует PSR-3 а также позволит проще обрабатывать ошибки сторонними решениями, например Raven.

Передача StatementInterface объекта в Connection::query() помечена устаревшим

Передача объекта реализующего Drupal\Core\Database\StatementInterface в Drupal\Core\Database\Connection::query() помечена устаревшей и будет удалена в Drupal 10. Сейчас метод позволяет передавать только строковые значения для параметра $query.

Было:

  $db = \Drupal\Core\Database\Database::getConnection();
  $stmt = $db->prepareStatement('SELECT * FROM {test}', []);
  $result = $db->query($stmt);

Стало:

  $db = \Drupal\Core\Database\Database::getConnection();
  $result = $db->query('SELECT * FROM {test}');

Библиотеки jQuery UI помечены устаревшими

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

  • jquery.ui
  • jquery.ui.autocomplete
  • jquery.ui.dialog
  • jquery.ui.draggable
  • jquery.ui.menu
  • jquery.ui.mouse
  • jquery.ui.position
  • jquery.ui.resizable
  • jquery.ui.widget

Если ваши модули используют их, вам необходимо обновить зависимости и использовать для этого контрибные модули. Полный и актуальный список контрибных модулей для конкретных библиотек вы найдёте на странице проекта jQuery UI.

Библиотеки drupal.autocomplete, drupal.dialog и drupal.tabbingmanager продолжать иметь зависимости на jQuery UI JS и CSS файлы, но они явно прописаны в данных библиотеках, без использования устаревших.

Модули и темы переопределяющие или заменяющие данные библиотеки теперь должны производить нужные изменения непосредственно в библиотеках drupal.autocomplete, drupal.dialog и drupal.tabbingmanager.

Добавлено новое свойство 'bundle' для маршрутов entity:*

Настройки для маршрутов сущностей теперь принимают новое свойство bundle в качестве массива. При указании данного свойства, конвертация параметра для сущности будет ограничена указанными бандлами.

example.route:
  path: foo/{example}
  options:
    parameters:
      example:
        type: entity:node
        bundle:
          - article
          - news

В примере выше, параметр {example} будет конвертирован в ноду только если это нода типа «article» или «news».

В связи с этим, свойство маршрута _entity_bundles помечено устаревшим.

Благодаря данному изменения, при несоответствии типов, маршрут теперь будет отвечать HTTP 404 вместо HTTP 403.

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

Расширения (модули, темы оформления) больше не могут указывать свойство major в *.info.yml файлах.

Изменены сигнатуры конструкторов EntityFieldManager и EntityLastInstalledSchemaRepository

Конструктор класса Drupal\Core\Entity\EntityFieldManager теперь принимает новый параметр типа \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface. Для сохранения обратной совместимости параметр является опциональным, тем не менее, он станет обязательным в Drupal 10.

Конструктор класса Drupal\Core\Entity\EntityLastInstalledSchemaRepository теперь принимает новый параметр типа \Drupal\Core\Cache\CacheBackendInterface. Для сохранения обратной совместимости параметр является опциональным, тем не менее, он станет обязательным в Drupal 10.

Данное изменение также немного улучшает производительность сущностей, снижая количество запросов к БД.

Drupal теперь использует возможности PHP для генерации ID сессии

Drupal теперь использует встроенный в PHP механизм генерации ID сессии. Это означает что session_id() и \Drupal::service('session')->getId() не гарантируют что вернут одни и те же результаты, даже если сессия в Drupal инициализирована. Это вызвано тем что Drupal использует "ленивые сессии" - сессия будет инициализирована только в случае попытки записать туда значение.

Это также означает что Drupal теперь поддерживает следующие настройки PHP:

Идентификаторы сессии для анонимных пользователей

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

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

 if (!$session->has('core.tempstore.private.owner')) {
    // This generates a unique identifier for the user
    $session->set('core.tempstore.private.owner', Crypt::randomBytesBase64());
 }

SharedTempStore и SharedTempStoreFactory получили новые зависимости

В SharedTempStore теперь инжектится сервис current_user.

В SharedTempStoreFactory теперь инжектятся сервисы current_user и session.

ShareTempStoreFactory больше не использует ID сессии в качестве идентификатора анонимного пользователя. Он генерирует свой уникальный ID когда это требуется. Данное значение хранится в сессии под ключом core.tempstore.shared.owner.

Drupal\Core\Session\SessionManager::migrateStoredSession() удалён

Для того чтобы использовать встроенный в PHP генератор ID сессии был удалён метод Drupal\Core\Session\SessionManager::migrateStoredSession(). Замена не предоставляется, так как данный метод не был частью публичного API.

Собственные реализации SessionManagerInterface которые расширяют SessionManager должны быть обновлены чтобы не вызывать данный метод. Генерация сессии теперь производится при помощи вызова session_regenerate_id() который производится в \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage::regenerate().

Если имеются собственные реализации которые переопределяют метод ::migrateStoredSession(), то данный код может быть удалён после того, как минимальное требование модуля будет Drupal 9.2.0.

Код, использующий данный метод будет удалён, поэтому это не вызовет проблем. Если вам требуется мигрировать старую сессию в новую, вы по прежнему можете использовать \Drupal::service('session')->migrate();.

Все идентификаторы в запросах теперь должны быть обёрнуты в кавычки

Имена столбцов и синонимы таблиц должны быть обёрнуты квадратными кавычками ([]) при использовании Connection::query(), db_query(), ConditionInterface::where() или SelectInterface::addExpression(). Это позволит слою баз данных корректно оборачивать данные идентификаторы.

Например:

$connection->query('SELECT [nid] FROM {node} WHERE [nid] = :id', [':id' => '1']);

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

Запросы построенные при помощи Connection::select(), Connection::insert(), Connection::delete(), Connection::update(), Connection::upsert(), Connection::merge() не требуют добавлять квадратные скобки при вызовах ::fields() или ::condition(). Новый способ записи должен быть использовать при добавлении "сырого" SQL значения в объект при помощи ::addExpression(), ::where() или ::having().

Например:

// Обратите внимание, что это плохой пример, так как использование ::condition() было бы лучше.
$connection->select('node')->where('[nid] = :id', [':id' => '1']);

В крайне редких случаях запросам требуются квадратные скобки, например, при создании SQL функции. В таких ситуациях задайте параметр $option['allow_square_brackets'] равным TRUE.

Например:

$connection->query('CREATE OR REPLACE FUNCTION "substring_index"(text, text, integer) RETURNS text AS
  \'SELECT array_to_string((string_to_array($1, $2)) [1:$3], $2);\'
  LANGUAGE \'sql\'',
  [],
  ['allow_delimiter_in_query' => TRUE, 'allow_square_brackets' => TRUE]
);

Изменения в драйверах БД

Если вы являетесь автором или имеет свой собственный драйвер БД, вам необходимо задать значение свойству \Drupal\Core\Database\Connection::$identifierQuotes. Значение должно быть массивом из двух строк. Первое значение массива отвечает за символ начала цитаты, второе, его закрытие.

В Drupal 10 данное свойство станет обязательным. В Drupal 9, когда значение не задано, будут использованы пустые строки.

Проверьте все переопределения \Drupal\Core\Database\Connection::escapeDatabase(), \Drupal\Core\Database\Connection::escapeTable(), \Drupal\Core\Database\Connection::escapeField() и \Drupal\Core\Database\Connection::escapeAlias(). Скорее всего, они больше не потребуются.

Если драйвер использует \Drupal\Core\Database\Connection::$escapedNames, код должен быть обновлён с использованием либо \Drupal\Core\Database\Connection::$escapedTables, либо \Drupal\Core\Database\Connection::$escapedFields.

Изменения связанные с восстановлением пароля

В процесс восстановления пароля внесены некоторые изменения.

Восстановление пароля больше не раскрывает имя пользователя или что указанный email используется на сайте

Форма восстановления пароля больше не отображения сообщение, указывающее, что введенное имя пользователя или email не существуют.

Ранее

Если указанное имя пользователя или email не использовалось на сайте, выводилось следующее сообщение:

unknown@example.com is not recognized as a username or an email address.

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

Когда пользователь зарегистрирован и предоставлены корректные данные, выводилось следующее сообщение:

Further instructions have been sent to your email address.

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

После изменений

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

Если предоставлены некорректные имя пользователя (валидация на длину, допустимые символы и т.д.) или email, будет показано следующее сообщение:

The username or email address is invalid.

Если валидация на имя пользователя или email прошла успешно, будет показано следующее сообщение:

If [username or email] is a valid account, an email will be sent with instructions to reset your password.

Изменена сигнатура UserPasswordForm

Класс \Drupal\user\Form\UserPasswordForm теперь принимает два новых аргумента в конструкторе:

   * @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
   *   The typed data manager.
   * @param \Drupal\Component\Utility\EmailValidatorInterface $email_validator
   *   The email validator service.

Если ваш код инициализирует данный класс самостоятельно без использования метода ::create(), обновите свой код.

Данные параметры опциональны в Drupal 9 но станут обязательными в Drupal 10.

Добавлены хуки для изменения форм виджетов полей

Представлены новые хуки для редактирования форм используемые для настроек виджетов полей: hook_field_widget_complete_form_alter(), hook_field_widget_complete_WIDGET_TYPE_form_alter(), hook_field_widget_single_element_form_alter() и hook_field_widget_single_element_WIDGET_TYPE_form_alter().

Из-за введения новых хуков, следующие хуки помечены устаревшими: hook_field_widget_multiple_form_alter(), hook_field_widget_multiple_WIDGET_TYPE_form_alter(), hook_field_widget_form_alter() и hook_field_widget_WIDGET_TYPE_form_alter().

Добавлен новый хук hook_entity_form_mode_alter()

Представлен новый хук hook_entity_form_mode_alter() позволяющий модулям переопределять режим формы сущности.

Например, разные режимы формы сущности могут быть применены основываясь на роли пользователя:

function hook_entity_form_mode_alter(string &$form_mode, Drupal\Core\Entity\EntityInterface $entity): void {
  // Change the form mode for users with Administrator role.
  if ($entity->getEntityTypeId() == 'user' && $entity->hasRole('administrator')) {
    $form_mode = 'my_custom_form_mode';
  }
}

Аргумент $context удалён для hook_entity_view_mode_alter()

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

Ранее:

function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity, $context) {
  if ($entity->getEntityTypeId() == 'node' && $view_mode == 'teaser') {
    $view_mode = 'my_custom_view_mode';
  }
}

После изменения:

function hook_entity_view_mode_alter(&$view_mode, Drupal\Core\Entity\EntityInterface $entity) {
  if ($entity->getEntityTypeId() == 'node' && $view_mode == 'teaser') {
    $view_mode = 'my_custom_view_mode';
  }
}

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

Ранее, если пользователь или API клиент пытался загрузить файл с потенциально опасным расширением (например php, js), Drupal всегда переименовывал данные файлы добавляя .txt в конце. Это действие позволяло исключить исполнение данных файлов веб-сервером. Данное поведение также срабатывало на файловые поля которые настроены таким образом, что не разрешают загрузку .txt.

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

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

Более того, API клиенты (JSON:API, REST) возможно начнут отклонять подобные загрузки если они опираются на старое поведение и владельцы сайта решат не использовать новое поведение.

Drupal Migrate UI теперь правильно использует настройку приватной директории

При обновлении с Drupal 7 используя Migrate Drupal UI, пути для публичной и приватной файловой директории могли быть введены на странице /upgrade/credentials. Значение введённое для приватной директории игнорировалось, что приводило к ситуации когда публичная файловая система использовалась для миграции приватных файлов. Эта ошибка исправлена и теперь будет использоваться значение введенное в настройку приватного файлового пути.

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

Добавлен метод для чистки информации о БД в бэктрейсах

Добавлен новый статический метод Drupal\Core\Database\Log::removeDatabaseEntries() который принимает следующие аргументы:

  • $backtrace: Результат вызова debug_backtrace().
  • $driver_namespace: Пространство имён драйвера БД.

Данный метод удалит из бэктрейса всю информацию связанную с обращением к БД с использованием указанного драйвера.

Плагин Composer drupal/core-vendor-hardening теперь позволяет чистить пакеты за пределами vendor директории

Ранее, Composer плагин drupal/core-vendor-hardening подразумевал что все пакеты установленные через Composer находятся в vendor директории. Это поведение приводило к тому, что пакеты, установленные при помощи composer/installers не могли быть очищены данным плагином.

Начиная с данной версии, все пакеты установленные за пределами vendor директории с использованием composer/installers также могут быть очищены.

Расширения файлов теперь могут содержать нижнее подчёркивание

Добавлена возможность указывать расширения файлов содержащие нижнее подчёркивание (_).

Ранее:

  • Недопустимый формат:
    • example.x_t
    • example.x.t
    • example.x_y_t

Сейчас:

  • Допустимый формат:
    • example.x_t
    • example.x.t
    • example.x_y_t
  • Недопустимый формат:
    • example.x_.t
    • example.x._t
    • example.xt_
    • example.x__t
    • example._xt-

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

Создание сервисов без указания области видимости помечено устаревшим и не будет поддерживаться в Drupal 10.

В Symfony 5 все сервисы по умолчанию являются приватными, тогда как Drupal ожидает что сервисы по умолчанию публичные. Drupal 9 использует Symfony ^4.4, тогда как Drupal 10 будет использовать Symfony ^5.4.

Таким образом, все сервисы объявляемые в MODULE.services.yml становятся публичными по умолчанию (public: true), если не указано обратного.

Сервисы созданные программно, будут приватными по умолчанию:

$container = \Drupal::getContainer();
$definition = new Definition(RouteProvider::class);
$container->setDefinition($id, $definition);

Если вы хотите сохранить текущее поведение, обновите код и явно укажите что сервис публичный:

$container = \Drupal::getContainer();
$definition = new Definition(RouteProvider::class);
$definition->setPublic(TRUE);
$container->setDefinition($id, $definition);

Плагин обработчик MachineName теперь позволяет указывать регулярное выражение

Регулярное выражение используемое в плагине обработчике миграций MachineName теперь может быть настроено используя свойство replace_pattern.

Ранее использовалось конкретное регулярное выражение /[^a-z0-9_]+/.

process:
  foo:
    plugin: machine_name
    source: foo

Пример выше трансформировал бы значение the.bar в the_bar.

Теперь вы можете указать собственное регулярное выражение:

process:
  foo:
    plugin: machine_name
    source: foo
    replace_pattern: '/[^a-z0-9_.]+/'

Пример выше позволит получить в качестве результата the.bar.

GDToolkit теперь поддерживает WebP

PHP расширение GD поддерживает формат WebP начиная с версии 7.0.10.

Drupal ядро теперь может создавать изображения в данном формате.

Заметка

Для корректной работы, расширение GD должно быть скомпилировано с поддержкой WebP. Чтобы убедиться, что ваш сервер поддерживает данную возможность, обратитесь к странице информации о состоянии (admin/reports/status/php#module_gd).

README файл конвертирован в Markdown

Файл core/README.txt был конвертирован в Markdown формат и переименован в core/README.md. Этот формат более дружелюбен для новых контрибуторов. Информации об использовании Drupal, что раньше была в данном файле, выделена в новый файл core/USAGE.txt.

Если вы используете плагин drupal/core-composer-scaffold для исключения README.txt, возможно вы захотите обновить вашу конфигурацию для исключения новых файлов:

{
  ...
  "extra": {
    "drupal-scaffold": {
      "file-mapping": {
        "[web-root]/README.md": false,
        "[web-root]/USAGE.txt": false
      }
    }
  }
}

Проверка доступа _jsonapi_relationship_field_access помечена устаревшей

Класс Drupal\jsonapi\Access\RelationshipFieldAccess и связанная с ним проверка доступа _jsonapi_relationship_field_access помечены устаревшими и будут удалены в Drupal 10.

Замена не предоставляется. Проверка доступов к маршруту в JSON:API является внутренним API и не предназначен для использования за его пределами.

Добавлено событие для санитизации имён файлов

Drupal ядро теперь использует новое событие Drupal\Core\File\Event\FileUploadSanitizeNameEvent для санитизации имён файлов перед их сохранением. Есть у сущности есть файловое поле, событие будет вызвано из Form Widget, REST API или JSON:API.

Если код использует элемент формы file (\Drupal\Core\Render\Element\File) — реализация сохранения файла останется неизменной. В таком случае рекомендуется делать вызов file_save_upload() который вызовет новое событие и проведёт валидации для файла. Тем не менее, если кастомный или контрибный код вызывает file_munge_filename() и делает изменение имени в целях безопасности самостоятельно, то рекомендуется также вызывать новое событие или функцию file_save_upload().

Новое событие будет содержать в себе обработанное имя файла и метку, было ли оно изменено в целях безопасности.

Пример:

$event = new FileUploadSanitizeNameEvent($filename, $extensions);
\Drupal::service('event_dispatcher')->dispatch($event);

$sanitized_filename = $event->getFilename();
$is_security_rename = $event->isSecurityRename();

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

Drupal ядро добавляет свой подписчик (Drupal\system\EventSubscriber\SecurityFileUploadEventSubscriber) в качестве финального и повторяет логику функции file_munge_filename().

В связи с данным изменением, произведены следующие депрекации:

  • file_munge_filename() - заменён событием.
  • file_unmunge_filename() - замена не предоставлена.
  • FILE_INSECURE_EXTENSION_REGEX - заменена \Drupal\Core\File\FileSystemInterface::INSECURE_EXTENSION_REGEX.

Изменения связанные с pager.manager

  • #1202484

  • Добавлен новый метод PagerSelectExtender::getElement() позволяющий узнать ID пагинации используемой запросом, чтобы использующий его код не требовал необходимости переопределять его для будущих запросов.

  • Метод \Drupal\Core\Pager\PagerManagerInterface::getMaxPagerElementId(), позволяющий определять максимальный используемый Pager ID теперь является публичным.

  • Добавлен новый метод \Drupal\Core\Pager\PagerManagerInterface::reservePagerElementId() для резервации необходимого Pager ID.

  • Добавлен новый метод \Drupal\Core\Database\Connection::getPagerManager() для быстрого доступа к pager.manager из подключения к БД.

В Database API представлен новый класс - ExceptionHandler, Connection::handleQueryException - помечен устаревшим

Connection::handleQueryException — является protected методом и его невозможно вызывать, например, из классов отвечающих за конкретную операцию с БД.

В #3177660 было решено отказаться от использования Connection::query() для любых целей. В качестве замены было предложено подготавливать и вызывать Statement объекты в драйверах БД, а также обрабатывать исключения более последовательно.

Для это был создан класс ExceptionHandler, который необходимо использовать для обработки исключений связанных с драйвером БД.

В связи с данным изменением, Connection::handleQueryException помечен устаревшим.

Ранее:

    ...
    catch (\PDOException $e) {
      // Most database drivers will return NULL here, but some of them
      // (e.g. the SQLite driver) may need to re-run the query, so the return
      // value will be the same as for static::query().
      return $this->handleQueryException($e, $query, $args, $options);
    }

Сейчас:

    ...
    catch (\Exception $e) {
      // Most database drivers will return NULL here, but some of them
      // (e.g. the SQLite driver) may need to re-run the query, so the return
      // value will be the same as for static::query().
      ...
        return $this->exceptionHandler($e)->handleExecutionException($stmt, $args, $options);
      ...
    }

Добавлена JavaScript библиотека tabbable на замену jQuery UI tabbable

Drupal ядро находится на стадии удаления jQuery UI зависимостей. Ядро использовало одну из возможностей jQuery UI - возможность выборки элементов, которые доступны при помощи Tab в текущем контексте при помощи :tabbable селектора.

В ядро была добавлена JavaScript библиотека tabbable (core/tabbable), которая позволяет добиться того же результат без зависимости на jQuery UI.

Ранее:

const tabbableElements = $(context).find(':tabbable');  // returns a jQuery object with every tabbable element found in context.

Сейчас:

const tabbableElements = tabbable.tabbable(context);  // returns an array of DOM nodes of every tabbable element found in context.

Данная библиотека также имеет и другие возможности которые описаны в её документации.

Так как библиотека использует CSS.escape, а IE11 не поддерживает данную возможность, в ядро также был добавлен полифил библиотека CSS.escape (css.escape).

В ядро добавлена замена jQuery Once

Для того чтобы позволить JavaScript скриптам удалить зависимости на jQuery, возможность jQuery.once() была реализована на нативном JavaScript. Данная реализация дополнительно опубликована как npm пакет @drupal/once.

Новое в API

  • Объявлена новая библиотека core/once
  • Библиотека core/jquery.once помечена устаревшей
  • В новой библиотеке 4 функции:
    • once - эквивалент jQuery.fn.once
    • once.filter - эквивалент jQuery.fn.findOnce
    • once.remove - эквивалент jQuery.fn.removeOnce
    • once.find - новая функция, не имеющая аналога в jQuery

Изменения в коде

Ранее:

# 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('.myfeature').once('myfeature');
    }
  };
}(jQuery, Drupal));

Сейчас:

# 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', '.myfeature', context);
    }
  };
}(Drupal, once));

Для более подробной документации новой библиотеки смотрите @drupal/once.

Так как IE11 не поддерживает Element.prototype.matches, был добавлен полифил core/drupal.element.matches.

Добавлена новая AJAX команда NewFirstCommand

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

  • Если контейнер содержит хотя бы один «tabbable» элемент, первый что находится в контейнере и получит фокус.
  • Если внутри нет элементов или не найдено ни одного, на который можно установить фокусировку, будет предпринята попытка установить фокусировку на сам контейнер, если он поддерживает данную возможность.
  • Если фокусировка не может быть установлена на контейнер, она будет установлена на элемент, который вызвал AJAX запрос.

Например:

$response = new AjaxResponse();

// Первый фокусируемый элемент в элементе #some-new-form получит фокус.
$response->addCommand(new FocusFirstCommand('#some-new-form'));

Ранее, для того чтобы сделать то же самое, необходимо было вызывать InvokeCommand с использованием :tabbable псевдо-селектора в качестве аргумента. Это работало благодаря jQuery UI. Так как он выводится из оборота, была представлена эта замена. Теперь эта команда не требует зависимости jQuery.

Добавлен генератор стартовой темы

Важная информация

Перед релизом данную возможность удалили, так как сочли её незавершённой. Генератор будет доработан и добавлен в Drupal 9.3.0.

Для EntityQuery теперь нужно явно указывать проверку доступов

Метод \Drupal\Core\Entity\Query\QueryInterface::accessCheck() позволяет разработчикам указать, должны ли сущности из запроса проверяться на возможность просмотра текущим пользователям. Данное значение всегда должно быть указано при запросе. Тем не менее, все запросы поддерживают данный метод, но ядро реализует его только для контент-сущностей с SQL-хранилищем.

До Drupal 9.2, если ::accessCheck() не вызывался явно на запрос, то он принимал значение по умолчанию TRUE (проверять права доступа). Данное поведение приводит к множеству ошибок у разработчиков, так как об этом поведение легко забыть или вовсе не знать.

Таким образом, построение запроса при помощи EntityQuery без явного вызова ::accessCheck() помечено устаревшим. Все запросы данного типа должны явно указывать требование проверки прав доступа под свои нужды.

Ранее:

// This gets all articles the current user can view.
$ids = \Drupal::entityQuery('node')
  ->condition('type', 'article')
  ->execute();

// This also gets all articles the current user can view.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(TRUE)
  ->condition('type', 'article')
  ->execute();

// This gets all articles that exist regardless of access.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(FALSE)
  ->condition('type', 'article')
  ->execute();

Сейчас:

// This will trigger a deprecation error.
$ids = \Drupal::entityQuery('node')
  ->condition('type', 'article')
  ->execute();

// Unchanged: This gets all articles the current user can view.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(TRUE)
  ->condition('type', 'article')
  ->execute();

// Unchanged: This gets all articles that exist regardless of access.
$ids = \Drupal::entityQuery('node')
  ->accessCheck(FALSE)
  ->condition('type', 'article')
  ->execute();

Функции управления схемами предоставляемые schema.inc помечены устаревшими

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

  • drupal_install_schema()
  • drupal_uninstall_schema()
  • _drupal_schema_initialize()
  • drupal_get_module_schema()

Замены данным функцим не предоставляются, так какд данные функции были предназначены для внутреннего использования сервисом «установки».

Если ваши тесты используют drupal_get_module_schema() для получения информации о схемах теперь должны использовать статический хелпер:

use Drupal\TestTools\Extension\SchemaInspector;

$module_handler = $this->container->get('module_handler');
$specification = SchemaInspector::getTablesSpecification($module_handler, $module);
$schema = $specification[$table];

behat/mink-browserkit-driver заменён на friends-of-behat/mink-browserkit-driver

Зависимость behat/mink-browserkit-driver используется для функционального тестирования, но у неё нет поддержки PHP 8 и Symfony 5+, а также, отсутствует активность в более года.

Данный пакет был форкнут в friends-of-behat/mink-browserkit-driver где разработка была продолжена, была добавлена поддержка PHP 8 и Symfony 5+.

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

Ядро больше не использует jQuery UI position-min.js

Все библиотеки ядра, которые загружали assets/vendor/jquery.ui/ui/position-min.js, больше не используют его как зависимость. Вместо данного файла добавлена новая библиотека core/drupal.jquery.position. Данная библиотека использует misc/position.js. Файл является изменённой версией jQuery UI Position и имеет тот же функционал, отформатирован в формате Drupal Coding Styles и расширяет jQuery напрямую в обход jQuery UI.

Если вы используете или расширяете старый файл assets/vendor/jquery.ui/ui/position-min.js, вам необходимо теперь расширять или переопределять core/drupal.jquery.position.

Плагин обработчик миграций «Callback» теперь поддерживает множественные аргументы

Плагин callback является частью Migrate API, который позволяет применить PHP функцию или метод класса на этапе подготовки данных в процессе миграции. До 9.2.0 данный плагин был ограничен функцией и методами с одним аргументом.

Начиная с Drupal 9.2.0, плагин принимает необязательную настройку unpack_source.Когда данный параметр задан, значение для обработки должно быть массивом и будет интерпретировано как список аргументов.

До Drupal 9.2.0

process:
  destination_field:
    plugin: callback
    callable: mb_strtolower
    source: source_field

Функция mb_strtolower() принимает один аргумент.

Начиная с Drupal 9.2.0

Пример выше будет работать, как и ранее. С новой опцией unpack_source, плагин callback теперь может использовать функции с двумя и более аргументами, например как rtrim():

source:
  # plugin ...
  constants:
    slash: /
process:
  field_link_url:
    - plugin: callback
      callable: rtrim
      unpack_source: true
      source:
        - url
        - constants/slash

Функция rtrim() принимает два аргумента. В примере выше будут удаляться / в конце строки если такие имеются в URL.

Критические предупреждения безопасности теперь отображаются администраторам

Некоторые критические предупреждения безопасности (SA-) и публичные объявления (PSA-) будут отображаться на странице отчёта состояния сайта для пользователей с правом доступа administer site configuration.

Рекомендуется оставить данное поведение включённым по умолчанию, но если вы хотите отключить запросы для данных предупреждений в окружении, вы можете переопределить конфигурацию в settings.php:

$config['system.advisories']['enabled'] = FALSE;

Новое API

Добавлен новый сервис system.sa_fetcher который и будет отвечать за получение информации. Вы можете получить предупреждения следующим способом:

\Drupal::service('system.sa_fetcher')->getSecurityAdvisories();

Также добавлена новая конфигурация system.advisories с двумя настройками:

  • enabled: Логическое значение, определяющее, будет ли запрашиваться данная информация в процессе выполнения регулярных операций.
  • interval_hours: Значение в часах, как часто будет обновляться информация.

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

Получение данной информации отключено для функциональных тестов. Если тесту необходима данная информация, в таком случае необходимо убрать данную настройку путём переопределения \Drupal\Core\Test\FunctionalTestSetupTrait::writeSettings(). Например:

protected function writeSettings(array $settings): void {
  // Unset 'system.advisories' to allow testing enabling and disabling this
  // setting.
  unset($settings['config']['system.advisories']);
  parent::writeSettings($settings);
}

Тесты, которые включают данное поведение, отвечают за мокинг JSON ответа drupal.org с информацией о безопасности, для того чтобы избежать внешних HTTP запросов в процессе тестирования. Вы можете изучить тестовый модуль advisory_feed_test для того чтобы посмотреть, как делать подобные тесты.

Добавлен заголовок Permission-Policy для блокировки Google FLoC

Начиная с 9.2.0 к ответам будет добавляться новый заголовок Permissions-Policy: interest-cohort=(). Данный заголовок добавлен в связи с созданием Federated Learning of Cohorts (FLoC), что позволяет собирать информацию о пользователе без использования cookies, независимо от того, используются ли на сайте любые аналитические сервисы Google.

Для того управления данным заголовком добавлена новая настройка в settings.php block_interest_cohort. Если вы желаете отключить данный заголовок, задайте значение FALSE:

$settings['block_interest_cohort'] = FALSE;

jQuery Joyride заменён на ShepherdJS

Библиотека Joyride помечена устаревшей

Библиотека core/jquery.joyride помечена устаревшей, так как библиотека jQuery Joyride имеет слабую поддержку, не имеет релизов уже несколько лет и зависит от jQuery 3 что вносит неопределённости в будущую поддержку jQuery 4.

Tour модуль теперь использует новую библиотеку core/shepherd, которая подключает ShepherdJS.

Последствия замены библиотеки

Изменена разметка для подсказки
Заметка

Данные изменения не касаются тем расширяющих Stable или Stable 9. Данные темы предоставляют обратную совместимость.

Shepherd и jQuery Joyride рендерят подсказки по-разному. Для тем что не расширяют Stable или Stable 9, CSS стили были изменены, но не должны оказать серьезного влияния. Если одно из следующих верно для вашего проекта, вы можете заметить изменения:

  • Сайт предоставляет свои собственные стили для подсказок Tour модуля отличных от тех что предоставляет ядро.
  • Сайт использует Tip плагины отличные от тех что предоставляются ядром.

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

  • Произвести рефакторинг своих стилей для того чтобы они учитывали новую разметку.
  • Сделать так, чтобы тема сайта расширяла Stable или Stable 9, или скопируйте из них tour.js файл и загружайте его параллельно с библиотекой Tour. Если данный файл будет загружен на странице, то подсказки будут рендериться с разметкой идентичной jQuery Joyride.
Конфигурация Tour изменена
Заметка

Данное изменение не должно сказаться на «турах» хранимых в конфигурациях. Они будут обновлены в процессе обновления сайта.

Конфигурационные свойства туров location и attributes помечены устаревшими. Они были заменены на position и selector.

  • Использование свойства location должно быть заменено на position.
  • Использование data-class и data-id должны быть перенесены в selector. Например:
attributes:
  data-class: 'some-class'

необходимо заменить на

selector: '.some-class'
attributes:
  data-id: 'an-id'

необходимо заменить на

selector: '#an-id'
  • Все прочие использования attribute должны рассматриваться индивидуально и конкретные случаи.

Методы ::getOutput() и ::getAttributes() помечены устаревшими

Методы ::getOutput() и ::getAttributes() интерфейса \Drupal\tour\TipPluginInterface помечены устаревшими.

Для обновления собственных плагинов, вам необходимо реализовывать \Drupal\tour\TourTipPluginInterface. Существующий базовый класс \Drupal\tour\TipPluginBase предоставлет реализации для 2 из 3 новых методов. Третий новый метод — ::getBody() является заменой ::getOutput().

Ранее:

public function getOutput() {
  $output = '<h2 class="tour-tip-label" id="tour-tip-' . $this->getAriaId() . '-label">' . Html::escape($this->getLabel()) . '</h2>';
  $output .= '<p class="tour-tip-body" id="tour-tip-' . $this->getAriaId() . '-contents">' . $this->token->replace($this->getBody()) . '</p>';
  return ['#markup' => $output];
}

Сейчас:

public function getBody() {
  // The label is now handled by calling code.
  return [
    '#type' => 'html_tag',
    '#tag' => 'p',
    '#value' => $this->token->replace($this->get('body')),
    '#attributes' => [
      'class' => ['tour-tip-body'],
    ],
  ];
}

Функции для кодирования и декодирования Mime заголовков помечены устаревшими

Кодирование Mime заголовков в Drupal не соответствует RFC 2047.

С годами появились другие решения, которые справляются с этим лучше, включая некоторые встроенные функции PHP.

Как результат, класс Drupal\Component\Utility\Mail помечен устаревшим.

Ранее:

$headers['From'] = Mail::formatDisplayName('foo@example.com');

Сейчас:

use Symfony\Component\Mime\Header\MailboxHeader;

$mailbox = new MailboxHeader('From', new Address('foo@example.com'));
$headers['From'] = $mailbox->getBodyAsString();

Ранее:

$mail_subject = Unicode::mimeHeaderEncode($message['subject']);

Сейчас:

use Symfony\Component\Mime\Header\UnstructuredHeader;

$mail_subject = (new UnstructuredHeader('subject', $message['subject']))->getBodyAsString();

Ранее:

$decoded_string = Unicode::mimeHeaderDecode($encoded_string);

Сейчас:

$decoded_string = iconv_mime_decode($encoded_string);

Aggregator

  • #3178175 Модуль больше не требует наличия curl.

AJAX

  • #3179939 Удалён неиспользуемый AjaxTestBase.

Bartik

  • #2031447 Улучшена вёрстка для вывода «сеткой» при помощи Views.

Block Content

  • #3207405 На странице блоков содержимого добавлена кнопка сброса фильтрации.

Book

  • #2575827 BookNavigationBlock и BookNavigationCacheContext теперь получают информацию из route_match сервиса, вместо получения из аттрибутов запроса.
  • #2470896 Подшивки книг теперь переводимы. В связи с чем классы Drupal\book\BookExport, Drupal\book\BookBreadcrumbBuilder и Drupal\book\BookManager имеют новые зависимости.
  • #3188519 В конструкторе BookBreadcrumbBuilder исправлена ошибка в названии сервиса.

Cache System

  • #3209931 Сервисы cache_tags.invalidator.checksum и cache.backend.database теперь backend_overridable.

CKEditor

  • #3150364 Улучшена документация (/admin/help/ckeditor) для CKEditor.
  • #3211474 CKEditorLoadingTest::testExternalStylesheets() конвертирован в Kernel тест.
  • #3211599 CKeditor обновлён до версии 4.16.0.
  • #3215916 CKeditor обновлён до версии 4.17.0.
  • #3215929 CKeditor откачен до версии 4.16.1, чтобы соответствовать версиям обновлений для SA-CORE-2021-003.

Claro

  • #3083051 Произведён рефакторинг tabledrag для соответствия изменениям в ядре.
  • #3213557 Исправлено отображение чекбоксов в Layout Builder.
  • #3202493 Добавлена библиотека со стилями для административных страниц с CKEditor.
  • #3177415 Улучшено формирование CSS классов для вертикальных табов.

Comment

  • #2742997 CommentActionsTest конвертирован в Kernel тест.
  • #3214487 Для комментариев не использующих древовидный вывод, отключён вывод ссылки «Reply».

Composer

  • #3096781 Зависимости symfony/mime, symfony/var-dumper и symfony/phpunit-bridge обновлены до версии 5.2. Добавлена новая зависимость symfony/deprecation-contracts.
  • #3187025 Зависимости ядра обновлены на 08.12.2020.
  • #3206301 Зависимости ядра обновлены на 30.03.2021.
  • #3210632 Зависимости ядра обновлена на 17.05.2021.
  • #3215039 Зависимости ядра обновлена на 21.05.2021.
  • #3215280 Подняты минимальные версии для некоторых зависимостей ядра с которым возникали проблемы при тестировании.
  • #3217322 Зависимости ядра обновлена на 03.06.2021.

Configuration System

  • #3196756 Исправлена некорректное упоминание файла в документации ConfigInstallerInterface.
  • #2844452 Многострочные строки в YAML файлах теперь экспортируются без использования \r\n.
  • #3084436 Теперь при работе с единичной конфигурацией в административном интерфейсе, форма очищается после смены типа конфиграции чтобы не вводить в заблуждение.
  • #3217861 Улучшена документация для ConfigEntityDependency::getDependencies().

Contact

  • #3173756 Добавлена административная вкладка "Просмотр" для контактных форм.

Content Moderation

  • #3203809 Вызовы Entity Query в модуле больше не учитывают права доступа.
  • #3204883 Сущность taxonomy_term теперь корректно запрещена на использование в Content Moderation.
  • #2977495 Добавлены описания правам доступа модуля.

Cron System

  • #2863464 Логи крона теперь используют тип info вместо notice, для большего соответствия RFC 5424.

CSS

  • #3207680 Улучшено оформление списков для off-canvas модального окна.

Database System

  • #3129563 Сторонние драйвера БД теперь могут переопределять стандартные реализации расширителей запросов: Drupal\Core\Database\Query\PagerSelectExtender, Drupal\Core\Database\Query\TableSortExtender и Drupal\search\SearchQuery.
  • #3129534 Добавлены новые методы Drupal\Core\Database\Connection::getProvider() и Connection::enableModuleProvidingDatabaseDriver().
  • #3192951 Вызовы методов с передачей FQN класса ('Drupal\Core\Database\Query\PagerSelectExtender') заменены на константу (PagerSelectExtender::class).
  • #3089326 Методу Drupal\Core\Database\Log::log() добавлен новый опциональный параметр start.
  • #3186795 Drupal\Core\Database\StatementEmpty помечен устаревшим.
  • #3201266 Код, защищающий от множественных утверждений, который был частью Connection::query(), перенесён в защищённый метод ::preprocessStatement().
  • #3189680 Опция throw_exception помечена устаревшей.
  • #3211866 Upsert::execute() теперь всегда возвращает число.
  • #3216552 Исправлены некорректные вызовы Connection::select() в MenuTreeStorage.

Editor

  • #3181290 Удалён неиспользуемый код в editor.admin.es6.js.

Entity System

  • #3138631 Если поле содержит некорректную связь, сообщение об ошибке теперь будет более точно сообщать с чем связана проблема.
  • #3195628 CreateSampleEntityTest больше не устанавливает схему file сущности дважды.
  • #3196168 \Drupal\Core\Entity\EntityDeleteForm больше не помечен @internal.
  • #3159744 Из теста EntitySchemaTest удалены фиксированные ID.
  • #3201956 Удалена передача бесполезного аргумента в ConfigEntityStorage при вызове $this->mapFromStorageRecords().
  • #3201957 Удалено неиспользуемое свойство COnfigEntityStorage::$entities.
  • #3202963 Формы удаления bundle сущностей теперь показывают количество материалов, которые основаны на нём.
  • #3203147 Удалён решённый @todo из `EntityBundleListenerInterface.
  • #3207961 Добавлено явно указание проверки прав доступа при использовании EntityQuery в пропущенных местах.
  • #3210372 EntityConverter теперь дополнительно проверяет что переданный bundle существует.
  • #3214773 Исправлены тайпхинты для EntityRepositoryInterface::getActiveMultiple() и EntityRepositoryInterface::getCanonicalMultiple().
  • #3012172 В EntityViewBuilder::addContextualLinks() улучшена проверка на возможность создания ссылки для сущности.

Extension System

  • #3210900 Функция update_set_schema() помечена устаревшей.

Field System

  • #3203611 Исправлен тайпхинт для \Drupal\field\Entity\FieldConfig::loadByName.

File

  • #2479607 Удалены устаревшие схемы из file.file.views.schema.yml.
  • #3207476 file_get_content_headers() больше не кодирует заголовок Content-Type.
  • #3048423 Тест RelationshipUserFileDataTest конвертирован в Kernel тест.
  • #2359675 Исправлена неполадка, из-за которой проверка на максимально загружаемый размер файла всегда была положительной.

Filter

  • #3217732 Исправлена неполадка, из-за которой filterStatus() не мог найти разметку после AJAX.

Form System

  • #3122912 Вызовы t() заменены на $this->t().
  • #3205031 В Drupal\form_test\Form\FormTestVerticalTabsForm добавлен отсутствующий use.
  • #588438 Исправлена неполадка в тесте FormTest::testRequiredFields() которая приводила к ошибке при вызове drupal_render() с элементом radios.

HAL

  • #3210898 Часть тестов теперь расширяет NormalizerDenormalizeExceptionsUnitTestBase.

Help

  • #3090659 Добавлены Twig функции для установки ссылок на Help Topics: help_route_link() и help_topic_link().
  • #3087218 Улучшена скорость индексации справки.
  • #3209139 Добавлена функция-хелпер _help_topics_search_update().
  • #3213022 Теперь ссылка на несуществующий Help Topic указывает его ID.

Help Topics

  • #3090257 Добавлено больше тестов проверки синтаксиса.
  • #3095737 Справка для модулей config_translation, content_translation, locale и language конвертирована в Help Topics.

History

  • #3122056 Неопубликованные сущности более не учитываются в истории.

Install system

  • #3188654 Исправлены ссылка на загрузку переводов.
  • #3206168 Исправлен вызов install_display_output() с третьим аргументом.

JavaScript

  • #3191497 cpre/jquery.ui.dialog добавлена зависимость core/jquery.
  • #3211605 Библиотека Popper.js обновлена до версии 2.9.2.
  • #3211606 Библиотека Tabbable обновлена до версии 5.2.0.
  • #3211602 Библиотека jQuery Form обновлена до версии 4.3.0.
  • #3185165 Библиотека Modernizr обновлена до версии 3.11.7.
  • #3179734 jQuery селектор :tabbable помечен устаревшим.
  • #3191649 Библиотека Sortable обновлена до версии 1.13.0.
  • #3211601 Библиотека jQuery обновлена до версии 3.6.0.
  • #3210633 JavaScript зависимости ядра обновлены на 17.05.2021.
  • #3214412 Сборка и Prettier теперь запускаются после обновления при помощи Yarn.
  • #3144854 Удалена зависимость stylelint-no-browser-hacks.
  • #1870006 Улучшено отображение HTML5 ошибок валидации при наличии тулбара.
  • #3218658 Библиотека @drupal/once обновлена до версии 1.0.1.

JSON:API

  • #3163853 ResourceTestBase теперь использует ::assertEquals() вместо ::assertSame() для сравнения данных.

Layout Builder

  • #3180674 Удалён неиспользуемый модуль layout_builder_overrides_test.
  • #3115503 \Drupal\Core\Layout\LayoutInterface теперь расширяет \Drupal\Core\Plugin\ContextAwarePluginInterface. Это означает что Layout плагины теперь контекстно-зависимые.

Locale

  • #3184527 \Drupal\locale\LocaleLookup::getCid() больше не учитывает пользовательские роли.

Media

  • #3085264 Объединены тесты media_test_filter и media_test_ckeditor.
  • #3134554 Исправлена неполадка при которой медиа-поля с Media library виджетом приводили к «Notice: Undefined index».
  • #3215198 Обновление информации о ширине и высоте для медиа сущностей с поддержкой данных параметров, теперь загружают информацию о файлу только когда данные параметры обновляются.

MySQL DB Driver

  • #3185231 Режим SQL при инициализации теперь задаётся через ANSI,TRADITIONAL вместо перечисления всех возможных значений.
  • #3210888 Удалён метод Drupal\Core\Database\Connection::serialize().

Migration System

  • #2939328 Внесены улучшения в подсказки для Drupal Migrate UI.
  • #3151363 Исправлена подготовка пути до источника. Теперь она будет без двойных // слэшей.
  • #3184545 Для Migration::getMigrationPluginManager() исправлена документация о возвращаемом типе.
  • #2920168 Удалён метод SqlBaseTest::getHighWaterStorage().
  • #3047328 Обработчик Log теперь может логгировать различные типы данных, а не только строки.
  • #3148959 Обработчик Extract теперь отображает при обработке какого значение произошла ошибка.
  • #3187477 Их источника TermTranslation удалено подключение трейта I18nQueryTrait.
  • #2937989 Источник данных Node для Drupal 6 и Drupal 7 теперь может принимать сразу несколько типов содержимого в качестве источника.
  • #3189878 Из плагина источника данных Drupal 7 File удалено свойство temporaryPath.
  • #3189064 Для плагинов источников данных расширяющих SqlBase зависимость database больше не сериализуется.
  • #3187263 Миграции для конфигурационных блоков d6_block_translation и d7_block_translation теперь запрашивают config_translation вместо content_translation.
  • #3194385 Тест для d6 миграций MigrateUserPictureFileTest объединён в MigrateUserPictureD6FileTest.
  • #3190504 Исправлена документация к плагинам источников нод.
  • #2814953 Добавлены миграции для полей связи с node и user из Drupal 7.
  • #3192900 Некоторые Kernel тесты были объединены.
  • #3005969 Добавлена поддержка миграций типа поля telephone из Drupal 7.
  • #3189054 Удалена пометка, что MigrateException может быть вызвано конструктором MigrateExecutable, так как оно там не вызывается.
  • #3200735 Добавлена документация для плагинов источников Drupal 6 и Drupal 7 user, profile и roles.
  • #3175953 Произведена чистка в функциональных тестах.
  • #3191990 Произведён небольшой рефакторинг кода в DrupalSqlBaseTest.
  • #3205029 Из DestinationCategoryTest удалены референсы на несуществующие классы.
  • #3051252 Добавлены миграции для модулей multiupload_filefield_widget и `multiupload_imagefield_widget'.
  • #3206932 Константа targetEntityType из d6/ViewMode плагина переименована в entity_type.
  • #2974128 Добавлен отсутствующий параметр no_stub: false для плагина обработчика DefaultValue.
  • #3213638 Исправлено некорректное описание для Drupal\Plugin\Migration.
  • #3193189 Плагин источник d6_taxonomy_term_localized_migration теперь загружает только те термины, что используют словарь с переводами.
  • #3191782 Исправлены зависимости для миграций переводов профилей из Drupal 6.
  • #3204461 Исправлена ошибка связанная с sort() в ValidateMigrationStateTestTrait.
  • #3189463 Все миграция связанные с переводами и локализацией теперь зависят от миграции language.
  • #3213616 Добавлены соотношения для полей модуля Datetime из D6 и D7.
  • #3187318 Миграция пользователей из прошлых версий Drupal больше не мигрирует пользователя с UID = 0.

Node System

  • #3187435 Для Views плагина Vid, аргумент $database помечен устаревшим.
  • #3218024 Вызов $node->link заменён на $node->toUrl().

Olivero

  • #3187884 Удален лишний условный оператор из block--system-branding-block.html.twig.
  • #3180281 Максимальная длина описания для элементов форм задана в 60 символов.
  • #3173007 Внесены изменения в разметку и comments.pcss.css для соответствия БЭМ методологии.
  • #3176893 Внесены изменения в разметку и book.pcss.css для соответствия БЭМ методологии.
  • #3173014 Внесены изменения в разметку и стили элементов навигации для соответствия БЭМ методологии.
  • #3153260 Стандартизовано оформление :focus псевдо-элемента среди различных элементов.
  • #3194350 Реализовано новое оформление для элементов форм.
  • #3200595 Исправлено outline оформление для кнопки мобильного меню.
  • #3200631 Исправлено отображения <select> элемента в jQuery UI dialog на Safari.
  • #3191716 Открытие вложенных пунктов меню на мобильной версии теперь требует всего 1 тап для открытия, а не 2 как было ранее.
  • #3192656 Исправлена неполадка с текстовыми элементами формы приводящая к появлению горизонтальной прокрутки.
  • #3190268 Полифилы поставляемые с темой, заменены на библиотеки с аналогичными полифилами из ядра.
  • #3192903 Mouseout событие при наличии активного фокуса на вложенном меню, больше не закрывает его.
  • #3205434 Добавлены Nigthwatch тесты.
  • #3206948 Для элемента input[type="color"] убраны отступы и увеличена ширина для корректного отображения.
  • #3207032 Исправлено отображение кнопки «Назад» в IE11.
  • #3173900 JavaScript темы теперь использует новый Drupal JavaScript Once API
  • #3186349 Исправлены множественные проблемы доступности для функционала показа \ скрытия шапки.
  • #3191077 Исправлена неполадка с мобильным меню, которое позволяло производить навигацию при помощи «TAB» только в одну сторону.
  • #3208286 Исправлено название переменной с topLevelMenuITem на topLevelMenuItem в файле second-level-navigation.es6.js.
  • #3208116 Исправлено «мерцание» мобильного меню на Safari.
  • #3206290 Исправлено отображение иконки поиска в режиме повышенной контрастности Windows.
  • #3207996 Из text-content.pcss.css удалено свойство text-decoration-width.
  • #3200599 Улучшены стили для подвала и удалены не используемые.
  • #3210130 Форма комментариев теперь растягивается на всю ширину для мобильных устройств.
  • #3191692 Второстепенные меню теперь закрывают при потере фокуса.
  • #3210329 Исправлено значение для aria-checked для sticky-header-toggle в момент загрузки страницы.
  • #3173016 Улучшены стили и разметка для node.html.twig для их универсальности.
  • #3209125 Форма поиска теперь закрывается при нажатии Esc.
  • #3208114 Исправлена неполадка для Safari из-за которой надпись «Menu» становилась белой.
  • #3196874 Разметка для пагинации книг «БЭМифицирована».
  • #3182200 Разметка второстепенного меню теперь соответствует БЭМ.
  • #3200644 Для элемента автодополнения добавлено оформление отключенного состояния.
  • #3211888 Исправлены отображение сетки 33/34/33 на IE 11.
  • #3212281 Удален лишний отступ в списках для CKEditor.
  • #3153265 Исправлена неполадка из-за которой ссылка «Перейти к содержимому» при фокусе приводила к смещению макета.
  • #3211897 Исправлена неполадка из-за которой меню в мобильной версии могло закрываться при скроле.
  • #3191725 Улучшены стили для таблиц с сортировкой.
  • #3190120 Второстепенное меню теперь всегда в фокусе при навигации с использованием клавиатуры.
  • #3212998 Улучшены селекторы для элементов JavaScript.
  • #3212704 Исправлено отображение содержимого под макетом 33/33/33 в IE 11.
  • #3208000 Удалён временный шаблон toolbar.html.twig.
  • #3210443 Теперь после закрытия выпадающего меню при помощи «Esc» фокус возвращается на переключатель данного меню.
  • #3173012 Внесены корректировки в header-search-side.pcss.css и header-search-narrow.pcss.css.
  • #3200628 Исправлено выравнивание текста лдя маленьких кнопок.
  • #3214140 Иконка закрытия системного сообщения больше не имеет border-radius.

Plugin System

  • #3046342 Для ContextAwarePluginInterface исправлена документация связанная с @throws.

PostgreSQL DB Driver

  • #3185399 Для определения предыдущего ID теперь используется RETURNING.

Render System

Responsive Image

Routing system

  • #3191061 Из \Drupal\Core\Routing\RequestContext удалён @todo.
  • #3209453 Сервис search.index теперь backend_overridable.

System

  • #2409413 Удалены неиспользуемые RSS настройки и описания.
  • #3002983 Протокол в ссылках заменён на HTTPS.
  • #3174832 Исправлена документация для admin-block-content.html.twig.
  • #3204220 Drupal\system\ModuleDependencyMessageTrait теперь Drupal\Core\Extension\ModuleDependencyMessageTrait.
  • #3211480 Drupal\Tests\system\Functional\Common\UrlTest конвертирован в Kernel тест.
  • #3163487 Улучшена документация для свойств \Drupal\Core\Link.

Taxonomy

  • #3170185 Drupal\taxonomy\Form\OverviewTerms теперь использует pager.manager для получения текущей страницы вместо Request.
  • #3207477 Хранилище Taxonomy Term теперь явно вызывает ::accessCheck() для EntityQuery.
  • #2998826 Добавлен контекст для предоставления сущности Taxonomy Term из маршрута taxonomy_term.taxonomy_term_route_context.

Theme System

  • #3181367 Аргумент LoaderInterface $loader для TwigEnvironment::__construct() теперь всегда должен иметь значение.

Toolbar

  • #3174422 Для тулбара добавлен класс clearfix.

Transliteration System

  • #3025727 В данным для тестирования PhpTransliterationTest добавлены описания что именно за данные тестируются.

Umami Demo

  • #3051465 Поле тегов для материалов теперь не переводимое и не создаёт автоматически несуществующие теги.
  • #3066570 Роль редактора теперь имеет больше прав, в связи с чем может: управлять переводами, изучать страницы "помощи", просматривать таксономию, управлять ярлыками.
  • #3061267 Машинные имена блоков теперь имеют префикс равный машинному имени темы оформления.
  • #3108503 Теперь Layout Builder по умолчанию включен для всех типов содержимого.
  • #2938803 Убрано предупреждение о том что Umami демонстрационный профиль при выборе установочного профиля, так как это указано в его названии и описании.

Update

  • #2577407 Установка нового модуля через интерфейс теперь имеет постоянный лейбл «Add».

User

  • #3186752 Аргумент $langcode для функции _user_mail_notify() помечен устаревшим.
  • #3206358 Удалена инициализации $bag в SessionManager.
  • #2799049 Добавлено новое разрешение view user email addresses позволяющее пользователям с данным доступом просматривать email адреса пользователей. На данный момент email адреса могут просматривать исключительно администраторы.
  • #3212034 Добавлены переносы на новые строки в email письмах для пользователей.

Views

  • #2628130 Параметр $database для \Drupal\node\Plugin\views\argument\Vid помечен устаревшим.
  • #2925612 Метод StylePluginBase::wizardForm() помечен устаревшим, так как нигде не используется.
  • #3186582 Отображение по умолчанию во Views теперь именуется как «Default».
  • #3197886 Класс ViewsPluginAnnotationBase больше не реализуется AnnotationInterface.
  • #2342807 DisplayPathTest больше не пытается включить модуль menu_ui, который уже включен к тому моменту.
  • #3202052 Плагин аргументов Views теперь явно вызывает ::accessCheck() в ::titleQuery().
  • #3109110 Плагин кеширования \Drupal\views\Plugin\views\cache\Time и все расширяющие его плагины теперь должны использовать $this->view->getRequest(). Объект запроса больше не передаётся в качестве аргумента.
  • #2716019 для формирования заголовка представления на основе пути, теперь используется функция обратного вызова Drupal\views\Routing\ViewPageController::getTitle().

Workspaces

  • #3128536 Свойство WorkspaceManager::$blacklist переименовано в $supported.
  • #2998454 Употребление терминов «deploy» и «publish» приведено в порядок для избежания путаницы.
  • #3092553 В список рабочих областей добавлена возможность переключиться на «Live» версию.

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

  • #3176655 GoutteDriver помечен устаревшим, вместо него ядро теперь использует BrowserKitDriver.
  • #3132887 BrowserTestBase::drupalGetHeader() помечен устаревшим. Используйте $this->getSession()->getResponseHeader().
  • #3181329 Удалён метод BrowserTestBase::getResponseLogHandler() так как он дублирует BrowserHtmlDebugTrait::getResponseLogHandler().
  • #3184632 Сравнения для submit инпутов с использованием xpath заменены на WebAssert.
  • #3139431 Вызовы устаревшего AssertLegacyTrait::assertFieldsByValue() заменены на современные аналоги.
  • #3132919 Вызовы ::assert*() со сравнением в качестве ожидаемого значения заменены на ::assertNot*().
  • #3191986 Вызовы устаревшего AssertLegacyTrait::assertNotIdentical() заменены на современные аналоги.
  • #3169171 Исправлены сообщения о депрекации.
  • #3178248 Удалён метод StandardInstallerTest::curlExec(), так как нигде не используется.
  • #2795567 Для тестов Unit*, Kernel* и BrowserTests добавлена глобальная функция dump() которая использует Symfony VarDumper.
  • #3193163 Использование AssertLegacyTrait::verbose() помечено устаревшим.
  • #3187949 Метод ::cssSelectToXpath() перенесён из BrowserTestBase в UiHelperTrait.
  • #3187113 Удалены вызовы t() в ::submitForm().
  • #3205139 Удалён ModuleTestBase::assertTableCount().
  • #2189411 Из FunctionalTestSetupTrait удалена пересборка контейнера.
  • #3204002 Из TestServiceProvider удалён мёртвый код связанный с SimpleTest.
  • #3132778 Использование strstr() заменено на ::assertStringContainsString() и ::assertStringNotCOntainsString().
  • #3176361 Из JavaScript условий удалены точки с запятой.
  • #3211838 Сравнения с использованием xpath на span заменены на WebAssert.
  • #3133162 Употребление глагола «Test» заменено на «Tests».
  • #3217709 Использование ::assertRegExp() заменено на новые методы, так как данный помечен устаревшим.
  • #3217712 Использование ::assertDirectoryNotIsWritable() заменено на новые методы, так как данный помечен устаревшим.
  • #3174200 В ядро добавлен Symfony PHPUnit-Bridge polyfills.
  • #3217711 Использование ::assertNotRegExp() заменено на новые методы, так как данный помечен устаревшим.
  • #3217713 Использование ::assertFileNotIsWritable() заменено на новые методы, так как данный помечен устаревшим.
  • #3217716 Использование ::expectException(Error::class) заменено на новые методы, так как данный помечен устаревшим.
  • #3217714 Использование ::expectException(Warning::class) заменено на новые методы, так как данный помечен устаревшим.
  • #3218586 Улучшен тест ConfigTest::testSetIllegalOffsetValue() где забыли заменить ::expectException().
  • #3217706 Использование ::assertFileNotExists() заменено на новые методы, так как данный помечен устаревшим.

Symfony 5

  • #3188056 Обновлён код, который вызывал сериалайзер Symfony с NULL в качестве формата.
  • #3185603 Добавлен ConstraintFactory для инициализации констрейн плагинов Drupal.
  • #3209239 FileUploadSanitizeNameEvent::stopPropagation() добавлен тайпхинт возвращаемому значению (void).
  • #3213295 Компоненты Symfony 5 обновлены до 5.3-rc1.
  • #3216088 Компоненты Symfony 5 обновлены до 5.3.

Symfony 6

  • #3195533 Константа Symfony\Component\HttpFoundation\Request::HEADER_X_FORWARDED_ALL помечена устаревшей. Используйте либо HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO, либо HEADER_X_FORWARDED_AWS_ELB, либо HEADER_X_FORWARDED_TRAEFIK.
  • #3161983 Код ядра обновлён для соответствия новому EventDispatcher. Смотрите Drupal 9.1.0 для более подробных изменений.
  • #3187857 Сообщения об устаревшем коде больше не будут приводить к предупреждению об изменении сигнатуры методов ::setDeprecated().
  • #3199691 Временно отключено тестирование octal типа в YAML файлах, так как в спецификации YAML 1.2, который используется Symfony начиная с версии 5.1, поменялся его формат с 0777 на 0o777.
  • #3209482 Тайпхинты EventDispatcherInterface обновлены для FileUploadResource.
  • #3209618 Метод Symfony\Component\HttpKernel\Event\KernelEvent::isMasterRequest() помечен устаревшим. Так как в Drupal 10 планируется использовать Symfony 6, данный метод заранее помечен устаревшим. В качестве замены используйте Symfony\Component\HttpKernel\Event\KernelEvent::isMainRequest().
  • #3215830 KernelEvent теперь использует Drupal\Component\EventDispatcher\Event вместо Symfony\Component\EventDispatcher\Event.

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

  • #3173636 В PagerManager добавлена реализация PagerManagerInterface::findPage().
  • #3181084 Из web.config удалены комментарии для правила httpoxy.
  • #3180998 Удалён код для поддержки старых версий PHP ниже 7.3.
  • #3164676 Из словаря cspell удалены слова с ошибками, фикстуры для тестов добавлены в список игнорируемых файлов.
  • #3187489 Sally Young (justafish) и Théodore Biadala (nod_) добавлены в список мейнтенеров ядра.
  • #3178135 favicon.ico из /core/misc обновлён для соответствия новому логотипу Drupal.
  • #3185652 Исправлены множественные ошибки для соответствия стандарту Drupal.Commenting.DocComment.ShortFullStop.
  • #3183656 Исправлены множественные ошибки для соответствия стандарту Drupal.Commenting.DocComment.TagGroupSpacing.
  • #3185614 Исправлена опечатка в «The users's account name».
  • #3170260 В MAINTAINERS.txt добавлен раздел для инициативы Decoupled Menus.
  • #3188920 Guzzle исключения обновления для совместимости с Guzzle 7.
  • #3147135 Исправлены множественные ошибки для соответствия стандарту Drupal.Classes.UseGlobalClass.
  • #3189466 Francesco Placella (plach) снял с себя полномочия мейнтейнера ядра.
  • #3162827 В модулях ядра, где использование хранилища сущности является опциональным, данные хранилища запрашиваются только в данной ситуации. Следовательно, в классах теперь хранится entityStorage, вместо хранилища конкретной сущности.
  • #3162822 Исправлены проблемы со словами включающие "reference" и CSPell.
  • #3193381 Удалена информация о Workspace инициативе. Инициатива теперь является часть "инициатив сообщества".
  • #3195571 Константа Drupal\Core\Routing\RouteCompiler::REGEX_DELIMITER помечена устаревшей.
  • #2002514 Функция debug() помечена устаревшей. Удалены все упоминания для _drupal_debug_message(). Используйте dump().
  • #3191487 Из MAINTAINERS.txt удалён раздел с "Layout Initiative", так как она считается завершённое. Все последющие изменения связанные с макетами будут классифицироваться под инициативой "Easy out of the box".
  • #2723621 Исправлены ошибки для соответствия стандартам Drupal.Commenting.FunctionComment.IncorrectTypeHint и Drupal.Commenting.FunctionComment.InvalidTypeHint.
  • #3188957 В DrupalTestBrowser теперь используется RequestException::hasResponse().
  • #2510438 Удалён индекс all для таблицы key_value_expire.
  • #3185653 Удалены упоминания ::drupalPostAjaxForm(), который был удалён в Drupal 9.
  • #3200213 Добавлена документация для сервиса session_bag.
  • #3202014 pager_test_preprocess_pager() теперь использует early return если пейджер не найден.
  • #3202787 Исправлены ссылка в документации к FunctionalTestSetupTrait::setContainerParameter().
  • #2508071 Добавлено объявление свойства KeyValueFactory::$options.
  • #2711739 Добавлена отсутствующая документация для методов QueryInterface.
  • #1923816 Исправлены примеры для QueryAggregateInterface.
  • #3186626 Удалена поддержка параметра $proxy_class_name для метода ProxyBuilder::build(), так как он не используется.
  • #3198594 Добавлен класс Drupal\Core\Http\InputBag для предоставления моста между Symfony 4 и 5, только для внутреннего пользования.
  • #2903911 Исправлены ошибки стандарта кодирования Drupal.Commenting.FunctionComment.ParamMissingDefinition.
  • #2160091 drupal_flush_all_caches() больше не сбрасывает контейнер дважды. Данная функция теперь получает параметр $kernel, если он не передан, или не является экземпляром DrupalKernel, то будет сброшен кеш контейнера. При наличии данного аргумента, ответственность за сброс кеша контейнера ложится на того, кто вызвал данную функцию.
  • #2937858 Исправлены ошибки для соответствия стандарту Drupal.Commenting.DocCommentAlignment.
  • #3207119 Исправлены ошибки для соответствия стандарту Squiz.WhiteSpace.ScopeKeywordSpacing.
  • #2829453 Из \Drupal удалён docblock c @file.
  • #3208266 Запросы в функциях workspaces_install() и demo_umami_set_users_passwords() больше не учитывают права доступа.
  • #3165364 Проверка правописания отключена для файла LICENSE.txt.
  • #2732113 Улучшена документация в dblog_help().
  • #2937882 Исправлены ошибки для соответствия стандарту Drupal.Classes.PropertyDeclaration.
  • #2902548 Исправлены ошибки для соответствия стандарту Drupal.Semantics.RemoteAddress.
  • #3207456 Добавлена явная зависимость на symfony/mime.
  • #3212547 Удалены исправленные слова из словаря CSPell.
  • #2909369 Исправлены ошибки для соответствия стандарту Drupal.VariableComment.WrongStyle.
  • #3123070 Исправлены ошибки для соответствия стандарту PSR2.Classes.PropertyDelcaration.Underscore.
  • #3214234 Добавлен новый файл core/class_aliases.php. Данный файл также добавлен в автозагрузчик Composer.
  • #3214308 Удалён файл core/class_aliases.php, а его содержимое перенесено в bootstrap.inc. 🤭
  • #2969190 Улучшена документация метода ModuleInstallerInterface::uninstall().
  • #3207968 Комментарии с использованием @codingStandardsIgnoreFile заменены на phpcs:ignoreFile.
  • #3214920 Рекомендуемая версия PHP увеличена до 7.4.
  • #3109767 Улучшена генерация демонстрационных данных для типов полей string и link.
  • #3195888 Улучшена проверка зависимостей в core/scripts/dev/commit-code-check.sh.
  • #3186364 Для предварительных релизов Drupal разрешено использовать предварительные релизы зависимостей.
  • #3214565 Улучшен код в тесте BuildTestTest::testPortMany() приводящий к случайным провалам.
  • #3116804 Для Update Manager добавлены мейнтейнеры tedbow и dww.
  • #3218139 Упрощена логика добавления Permissions-Policy заголовка в ответ.
  • #3215611 Сообщение об устаревших сервисах теперь вызывается только в процессе сборки контейнера, а не на каждый их вызов.
  • #3217357 Ссылки ведущие на материалы по Drupal 8 теперь ведут на актуальные.
  • #3064596 DateTimePlus::createFromFormat() больше не занимается форматированием даты так как возвращает объект DateTime.
  • #3214395 В документацию hook_uninstall() добавлена подсказка о \Drupal\Core\Extension\ModuleUninstallValidatorInterface.

Ссылки

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

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

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

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

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

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

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