Как запросить ярлык Drupal (8.x/9.x) по его URL-адресу или пути к меню?

#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 :

Схема базы данных для таблицы quot;shortcut_field_dataquot; показывает, что значения свойства quot;ссылкаquot; сглаживаются до столбцов с именами quot;ссылка__uriquot;, quot;ссылка__заголовокquot; и quot;ссылка__параметрыquot;.

TL;DR Это означает, что это работает:

 $shortcuts_needing_update = 
  Drupal::entityTypeManager()
    ->getStorage('shortcut')
    ->loadByProperties([
      'link__uri' => 'internal:/admin/old/path',
    ]
  );
 

Читайте дальше, если хотите узнать тонкую причину, по которой это так.

Уровень базы данных Drupal использует подключаемые объекты «сопоставление таблиц», чтобы указать, как сопоставить объект (например, ярлык) с одной или несколькими таблицами базы данных и столбцами таблиц базы данных. Логика создания имени столбца для поля выглядит следующим образом в сопоставлении таблиц по умолчанию ( DrupalCoreEntitySqlDefaultTableMapping ):

Содержимое метода 'DrupalCoreEntitySqlDefaultTableMapping::getFieldColumnName ()' (описано ниже).

Как показано выше, если поле указывает, что оно позволяет хранить «общую» таблицу, и поле имеет несколько свойств ( uri title , и т.д.), То сопоставление сглаживает поле в отдельные столбцы для каждого свойства с префиксом имени поля. Таким образом, объект ярлыка с link => ['uri' => 'xyz']] становится столбцом link__uri со значением xyz в базе данных.

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

Как сопоставление определяет, должно ли поле использовать общее хранилище таблиц? Эта логика выглядит так: Содержимое метода 'DrupalCoreEntitySqlDefaultTableMapping::allowsSharedTableStorage ()' (описано ниже).

Таким образом, сопоставление таблиц по умолчанию будет использовать общее хранилище таблиц для поля только при определенных обстоятельствах:

  1. У поля не может быть пользовательского обработчика хранилища (проверьте здесь, так как ярлыки не предоставляют свою собственную логику хранения).
  2. Поле должно быть базовым полем (ярлыки-ничто без ссылки, поэтому это поле определяется как базовое поле, как указано в ОП).
  3. Поле должно быть однозначным (проверяет-ярлыки имеют только одну ссылку).
  4. Поле не должно быть удалено (проверяется; опять же, что такое ярлык без поля ссылки?).

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

Мы можем подтвердить это, используя 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');
 

Это приводит к следующему:
Если вы попросите сопоставление таблиц, настроенное для сущностей ярлыков, сгенерировать столбец для поля quot;ссылкаquot;, оно подтвердит правильность имени, которое мы вывели из схемы базы данных (quot;ссылка__urlquot;).