9.11. Drupal 实体(Entity)API。创建自定义实体类型。使用 Drupal Console 生成实体类型。
我们已经了解了 Form API、Fields API,并且知道 Drupal 中的数据是如何存入数据库的。现在让我们来看看所有 Drupal 网站的基础——Entity API(实体 API)。
你可能已经注意到,字段(fields)并不是独立存在的,而是“附加”在实体(entity)上的:节点(nodes)、区块(blocks)、分类术语(taxonomy terms)、视图(views)等。你可以创建可打包(bundle)的实体,例如内容类型、区块类型、分类字典等。但如果你需要创建一个带有自己 bundle 的新实体类型怎么办?这种情况下,你就需要使用 Entity API 来创建新的实体类型。
我已将所有代码添加到 GitHub 上的 drupalbook_product 模块中,你可以下载该模块并将其添加到自己的网站中:
https://github.com/levmyshkin/drupalbook8
创建新的实体类型最简单的方法是通过 Drupal Console,因为只需要执行一个命令即可完成。
你并不需要频繁地创建新的实体类型。大多数中小型项目通常使用现有的贡献模块(contrib modules)作为基础,例如用于电子商务的 Commerce 模块:
https://www.drupal.org/project/commerce
如果你打算创建自己的插件模块,那么也许会需要定义新的实体类型。当然,你也可以在 Drupal 模块中找到功能相似的模块,然后为它们添加或扩展所缺少的功能。
在本文中,我们将学习 Entity API,并创建我们自己的 Product(产品)实体类型,它将作为一个小型自定义目录或商店的基础。如果你确实决定要创建自定义商店,我仍然强烈建议你使用 Commerce 模块,因为它可以为你和你的客户节省大量时间。
当你想创建一个新的实体类型时,可能会问:为什么不能直接创建一个新的“产品”内容类型(Content type)并用于目录?确实,对于一个带有 Views 输出、按价格或库存进行简单筛选的小型目录来说,这样做是可行的。但当产品数量达到上千时,管理员在内容页面查找产品会变得非常不便。管理员希望能在后台页面上使用按编号、分类、颜色、名称等的筛选功能:
/admin/content
这样会显得过于冗杂,并且干扰其他内容类型(如新闻、文章、活动、页面等)的管理。因此,在这种情况下,通常会创建一个单独的 Product 实体类型,并为其提供独立的后台面板和设置。
让我们开始创建一个单独的 Product 实体类型。在执行生成命令前,我强烈建议先为网站创建备份,至少备份数据库。因为创建实体类型的过程会生成配置文件(configs),这些文件会写入数据库,如果过程中出错、某些配置写入而实体文件缺失,可能会导致网站崩溃。因此请务必先创建备份。
现在我们来创建一个新模块。它同样可以通过 Drupal Console 生成:
drupal generate:module
https://hechoendrupal.gitbooks.io/drupal-console/en/commands/generate-module.html
$ vendor/bin/drupal generate:module
// 欢迎使用 Drupal 模块生成器
输入新模块名称:
> Drupalbook Product
输入模块机器名称 [drupalbook_product]:
>
输入模块路径 [modules/custom]:
>
输入模块描述 [My Awesome Module]:
> Products catalog
输入包名称 [Custom]:
>
输入 Drupal 核心版本 [8.x]:
>
是否生成 .module 文件?(yes/no) [yes]:
> no
定义模块为特性 (yes/no) [no]:
> no
是否添加 composer.json 文件?(yes/no) [yes]:
> no
是否添加模块依赖?(yes/no) [no]:
> no
是否生成单元测试类?(yes/no) [yes]:
> no
是否生成可主题化模板?(yes/no) [yes]:
> no
是否继续操作?(yes/no) [yes]:
> yes
已生成或更新的文件
生成路径: /home/laptop/projects/drupalbook
1 - /modules/custom/drupalbook_product/drupalbook_product.info.yml
生成行数: "5"
或者手动创建一个模块文件 drupalbook_product.info.yml:
name: 'drupalbook_product'
type: module
description: 'Products catalog'
core: 8.x
package: 'Drupalbook'
现在我们可以生成 Product 实体类型了。
https://hechoendrupal.gitbooks.io/drupal-console/en/commands/generate-entity-content.html
$ drupal generate:entity:content
$ vendor/bin/drupal generate:entity:content
// 欢迎使用 Drupal 内容实体生成器
输入模块名称 [admin_toolbar]:
> drupalbook_product
输入新实体类名称 [DefaultEntity]:
> DrupalbookProductEntity
输入新实体机器名称 [drupalbook_product_entity]:
>
输入新实体标签 [Drupalbook product entity]:
> Product
输入实体路由基础路径 [/admin/structure]:
>
该实体是否具有 bundle?(yes/no) [no]:
> yes
实体是否支持多语言?(yes/no) [yes]:
> yes
实体是否可修订?(yes/no) [yes]:
> no
// generate:entity:config
输入配置实体路由基础路径 [/admin/structure]:
>
已生成或更新的文件
生成路径: /home/laptop/projects/drupalbook
...(共生成 29 个文件,略)...
生成行数: "1060"
模块生成后,启用它即可在网站上看到新的实体类型:
在生成实体过程中,Drupal Console 会提示一些参数:
Enter the class of your new content entity [DefaultEntity]:
输入新实体的 PHP 类名,建议以 “Entity” 结尾。
Enter the machine name of your new content entity [drupalbook_product_entity]:
机器名称通常根据类名自动生成,直接按回车即可。
Enter the base-path for the content entity routes [/admin/structure]:
此路径决定实体 CRUD 操作的后台页面位置:
产品页面的默认显示方式较为简陋,但可以通过 Views 进行改进或重新设计:
要创建新实体,首先需要创建 Product 类型的 bundle。我们之前选择了可打包实体(bundable entity):
Do you want this (content) entity to have bundles? (yes/no):
因此,我们正在创建新的产品类型。这将用于定义不同的字段,例如重量、尺寸、颜色等属性。例如,显示器会有屏幕对角线尺寸字段,而鞋子则会有鞋码字段。
让我们创建一个新的产品类型——“Clothes(服装)”:
现在,我们可以为新产品类型配置字段:
至少要添加一个价格字段。
创建几个产品后,我们可以查看数据库。此时数据库中会有一个 drupalbook_product_entity 表,用于存储产品的 UUID:
此外,还有一个 drupalbook_product_entity_field_data 表,用于存储实体的属性(Properties)。这些属性是直接保存在数据库表中的特殊字段,例如名称(Name,实体标签字段,例如节点标题 Title),它们不会随着修订而变化。
如果你添加了字段,则每个字段都会生成两张表,因为我们在创建时选择了可修订实体(revisionable entity):
Is your entity revisionable? (yes/no) [yes]
我想你现在已经明白如何创建新的实体类型了。在接下来的文章中,我们将扩展自定义目录/商店的功能。
我已将所有代码上传到 GitHub 的 drupalbook_product 模块中,你可以下载并将其添加到自己的网站: