0

我们正在推出对内部 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',
    ]);

根据中的代码,\Drupal\shortcut\Entity\Shortcut::baseFieldDefinitions()\Drupal\shortcut\Controller\ShortcutSetController::addShortcutLinkInline()明显 Shortcut 实体有一个名为的属性link,可以像包含uri键的数组一样设置它,但即使它是一个基本字段,似乎也无法通过该属性进行查询。

4

1 回答 1

1

查看数据库,Drupal 似乎将 URL 存储在名为的数据库列中link__uri

“shortcut_field_data”表的数据库模式显示“link”属性的值被展平为名为“link__uri”、“link__title”和“link__options”的列

TL;DR 这意味着这有效:

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

如果您想了解这种情况的微妙原因,请继续阅读。

Drupal 的数据库层使用可插入的“表映射”对象来告诉它如何将实体(如快捷方式)映射到一个或多个数据库表和数据库表列。为字段生成列名的逻辑在默认表映射 ( \Drupal\Core\Entity\Sql\DefaultTableMapping) 中如下所示:

'\Drupal\Core\Entity\Sql\DefaultTableMapping::getFieldColumnName()' 方法的内容(如下所述)。

如上所示,如果一个字段指示它允许“共享”表存储,并且该字段具有多个属性(urititle等),则映射会将字段展平为每个属性的不同列,并以字段名称为前缀。因此,具有 的快捷方式实体成为数据库中值为 的link => ['uri' => 'xyz']]列。link__urixyz

你不会经常看到像节点这样的实体,这就是为什么这在这里看起来很奇怪。我通常习惯于为链接字段之类的内容查看单独的数据库表。这是因为节点和其他内容实体通常不允许对其字段进行共享表存储。

映射如何确定字段是否应使用共享表存储?该逻辑如下所示: '\Drupal\Core\Entity\Sql\DefaultTableMapping::allowsSharedTableStorage()' 方法的内容(如下所述)。

因此,默认表映射仅在特定情况下才会对字段使用共享表存储:

  1. 该字段不能有自定义存储处理程序(请在此处查看,因为快捷方式不提供自己的存储逻辑)。
  2. 该字段必须是基本字段(没有链接,快捷方式什么都不是,因此该字段被定义为 OP 中提到的基本字段)。
  3. 该字段必须是单值的(签出——快捷方式只有一个链接)。
  4. 该字段不得被删除(签出;再次,什么是没有链接字段的快捷方式?)。

节点或其他内容实体通常不满足这组特定的情况,这就是为什么这里有点令人惊讶的原因。

我们可以通过使用Devel 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');

这导致以下结果: 如果您要求为快捷方式实体配置的表映射为“链接”字段生成列,它会确认我们通过查看数据库架构 (“link__url”) 推断出的名称是正确的。

于 2021-10-05T21:40:05.667 回答