如何通过 URL 或菜单路径查询 Drupal 快捷方式 (8.x/9.x)?
How do I query a Drupal Shortcut (8.x/9.x) by its URL or Menu Path?
我们正在对 in-house 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()
中的代码,很明显快捷方式实体有一个名为 link
的 属性,可以将其设置为包含 uri
键,但似乎无法通过此 属性 进行查询,即使它是一个基字段。
查看数据库,Drupal 似乎将 URL 存储在名为 link__uri
:
的数据库列中
TL;DR 这意味着这有效:
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link__uri' => 'internal:/admin/old/path',
]
);
如果您想知道出现这种情况的微妙原因,请继续阅读。
Drupal 的数据库层使用可插入的“table 映射”对象来告诉它如何将实体(如快捷方式)映射到一个或多个数据库 table 和数据库 table列。在默认 table 映射 (\Drupal\Core\Entity\Sql\DefaultTableMapping
) 中,为字段生成列名的逻辑如下所示:
如上所示,如果一个字段表明它允许“共享”table存储,并且该字段有多个属性(uri
、title
等),那么映射将字段扁平化为每个 属性 的不同列,并以字段名称为前缀。因此,具有 link => ['uri' => 'xyz']]
的快捷方式实体成为数据库中值为 xyz
的列 link__uri
。
对于像节点这样的实体,您不会经常看到这种情况,这就是为什么这在这里看起来很奇怪。我通常习惯于看到一个单独的数据库 table 用于 link 字段之类的东西。那是因为节点和其他内容实体通常不允许共享 table 存储它们的字段。
映射如何确定字段是否应使用共享 table 存储?该逻辑如下所示:
因此,默认 table 映射将仅在特定情况下对字段使用共享 table 存储:
- 该字段不能有自定义存储处理程序(在此处查看,因为快捷方式不提供自己的存储逻辑)。
- 该字段必须是一个基字段(快捷方式没有没有一个link,因此该字段被定义为OP中提到的基字段) .
- 该字段必须是单值的(签出 -- 快捷方式只有一个 link)。
- 该字段一定没有被删除(检查;再一次,没有 link 字段的快捷方式是什么?)。
节点或其他内容实体通常不满足这种特定情况,这就是为什么这里有点令人惊讶的原因。
我们可以通过使用 Devel PHP 直接向 table 映射查询快捷方式来确认这一点,代码如下:
$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');
结果如下:
我们正在对 in-house 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()
中的代码,很明显快捷方式实体有一个名为 link
的 属性,可以将其设置为包含 uri
键,但似乎无法通过此 属性 进行查询,即使它是一个基字段。
查看数据库,Drupal 似乎将 URL 存储在名为 link__uri
:
TL;DR 这意味着这有效:
$shortcuts_needing_update =
\Drupal::entityTypeManager()
->getStorage('shortcut')
->loadByProperties([
'link__uri' => 'internal:/admin/old/path',
]
);
如果您想知道出现这种情况的微妙原因,请继续阅读。
Drupal 的数据库层使用可插入的“table 映射”对象来告诉它如何将实体(如快捷方式)映射到一个或多个数据库 table 和数据库 table列。在默认 table 映射 (\Drupal\Core\Entity\Sql\DefaultTableMapping
) 中,为字段生成列名的逻辑如下所示:
如上所示,如果一个字段表明它允许“共享”table存储,并且该字段有多个属性(uri
、title
等),那么映射将字段扁平化为每个 属性 的不同列,并以字段名称为前缀。因此,具有 link => ['uri' => 'xyz']]
的快捷方式实体成为数据库中值为 xyz
的列 link__uri
。
对于像节点这样的实体,您不会经常看到这种情况,这就是为什么这在这里看起来很奇怪。我通常习惯于看到一个单独的数据库 table 用于 link 字段之类的东西。那是因为节点和其他内容实体通常不允许共享 table 存储它们的字段。
映射如何确定字段是否应使用共享 table 存储?该逻辑如下所示:
因此,默认 table 映射将仅在特定情况下对字段使用共享 table 存储:
- 该字段不能有自定义存储处理程序(在此处查看,因为快捷方式不提供自己的存储逻辑)。
- 该字段必须是一个基字段(快捷方式没有没有一个link,因此该字段被定义为OP中提到的基字段) .
- 该字段必须是单值的(签出 -- 快捷方式只有一个 link)。
- 该字段一定没有被删除(检查;再一次,没有 link 字段的快捷方式是什么?)。
节点或其他内容实体通常不满足这种特定情况,这就是为什么这里有点令人惊讶的原因。
我们可以通过使用 Devel PHP 直接向 table 映射查询快捷方式来确认这一点,代码如下:
$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');
结果如下: