Entity API 实现了 Typed Data API
显著改进
- Entity API 现在实现了 Typed Data API
在这个新的 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 以获取更多关于如何定义和使用实体字段定义的信息。