drupal8 自定义实体
Entities are a great way to organize your data in Drupal. If you are familiar with nodes, taxonomy terms, comments or users, you should also know that since Drupal 7, these have been entities. Another important aspect about them is that they are fieldable via the Field API.
实体是在Drupal中组织数据的好方法。 如果您熟悉节点,分类术语,注释或用户,那么您还应该知道,自Drupal 7起,这些都是实体。 关于他们的另一个重要方面是,它们是通过现场的API fieldable。
In this tutorial I will show you how you can define your own custom entity type and get started working with it. Why would one want to do this instead of using nodes? Because although they are great, nodes can sometimes be overkill. There is a lot of functionality you may not need such as revisions or commenting.
在本教程中,我将向您展示如何定义自己的自定义实体类型并开始使用它。 为什么要这样做而不是使用节点? 因为尽管节点很棒,但有时节点可能会过大。 您可能不需要很多功能,例如修订或注释。
For the purpose of this tutorial, we will define our own custom entity type called project
to represent simple information we have about our projects (title, description and deadline). Then we will look at a few things about working with the entities of this type.
就本教程而言,我们将定义自己的自定义实体类型,称为project
以表示有关项目的简单信息(标题,描述和截止日期)。 然后,我们将了解有关使用这种类型的实体的一些注意事项。
For following along, I assume you know how to write a basic custom module (mine will be named demo
). You can find a great tutorial on this subject here. Go ahead and write the .info
file and create the empty .module
and .install
files. I also set up a Git repository where you can get all the source code for this tutorial (one branch per part, two parts will be published).
接下来,我假设您知道如何编写基本的自定义模块(我的模块将命名为demo
)。 您可以在这里找到有关此主题的出色教程。 继续并编写.info
文件,并创建空的.module
和.install
文件。 我还建立了一个Git存储库 ,您可以在其中获取本教程的所有源代码(每个部分一个分支,将发布两个部分)。
Additionally, you need the Entity API contrib module enabled on your site and set as a dependency to your custom module. The Entity API module is very powerful when working with entities as it provides a lot of functionality that the Drupal core lacks.
此外,您需要在站点上启用Entity API contrib模块并将其设置为自定义模块的依赖项。 实体API模块在处理实体时非常强大,因为它提供了Drupal核心所缺少的许多功能。
定义我们自己的Drupal实体类型 (Defining our own Drupal entity type)
The first thing we need to do to create a new entity type is to declare its schema definition. That is, write the code that will generate the database table for the entity data. In my demo.install
file I have the following code:
创建新实体类型所需要做的第一件事是声明其架构定义。 也就是说,编写将为实体数据生成数据库表的代码。 在我的demo.install
文件中,我有以下代码:
/**
* Implements hook_schema().
*/
function demo_schema() {
$schema = array();
$schema['demo_projects'] = array(
'description' => 'The base table for the Project entity',
'fields' => array(
'id' => array(
'description' => 'Primary key of the Project entity',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'name' => array(
'description' => 'Project name.',
'type' => 'varchar',
'length' => 255,
'not null' => FALSE,
),
'description' => array(
'description' => 'Project description.',
'type' => 'text',
'size' => 'big',
'not null' => FALSE,
'default' => NULL
),
'deadline' => array(
'description' => 'Project deadline.',
'type' => 'int',
'length' => 11,
'not null' => FALSE,
),
),
'primary key' => array('id'),
);
return $schema;
}
This is a simple implementation of hook_schema() through which we create a demo_projects
table that has 4 columns: id, name, description and deadline, the first representing the primary key. Nothing big.
这是hook_schema()的简单实现,通过它我们创建了一个demo_projects
表,该表具有4列:id,名称,描述和截止日期,第一个代表主键。 没什么大不了的。
The next thing we need to do is implement hook_entity_info(). There are a lot of options we can specify in this hook, but here are the most basic and required ones (this goes in the demo.module
file):
我们需要做的下一件事是实现hook_entity_info() 。 我们可以在此挂钩中指定很多选项,但以下是最基本和必需的选项(在demo.module
文件中):
/**
* Implements hook_entity_info().
*/
function demo_entity_info() {
$info = array();
$info['project'] = array(
'label' => t('Project'),
'base table' => 'demo_projects',
'entity keys' => array(
'id' => 'id',
'label' => 'name',
),
'module' => 'demo',
);
return $info;
}
With this hook we return a new key in the $info
array that represents the entity machine name. Inside this array we specify the options (we will add more in the course of this tutorial). For now, we will stick to label
(human readable name of the entity type), base table
that stores the entity data, entity keys
which are the properties that act as identifiers for the entities and module
that specifies which module defines the entity type. The last one is not mandatory but recommended.
通过此钩子,我们在$info
数组中返回一个代表实体机器名称的新密钥。 在此数组中,我们指定选项(在本教程的过程中,我们将添加更多选项)。 现在,我们将坚持label
(实体类型的人类可读的名称), base table
,其存储实体数据, entity keys
它们是性质充当实体和标识符module
,指定哪个模块定义的实体类型。 最后一个不是强制性的,但建议使用。
And with this we have registered our own basic entity type with Drupal. To test out if it works, enable the module for the first time and check if the table was created in the database. Then populate it with a few rows to have something to work with:
至此,我们已经在Drupal中注册了自己的基本实体类型。 要测试它是否有效,请首次启用该模块,并检查表是否在数据库中创建。 然后用几行填充它以使用一些东西:
INSERT INTO `demo_projects` (`id`, `name`, `description`, `deadline`)
VALUES
(1, 'Summer House', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 1397501105),
(2, 'Winter House', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 1397501132);
Finally, register a path with Drupal (any path for testing only) using hook_menu() and paste the following in its callback function:
最后,使用hook_menu()在Drupal中注册一个路径(仅用于测试的路径) ,并将以下内容粘贴到其回调函数中:
$projects = entity_load('project', array(1, 2));
dpm($projects);
return 'Some string';
First, we use the entity_load() function to load the project entities with the IDs of 1 and 2 and then we print them to the screen using the Devel dpm()
function (so make sure Devel is enabled on your site for testing). And don’t forget that the callback function for the page needs to return something otherwise it won’t build.
首先,我们使用entity_load()函数加载ID为1和2的项目实体,然后使用Devel dpm()
函数将它们打印到屏幕上(因此请确保在您的站点上启用了Devel进行测试)。 并且不要忘记页面的回调函数需要返回某些内容,否则它将无法生成。
Now if you navigate to that page you’ll see in Krumo the data from the 2 entities in the database.
现在,如果您导航到该页面,您将在Krumo中看到数据库中2个实体的数据。
Alternatively, you can use the EntityFieldQuery class to query for the new entities by any property you want (not just the id). For more information about how this works you can check out this Sitepoint tutorial that will get you started.
或者,您可以使用EntityFieldQuery类通过所需的任何属性(而不仅仅是id)查询新实体。 有关此工作原理的更多信息,请查看此Sitepoint教程 ,它将帮助您入门。
实体类和控制器 (Entity class and controller)
Unfortunately, Drupal core does not come with too many helper functions to work with entities (entity_load()
is pretty much the only one). However, the Entity API module fills this gap.
不幸的是,Drupal核心并没有太多与实体一起使用的辅助函数( entity_load()
几乎是唯一的)。 但是,实体API模块填补了这一空白。
In order to make use of its functionality, we need to alter the entity info we declared earlier and specify the PHP classes that can be used to work with the entities. For now, we’ll add 2 more keys to the array keyed project
inside our hook_entity_info()
declaration:
为了利用其功能,我们需要更改我们先前声明的实体信息,并指定可用于与实体一起使用PHP类。 现在,我们将在hook_entity_info()
声明中的数组键控project
再添加2个键:
...
'entity class' => 'Entity',
'controller class' => 'EntityAPIController',
...
The first one is the base class provided by Entity API that will offer some wrapping functionality for the entities. This class is declared in the entity.inc
file of the module and if you look inside, you’ll notice that many of its methods call the methods of another (controller) class. This is the class we specified for the controller class
key.
第一个是由Entity API提供的基类,它将为实体提供一些包装功能。 此类在模块的entity.inc
文件中声明,并且如果您查看内部,您会注意到它的许多方法都调用另一个(控制器)类的方法。 这是我们为controller class
键指定的controller class
。
The EntityAPIController
class (found in entity.controller.inc
file of the module) offers some sensible defaults for working with the entities. It extends the default Drupal core DrupalDefaultEntityController
class and it is responsible – among many other things – for performing CRUD operations.
EntityAPIController
类(位于模块的entity.controller.inc
文件中)为使用实体提供了一些合理的默认值。 它扩展了默认Drupal核心DrupalDefaultEntityController
类,并且除其他事项外,还负责执行CRUD操作。
Both of these classes can be extended in your custom module to adjust functionality (like querying, loading or displaying the entities). We will see how to do this in a minute.
这两个类都可以在您的自定义模块中扩展以调整功能(例如查询,加载或显示实体)。 我们将在一分钟内看到如何执行此操作。
But first, I want to show you how to save a new entity. Currently, in my database I have 2 records with the ids 1 and 2. I want to adjust the code we wrote in the test page callback above to create a new entity with the id of 3 if one doesn’t already exist. It can look something like this:
但是首先,我想向您展示如何保存新实体。 当前,在我的数据库中,我有2条ID为1和2的记录。我想调整在上面的测试页回调中编写的代码,以创建一个ID为3的新实体(如果尚不存在)。 它可能看起来像这样:
$projects = entity_load('project', array(1, 2, 3));
if (!isset($projects[3])) {
$entity = entity_create('project', array('id' => 3));
$entity->name = t('Spring House');
$entity->description = t('Some more lipsum.');
$entity->save();
}
dpm($projects);
return 'Some string';
As you can see, now we try to load 3 project entities and check for the existence of the third. If it doesn’t exist, we use the entity_create()
helper function provided by Entity API, set the properties to some random values and then use the save()
method on the entity to persist it to the database. This method is provided by the Entity
class and its job is to call the save()
method on the controller class we defined above. And that method will perform the logic necessary to persist the entity. But all this happens behind the scenes and we don’t have to worry about it.
如您所见,现在我们尝试加载3个项目实体并检查第三个项目实体的存在。 如果不存在,则使用Entity API提供的entity_create()
帮助函数,将属性设置为一些随机值,然后在实体上使用save()
方法将其持久化到数据库中。 该方法由Entity
类提供,其工作是在上面定义的控制器类上调用save()
方法。 并且该方法将执行持久化实体所需的逻辑。 但是所有这些都是在幕后发生的,我们不必为此担心。
If you reload that page, you should see only 2 returned project entities, but if loaded a second time, there should be 3.
如果重新加载该页面,则应该只会看到2个返回的项目实体,但是如果第二次加载,则应该有3个。
覆盖实体类 (Overriding the entity classes)
The last thing I want to show you in this part of the tutorial is how to display your entities. For this, we will stick to the page callback function we’ve been working with and have it render a list of our entities.
在本教程的这一部分中,我想向您展示的最后一件事是如何显示您的实体。 为此,我们将坚持使用我们一直在使用的页面回调函数,并使其呈现我们的实体列表。
The first thing we need to do is override the buildContent()
method of the default EntityAPIController
class. The reason is that the controller cannot make assumptions about our data so we need to provide some information about how to display it. First, let’s declare our controller class that extends the previous one:
我们需要做的第一件事是覆盖默认EntityAPIController
类的buildContent()
方法。 原因是控制器无法对我们的数据做出假设,因此我们需要提供一些有关如何显示数据的信息。 首先,让我们声明扩展前一个控制器类的方法:
/**
* Extending the EntityAPIController for the Project entity.
*/
class ProjectEntityController extends EntityAPIController {
}
I chose the class name ProjectEntityController
and you need to make sure that you replace with this name the value you set for the controller class
key in the hook_entity_info()
implementation. Don’t forget.
我选择了类名称ProjectEntityController
并且需要确保使用该名称替换您在hook_entity_info()
实现中为controller class
键设置的值。 别忘了
Inside of this class, we can copy the method name from the original one and have it return the same its parent would:
在此类的内部,我们可以从原始名称中复制方法名称,并使它返回与其父代相同的名称:
public function buildContent($entity, $view_mode = 'full', $langcode = NULL, $content = array()) {
$build = parent::buildContent($entity, $view_mode, $langcode, $content);
// Our additions to the $build render array
return $build;
}
As such, there are no new changes. But now we can add our own data to the returned value of this method which is nothing more than a Drupal render array. So for example we can write this right before we return the $build
array:
因此,没有新的变化。 但是现在我们可以将自己的数据添加到此方法的返回值中,这不过是Drupal渲染数组。 例如,我们可以在返回$build
数组之前就这样写:
$build['description'] = array(
'#type' => 'markup',
'#markup' => check_plain($entity->description),
'#prefix' => '<div class="project-description">',
'#suffix' => '</div>',
);
$build['deadline'] = array(
'#type' => 'markup',
'#markup' => date('d F, Y', check_plain($entity->deadline)),
'#prefix' => '<p>Deadline: ',
'#suffix' => '</p>',
);
We are basically adding two new items to the array. The first one will wrap the description with a <div class="project-description">
and the second will output a formatted date in between paragraph tags. This is basic Drupal theming so brush up on that if you don’t understand what’s going on here. But you will notice that the project name is missing. That will be rendered automatically by Drupal because we specified it as the label
in the entity keys
of the hook_entity_info()
implementation.
我们基本上是在数组中添加两个新项目。 第一个将用<div class="project-description">
包装描述,第二个将在段落标签之间输出格式化日期。 这是Drupal的基本主题,因此如果您不了解这里发生的事情,请仔细阅读。 但是您会注意到项目名称丢失了。 这将由Drupal自动呈现,因为我们在hook_entity_info()
实现的entity keys
中将其指定为label
。
The final step is to go to our page callback function and make it display our entities. A quick way of doing that (just for demonstration purposes):
最后一步是转到页面回调函数,并使其显示我们的实体。 一种快速的方法(仅用于演示目的):
$projects = entity_load('project', array(1, 2, 3));
$list = entity_view('project', $projects);
$output = array();
foreach ($list['project'] as $project) {
$output[] = drupal_render($project);
}
return implode($output);
As before, we first load our entities with the respective ids. Then, we run them through the entity_view()
helper function that will end up calling the buildContent()
method we just overrode. This function returns a list of render arrays for each entity. We render each one and store the result in the $output
array that we then implode and return.
和以前一样,我们首先使用各自的ID加载实体。 然后,我们通过entity_view()
帮助函数运行它们,最终将调用我们刚刚覆盖的buildContent()
方法。 此函数返回每个实体的渲染数组的列表。 我们渲染每个,并将结果存储在$output
数组中,然后将其内爆并返回。
You can refresh the page and you should see a listing of all the entities you loaded. Make sure you clear the caches so that the changes become visible.
您可以刷新页面,并且应该看到所有已加载实体的列表。 确保清除缓存,以使更改可见。
结论 (Conclusion)
In this tutorial we began learning about entities in Drupal by defining our own entity type in code. We’ve seen how to write a schema definition for the data they represent and how to register them with Drupal. Then we saw the power of using the Entity API contrib module for an object oriented way of working with the entities.
在本教程中,我们通过在代码中定义我们自己的实体类型,开始学习Drupal中的实体。 我们已经看到了如何为它们表示的数据编写模式定义以及如何在Drupal中注册它们。 然后,我们看到了使用Entity API contrib模块进行面向对象的实体工作方式的强大功能。
In the second part of this tutorial we will look at three main aspects. First, we’ll create some pages to display the individual project entities and spin up an admin interface for managing the projects. Second, we’ll make them fieldable through the UI. And third, we’ll expose them to Views so we can do some proper queries and listings. Stay tuned!
在本教程的第二部分中,我们将研究三个主要方面。 首先,我们将创建一些页面来显示各个项目实体,并启动一个用于管理项目的管理界面。 其次,我们将使它们通过UI成为字段。 第三,我们将它们公开给Views,以便我们进行一些适当的查询和列出。 敬请关注!
翻译自: https://www.sitepoint.com/build-custom-entities-drupal-setup/
drupal8 自定义实体