logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动

9.10. Drupal 字段 API。Drupal 数据库中的字段。

17/10/2025, by Ivan

Menu

mysql

在本文中,我们将了解 Drupal 中字段是如何工作的,为什么它们是必需的,以及字段如何帮助我们快速开发 Drupal 网站。

在之前的文章中,我们已经处理过字段:

7.5. 使用 bootstrap 列排版服务块

7.6. Drupal 的 Isotope 画廊

7.7. 带有 YouTube 视频的 Drupal 区块

现在我们将搞清楚它是如何工作的。让我们进入编辑文章类型内容字段,并添加一个新的链接字段:

/admin/structure/types/manage/article/fields

add field

当你创建一篇新文章时,你将有两个输入 URL 和文本链接:

link

每次通过管理员创建新字段时,数据库中会创建两个表:

{entity_type}___field_name}
{entity_type}_revision___field_name}

Drupal 支持版本控制,因此所有数据至少会复制一次,因为唯一的版本就是你文章的当前版本。因此,字段和整个 Drupal 字段 API 用于简化与数据库的交互。我们只需通过管理员创建字段,Drupal 会自动在数据库中创建相应的表。

从 MySQL 表的命名中可以看出,同一个字段可以用于一个实体类型。例如,我们现在可以在“基本页面”类型的内容中重用链接字段,如下所示:

/admin/structure/types/manage/page/fields/add-field

add field

但如果你想在区块中创建一个链接字段,你将需要创建一个新字段。不能在不同类型的实体之间使用相同的字段。让我们为基本区块类型创建一个链接字段:

/admin/structure/block/block-content/manage/basic/fields/add-field

如你所见,在创建字段时,无法从现有字段中选择链接字段,因为区块和节点是不同类型的实体。

就像节点一样,我们将有两个表来存储区块中链接字段的数据:

tables and views

block_content_revision__field_link 和 block_content__field_link。

现在让我们了解一下 Drupal 如何为不同的捆绑节点存储同一字段的数据。我们为文章节点类型创建了链接字段,但随后在基本页面节点类型中重用了该字段。为了方便起见,最好将站点配置上传到文件夹并查看文件,但你也可以通过 Adminer 或 phpMyAdmin 在配置表中找到所需的配置:

select config

如果你搜索所有包含“link”字样的配置:

SELECT * FROM `config` WHERE CONVERT(`name` USING utf8mb4) LIKE '%link%' LIMIT 50

我们将找到以下与 field_link 字段相关的配置:

field.field.block.block_content.basic.field_link
field.field.node.article.field_link
field.field.node.page.field_link
field.storage.block_content.field_link
field.storage.node.field_link

对于每个实体类型,每个字段都会创建自己的字段存储配置。此配置定义了如何将数据存储在表 {entity_type}__{field_name} 和 {entity_type}_revision__{field_name} 中。在我们的案例中,表名分别为 block_content_field_link、block_content_revision_field_link、node__field_link 和 node_revision__field_link。接下来,我们将查看链接模块是如何存储数据的。让我们打开链接字段的字段存储配置:

uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6
langcode: en
status: true
dependencies:
  module:
    - block_content
    - link
id: block_content.field_link
field_name: field_link
entity_type: block_content
type: link
settings: {  }
module: link
locked: false
cardinality: 1
translatable: true
indexes: {  }
persist_with_no_fields: false
custom_storage: false

让我们逐行查看这些内容,以便清楚地了解字段存储配置中存储了哪些内容。

uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6

这是配置 ID,唯一标识每个配置。如果你已经在本地创建了字段并上传了配置文件,那么在 staging 环境中就无需手动创建该字段。字段会自动创建。如果你删除了字段并删除了本地配置,然后将其导入到 staging 环境,也会删除所有数据。因此,如果你在 staging 上创建了字段,请上传配置并将其添加到 git 中,以避免丢失更改。

langcode: en

在多语言站点中,针对不同语言的节点版本,字段表中存储了所有语言的数据,并指明哪些数据使用了特定语言:

select

我使用的是相同语言,因此配置中的默认语言也是相同的。

status: true

所有配置实体都有一个状态字段,显示该实体是否启用或禁用。字段存储配置使用 Drupal 中已创建的配置实体,见 FieldStorageConfig 类,它继承自 ConfigEntityBase:

https://api.drupal.org/api/drupal/core!modules!field!src!Entity!

dependencies:
  module:
    - block_content
    - link

依赖的附加模块。由于我们在区块中使用了链接字段,因此必须使用 Block Content 模块。

id: block_content.field_link

这是我们配置的唯一名称。

field_name: field_link

我们创建的字段的机器名称,Drupal 使用该名称。例如,当访问节点对象时,可以使用 $node->field_link->uri。如何引用实体字段,我们将在后续文章中详细了解。

Entity_type: block_content

这是我们的字段存储配置对应的实体类型。

type: link

Drupal 字段类型,我们将创建我们自己的字段类型,现在只需知道该类型字段是由链接模块创建的。你可以查看类:

core/modules/link/src/Plugin/Field/FieldType/LinkItem.php

该类用于我们配置。

settings: { }

此处存储字段类型的设置,目前它是空的,但例如,正文字段有一个设置用于显示摘要与否:

config/sync/field.field.block_content.basic.body.yml

settings:
display_summary: false

module: link

具有链接字段类型的模块。现在,我们有相同的模块名称和字段类型链接,但它们可以不同,例如,一个模块中可以实现多个字段类型,就像在 DateTime 模块中一样:

core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php

locked: false

表示字段是否可以编辑。这意味着该字段已设置为不可编辑。例如,Commerce 模块中的账单信息和运送信息字段曾被锁定,因为在使用送货和税费计算时,这些字段是强制要求存在的。

cardinality: 1

可以为一个实体输入的该字段的值的数量。我们选择了一个值,但此处可以选择其他数字如 2、3、5 等。对于无限数量的值,使用 cardinality: -1。

translatable: true

该字段是否可以翻译成其他语言。

indexes: { }

用于更好地在该字段中进行搜索的额外 SQL 索引。通常它对于配置和优化数据库查询是必要的。

persist_with_no_fields: false

如果字段从所有实体中删除,是否删除字段存储。例如,如果我们从文章和基本页面中删除该字段,则字段存储不会被删除。

custom_storage: false

自定义存储意味着我们有一个专门的表来存储字段数据,而不是 {entity_type}__{field_name}。我们不使用类似的东西,但有时它对与其他系统的集成很有帮助。

现在让我们打开链接字段类型文件:

core/modules/link/src/Plugin/Field/FieldType/LinkItem.php

让我们看看这个字段在数据库中存储了哪些数据。可以在 propertyDefinitions() 方法中看到:

public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
  $properties['uri'] = DataDefinition::create('uri')
    ->setLabel(t('URI'));
 
  $properties['title'] = DataDefinition::create('string')
    ->setLabel(t('Link text'));
 
  $properties['options'] = MapDataDefinition::create()
    ->setLabel(t('Options'));
 
  return $properties;
}

如你所见,我们存储了 URI、标题和选项数据。如果你打开 node__field_link 表,你将看到相同的字段:

select

现在我们已经了解了 Drupal 中的字段 API。我们通过模块中的 PHP 文件使用 LinkItem 类创建了一个字段类型。这允许我们为实体创建字段,然后可以使用它来输入数据并将这些数据存储在数据库中。这就是数据输入的过程。字段 API 还配置了用于数据输入的表单和字段数据输出。

让我们回到创建字段到文章和基本页面内容类型的那一刻。我们为节点创建了一个字段存储配置文件:field.storage.node.field_link.yml,但在创建字段时,我们还为每个实体的每个捆绑类型创建了一个配置文件,因此例如,我们现在有三个配置文件:

field.field.node.article.field_link.yml
field.field.node.page.field_link.yml
field.field.block.block_content.basic.field_link.yml

这些配置存储了字段设置表单中的数据:

link

通过这种方式,我们可以为不同的捆绑类型以不同的方式定制字段的数据输入表单。在 Drupal 中,每个捆绑类型的字段配置都被称为字段实例(Field Instance),因此我们首先创建一个字段存储配置,该配置可以在每个捆绑中单独使用。与 Drupal 7 不同,Drupal 8 中不再有用于处理字段实例的函数,实例的功能迁移到了 CRUD API:

https://www.drupal.org/node/2054619

你可以在官方文档中查看通过代码处理字段的示例:

https://www.drupal.org/node/2012896

我们只查看了字段 API 中与字段数据在数据库中的存储相关的部分。在接下来的几课中,我们将探讨字段 API 如何处理数据输入和字段数据输出,并且创建我们自己的完整字段类型。