#drupal #drupal-8 #drupal-9
Вопрос:
Мы внедряем обновление внутреннего профиля установки Drupal, и один из часто используемых путей меню меняется. Большинство наших установок ссылаются на этот путь к меню в ярлыке (через модуль «Ярлык» в ядре). В крючке обновления мы хотели бы иметь возможность запрашивать эти ярлыки и обновлять их.
Кажется, что это должно быть просто, но по какой-то причине нам трудно запрашивать ярлыки по их URL-адресу. Мы можем запросить их по названию, но это кажется хрупким (поскольку название может отличаться в разных установках, может отличаться в зависимости от локализации и т. Д.).
Мы попытались сделать следующее, но это привело к появлению сообщения об ошибке 'link' not found
:
// This does NOT work.
$shortcuts_needing_update =
Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link' => [
'internal:/admin/timeline-management',
],
]);
// This works, but is fragile.
$shortcuts_needing_update =
Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'title' => 'My shortcut',
]);
Основываясь на коде, DrupalshortcutEntityShortcut::baseFieldDefinitions()
и DrupalshortcutControllerShortcutSetController::addShortcutLinkInline()
очевидно, что у сущностей ярлыков есть свойство, link
которое можно задать как массив, содержащий uri
ключ, но, похоже, невозможно выполнить запрос с помощью этого свойства, даже если это базовое поле.
Ответ №1:
Глядя на базу данных, кажется, что Drupal хранит URL-адрес в столбце базы данных под названием link__uri
:
TL;DR Это означает, что это работает:
$shortcuts_needing_update =
Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link__uri' => 'internal:/admin/old/path',
]
);
Читайте дальше, если хотите узнать тонкую причину, по которой это так.
Уровень базы данных Drupal использует подключаемые объекты «сопоставление таблиц», чтобы указать, как сопоставить объект (например, ярлык) с одной или несколькими таблицами базы данных и столбцами таблиц базы данных. Логика создания имени столбца для поля выглядит следующим образом в сопоставлении таблиц по умолчанию ( DrupalCoreEntitySqlDefaultTableMapping
):
Как показано выше, если поле указывает, что оно позволяет хранить «общую» таблицу, и поле имеет несколько свойств ( uri
title
, и т.д.), То сопоставление сглаживает поле в отдельные столбцы для каждого свойства с префиксом имени поля. Таким образом, объект ярлыка с link => ['uri' => 'xyz']]
становится столбцом link__uri
со значением xyz
в базе данных.
Вы не часто видите это с такими объектами, как узлы, поэтому здесь это кажется странным. Обычно я привык видеть отдельную таблицу базы данных для таких вещей, как поля ссылок. Это связано с тем, что узлы и другие объекты контента обычно не разрешают совместное хранение таблиц для своих полей.
Как сопоставление определяет, должно ли поле использовать общее хранилище таблиц? Эта логика выглядит так:
Таким образом, сопоставление таблиц по умолчанию будет использовать общее хранилище таблиц для поля только при определенных обстоятельствах:
- У поля не может быть пользовательского обработчика хранилища (проверьте здесь, так как ярлыки не предоставляют свою собственную логику хранения).
- Поле должно быть базовым полем (ярлыки-ничто без ссылки, поэтому это поле определяется как базовое поле, как указано в ОП).
- Поле должно быть однозначным (проверяет-ярлыки имеют только одну ссылку).
- Поле не должно быть удалено (проверяется; опять же, что такое ярлык без поля ссылки?).
Этот конкретный набор обстоятельств не часто удовлетворяется узлами или другими объектами контента, поэтому здесь это немного удивительно.
Мы можем подтвердить это, используя PHP разработки, чтобы напрямую запросить у сопоставления таблиц ярлыки, используя код, подобный следующему:
$shortcut_table_mapping =
Drupal::entityTypeManager()
->getStorage('shortcut')
->getTableMapping();
$efm = Drupal::service('entity_field.manager');
$storage_definitions = $efm->getFieldStorageDefinitions('shortcut');
$link_storage_definition = $storage_definitions['link'];
$has_dedicated_storage = $shortcut_table_mapping->requiresDedicatedTableStorage($link_storage_definition);
$link_column = $shortcut_table_mapping->getFieldColumnName($link_storage_definition, 'url');
dpm($has_dedicated_storage, 'has_dedicated_storage(link)');
dpm($link_column, 'link_column');