logo

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

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

演示 EBT 模块 下载 EBT 模块

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

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

演示 EPT 模块 滚动

滚动

Entity API 实现了 Typed Data API

30/09/2025, by Ivan

显著改进

在这个新的 Entity API 实现中,一切都是基于相同 API 的字段,因此实体是可预测和一致的。

理解 Drupal 的数据模型

首先,在我们深入了解 Typed Data API 本身之前,我们需要理解 Drupal(Entity API)过去如何看待数据模型。这一点很重要,因为 Typed Data API 就是从这里衍生出来的,而 Entity API 正是为它开发的系统之一。

实体是一种复杂的数据,由其他数据片段组成,比如带有条目列表的字段。字段条目本身也是复杂的——它由更多的数据片段组成,例如文本值和输入格式。然而,这种复杂性最终会归结为某种原始数据类型,比如字符串或整数。

下面是 Drupal 7 的简化示例(示例中没有语言键,因为 Drupal 8 的处理方式不同):

示例 1

// 实体是复杂的,它们包含其他数据片段。
$entity;

// 字段不是复杂的,它们只包含一个条目列表。
$entity->image;

// 条目是复杂的,它们包含其他数据片段。同时它们也是可翻译和可访问的(有权限)。
$entity->image[0];

// 文件 ID 是一个原始整数。
$entity->image[0]['fid'];

// 替代文本是一个原始字符串。
$entity->image[0]['alt'];

整合所有内容

下面是一个简化的示例,展示 Entity API 如何实现与 Typed Data API 不同的接口。实际上,Entity API 扩展了这些接口,并添加了 Entity API 所需的附加方法。不过,以下所有语句都评估为 true:

示例 2

// 实体是复杂的。
$entity instanceof ComplexDataInterface;

// 属性不是复杂的,它们只是条目列表。
$entity->get('image') instanceof ListInterface;

// 条目是复杂的。
$entity->get('image')->offsetGet(0) instanceof ComplexDataInterface;

// 表示 alt 值的 Typed Data 对象。
$entity->get('image')->offsetGet(0)->get('alt') instanceof TypedDataInterface;

// alt 值是一个原始字符串。
is_string($entity->get('image')->offsetGet(0)->get('alt')->getValue());

下面简要概述了 Entity API 如何扩展 Typed Data API,以满足一些额外的需求:

示例 3

interface EntityInterface extends ComplexDataInterface, TranslatableInterface, AccessibleInterface {
 // ...
}

interface FielditemListInterface extends ListInterface {
 // ...
}

// 注意它扩展了两个接口。解释见下文。
interface FieldItemInterface extends ComplexDataInterface, TypedDataInterface {
 // ...
}

// 以下是一些实际的实现。

// 扩展一个抽象类,带有一些通用逻辑。
class ImageItem extends FieldItemBase {
 // ...
}

// 扩展一个抽象类,带有一些通用逻辑。
class String extends TypedData {
 // ...
}

[以下两段需要进一步补充]

以上最明显的两点:

1. EntityInterface 扩展了一些工具接口,用于处理翻译和访问控制。这一点应该很直观。
2. FieldItemInterface 同时扩展了 ComplexDataInterface 和 TypedDataInterface。如前所述,条目是复杂的,因为它们包含更多数据片段(例如文本值和格式)。但同时,条目本身又是 Typed Data 的一部分,因此它有自己的定义和数据类型。

因此,总结来说,除了示例 2 外,以下语句也都为 true:

示例 4

$entity instanceof EntityInterface;

$entity->get('image') instanceof FieldItemListInterface;

$entity->get('image')->offsetGet(0) instanceof FieldItemInterface;

$entity->get('image')->offsetGet(0)->get('alt') instanceof String;

is_string($entity->get('image')->offsetGet(0)->get('alt')->getValue());

使用 API

[此部分需要更多示例]

Entity API 定义了一些魔术方法,例如 __get(),以便快速轻松地访问字段值。因此,使用 API 非常简单,并且语法类似于 Drupal 8 之前的时代。

获取图像替代文本的实际值可以按以下方式完成:

示例 5

// 最详细的方式。
$string = $entity->get('image')->offsetGet(0)->get('alt')->getValue();

// Entity API 提供的魔术方法。
$string = $entity->image[0]->alt;

// Entity API 提供的更多魔术方法,默认获取列表中的第一个条目。
$string = $entity->image->alt;

上面的示例只是为旧 API 添加了更好的语法。下面的示例展示了该 API 的真正价值所在——数据定义:

示例 6

// 返回一个数组,包含所有字段及其定义的键。例如 'image' 字段。
$property_definitions = $entity->getFieldDefinitions();

// 返回一个数组,包含所有属性及其定义的键。例如 'file_id' 和 'alt' 属性。
$property_definitions = $entity->image
  ->getFieldDefinition()
  ->getFieldStorageDefinition()
  ->getPropertyDefinitions();

// 仅返回 'alt' 属性的定义。
$string_definition = $entity->image
  ->getFieldDefinition()
  ->getFieldStorageDefinition()
  ->getPropertyDefinition('alt');

基于上述定义,我们现在可以做一些智能的事情,比如序列化或创建其他数据数组。我们还可以通过语义丰富的 API(例如 JSON-LD 端点)提供这些数据,以便其他系统能够理解我们数据的结构。

参见 https://drupal.org/node/2078241 以获取更多关于如何定义和使用实体字段定义的信息。