实体类型
- Drupal 7 - 实体是通用的 stdClass 对象。
- Drupal 8 - 实体现在是具有特定类型的对象,每种实体类型都会定义一个类,用于该实体的实例。
要求
实体类必须放置在提供该实体类型的模块的 Entity 子命名空间中,例如 \Drupal\[module_name]\Entity。这意味着实体类的 PHP 文件可以在模块的 src/Entity 目录下找到。
类的文档块必须包含 EntityType 注解,它定义了该类型实体的元数据。这些包括实体类型的标签、控制器、表等。有关所有可用元数据属性的文档化列表,请参阅 \Drupal\Core\Entity\Annotation\EntityType 类。
命名
如果实体类型与模块名称不一致,则实体类型的名称必须带有模块名前缀。实体类型类本身不需要加前缀,因为它位于定义模块的命名空间中,只要类名本身足够清晰。例如,分类术语的实体类型称为 taxonomy_term,而类名为 Drupal\taxonomy\Entity\Term。
接口
Drupal 8 推荐使用接口而不是类来进行函数类型提示和方法调用。例如,通用实体存储使用 EntityInterface 作为类型提示,就像在 hook_entity_insert(EntityInterface $entity) 中一样;而节点存储使用 NodeInterface 作为类型提示,就像在 hook_node_insert(NodeInterface $node) 中一样。
实体的字段/属性通常很简短,偏向存储,并且不太具有可读性。此外,内容实体通常不会使用特定属性来表示其字段(包括基本字段,如节点标题)。
因此,推荐的方法是提供一个带有文档化方法名称的接口。在此过程中应遵循以下规则:
- 方法通常以 get/set/is 或类似前缀开头:getSomething()、setSomething($value)、isSomething()。
- 仅为需要被其他代码修改的内容添加方法。例如,节点的最后修改时间($node->updated)不应被修改,因此有 $node->getChangedTime() 方法,但没有 $node->setChangedTime() 方法。
- 使用自解释的方法名称,例如访问 $node->status 的方法是 $node->isPublished()。
可理解性
要了解某个模块提供了哪些实体类型,请查看该模块 Entity 命名空间下的类,这些类带有 @EntityType 注解,该注解还包含一个 id 键用于标识实体类型名称。
当试图查找某个实体类型定义在哪里时,首先要查找的是实体类型的前缀。如果模块没有遵循命名约定,可以通过搜索 id = "$type" 来找到。如果已知类或接口而不是实体类型,那么命名空间就能指示它的来源。
示例
core/modules/node/src/Entity/Node.php:
namespace Drupal\node\Entity;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
use Drupal\user\UserInterface;
/**
* 定义 Node 实体类。
*
* @ContentEntityType(
* id = "node",
* label = @Translation("Content"),
* bundle_label = @Translation("Content type"),
* handlers = {
* "storage" = "Drupal\node\NodeStorage",
* "storage_schema" = "Drupal\node\NodeStorageSchema",
* "view_builder" = "Drupal\node\NodeViewBuilder",
* "access" = "Drupal\node\NodeAccessControlHandler",
* "views_data" = "Drupal\node\NodeViewsData",
* "form" = {
* "default" = "Drupal\node\NodeForm",
* "delete" = "Drupal\node\Form\NodeDeleteForm",
* "edit" = "Drupal\node\NodeForm"
* },
* "route_provider" = {
* "html" = "Drupal\node\Entity\NodeRouteProvider",
* },
* "list_builder" = "Drupal\node\NodeListBuilder",
* "translation" = "Drupal\node\NodeTranslationHandler"
* },
* base_table = "node",
* data_table = "node_field_data",
* revision_table = "node_revision",
* revision_data_table = "node_field_revision",
* translatable = TRUE,
* list_cache_contexts = { "user.node_grants:view" },
* entity_keys = {
* "id" = "nid",
* "revision" = "vid",
* "bundle" = "type",
* "label" = "title",
* "langcode" = "langcode",
* "uuid" = "uuid",
* "status" = "status",
* "uid" = "uid",
* },
* bundle_entity_type = "node_type",
* field_ui_base_route = "entity.node_type.edit_form",
* common_reference_target = TRUE,
* permission_granularity = "bundle",
* links = {
* "canonical" = "/node/{node}",
* "delete-form" = "/node/{node}/delete",
* "edit-form" = "/node/{node}/edit",
* "version-history" = "/node/{node}/revisions",
* "revision" = "/node/{node}/revisions/{node_revision}/view",
* }
* )
*/
class Node extends ContentEntityBase implements NodeInterface {
// ...
}
要全面了解 Drupal 8 中的实体,我们可以参考以下图表。它展示了实体类。查看时可在新标签页中打开:
