当前位置: 首页 > 工具软件 > Drupal Create > 使用案例 >

drupal8 自定义实体_在Drupal中构建自己的自定义实体-实施

马煌
2023-12-01

drupal8 自定义实体

Welcome back to the second part of this tutorial in which we explore the world of custom entities in Drupal. If you haven’t already, I strongly recommend you read the first installment, but let’s do a short recap nonetheless.

欢迎回到本教程的第二部分,我们在其中探讨了Drupal中的自定义实体的世界。 如果您还没有,我强烈建议您阅读第一期,但是让我们做一个简短的回顾。

In the previous article we’ve defined the schema for our entity type and registered it with Drupal. We’ve also overridden the EntityAPIController to build up the display for our entities.

在上一篇文章中,我们为实体类型定义了架构,并向Drupal注册了架构。 我们还重写了EntityAPIController来建立实体的显示。

In this part of the tutorial we will continue and talk about a few other cool things we can do with entities in Drupal. First, we’ll quickly set up the pages where we can display the individual project entities. Next, we will build a straightforward but very powerful admin interface to manage them. Then, we will make our entity type fieldable so we can add fields through the UI. And finally, we’ll expose it to Views so we can create proper listings of project entities.

在本教程的这一部分中,我们将继续讨论在Drupal中的实体可以做的其他一些很酷的事情。 首先,我们将快速设置页面以显示单个项目实体。 接下来,我们将构建一个简单但功能非常强大的管理界面来对其进行管理。 然后,我们将使实体类型成为可字段化的,以便我们可以通过UI添加字段。 最后,我们将其公开给Views,以便我们可以创建项目实体的正确列表。

If you want, you can follow along with the source code from the first branch of the Git repository, or take a peek into the second branch which contains all the code we will cover today.

如果需要,可以跟随Git存储库第一个分支的源代码,或浏览第二个分支,其中包含我们今天将介绍的所有代码。

个体实体页面 (Individual entity pages)

The first thing we’ll do is create the pages for displaying individual project entities. We’ll start by adding a new item to our hook_menu() implementation:

我们要做的第一件事是创建用于显示单个项目实体的页面。 首先,向我们的hook_menu()实现添加一个新项:

$items['project/%'] = array(
    'title' => 'Project',
    'page callback' => 'demo_view_project',
    'page arguments' => array(1),
    'access arguments' => array('access content'),
  );

We are registering a path (project/id) and a callback function (demo_view_project()) to which we pass the wildcard URL argument (the ID of the project). As for access, anybody with the access content permission can see the page.

我们正在注册一个路径( project/id )和一个回调函数( demo_view_project() ),并将通配符URL参数(项目的ID)传递给该回调函数。 至于访问,任何具有access content权限的人都可以看到该页面。

Next, let’s write the said callback function (keep in mind this is a simple example just for demonstration purposes):

接下来,让我们编写一个回调函数(请记住,这是一个简单的示例,仅用于演示目的):

/**
 * Callback function for displaying the individual project page
 */
function demo_view_project($id) {

  $projects = entity_load('project', array($id));
  $project = $projects[$id];

  drupal_set_title($project->name);
  $output = entity_view('project', array($project));

  return $output;

}

This is again very simple: we load the entity with the ID passed from the URL, we set the title of the page, run the entity object through entity_view() and return it as page output. We’ve covered these Entity API concepts last time when we listed our projects. You can now clear the cache and navigate to project/1 and you should see the project with the ID of 1. If you see the project name twice, don’t worry, this will become clear in the next section when we let Drupal know which one is the default URI callback for the project entities.

这再次非常简单:我们使用从URL传递的ID加载实体,设置页面的标题,通过entity_view()运行实体对象,并将其作为页面输出返回。 上次列出项目时,我们已经介绍了这些Entity API概念。 现在,您可以清除缓存并导航到project/1并且应该看到ID为1的项目。如果您两次看到项目名称,请不要担心,当我们让Drupal知道时,这将在下一部分中变得清楚。哪一个是项目实体的默认URI回调。

管理员用户界面 (Admin user interface)

Now that we can display the individual entities, let’s leverage the power of the Entity API module to set up a quick admin user interface to manage them. There are a few simple steps we need to take for this.

现在我们可以显示各个实体,让我们利用Entity API模块的功能来设置一个快速的admin用户界面来管理它们。 为此,我们需要采取一些简单的步骤。

First, let’s edit our hook_entity_info() implementation for our entity type and add the following (I’ll explain everything after):

首先,让我们编辑我们的实体类型的hook_entity_info()实现,并添加以下内容(我将在后面解释所有内容):

...

'access callback' => 'demo_access_callback',
'uri callback' => 'entity_class_uri',
'admin ui' => array(
  'path' => 'admin/projects',
  'controller class' => 'EntityDefaultUIController',
),

...

And replace this line:

并替换此行:

'entity class' => 'Entity',

With this:

有了这个:

'entity class' => 'ProjectEntity',

With these modification, we do 4 things:

通过这些修改,我们做了4件事:

  1. We specify an access callback function for the entity type. We’ll need this for the admin UI and we’ll declare the callback function in a minute.

    我们为实体类型指定一个访问回调函数。 我们将在管理用户界面中使用此功能,并在一分钟内声明回调函数。
  2. We set the uri callback to the default one provided by the entity class (I will come back to this at point 4).

    我们将uri callback设置为实体类提供的默认uri callback (我将在第4点回到这一点)。

  3. We set the admin ui information: path to the UI page and the controller class that will handle it. EntityDefaultUIController is the default UI class that comes with Entity API and it is declared in the entity.ui.inc file.

    我们设置admin ui信息:UI页面的路径以及将处理该UI的控制器类。 EntityDefaultUIController是Entity API随附的默认UI类,并在entity.ui.inc文件中声明。

  4. We change the name of the entity class for this entity type to one that does not exist yet. We will create it now by extending the previous one so that we can override its defaultUri() method:

    我们将此实体类型的实体类名称更改为尚不存在的名称。 现在,我们将通过扩展前一个方法来创建它,以便我们可以覆盖其defaultUri()方法:

    /**
     * Project entity class extending the Entity class
     */
    class ProjectEntity extends Entity {
    
      /**
       * Change the default URI from default/id to project/id
       */
      protected function defaultUri() {
        return array('path' => 'project/' . $this->identifier());
      }
    
    }

As you can see, we are basically changing that path to the individual project entity returned by this class method. When the time comes, I will point out why this was handy but this will be the default one I mentioned at point 2. Now let’s quickly also declare our access callback function mentioned at point 1:

如您所见,我们基本上是将该路径更改为此类方法返回的单个项目实体。 时间到了,我会指出为什么这样做很方便,但这将是我在第2点提到的默认值。现在让我们快速地声明在第1点提到的访问回调函数:

/**
 * Access callback for project entities.
 */
function demo_access_callback($op, $project = NULL, $account = NULL) {
  if ($op == 'view' || $op == 'update' || $op == 'create' || $op == 'delete') {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

As you can see, this is not much of an access callback function as it returns true for everything. Here you will normally perform proper access checks but for our demonstration purposes it works just fine.

如您所见,这并不是访问回调函数,因为它对所有内容都返回true。 在这里,您通常会执行适当的访问检查,但是出于演示目的,它可以正常工作。

Now there is one last thing we need to do to make use of our admin interface: declare a simple add/edit form for the project entity and its submit handler:

现在,我们需要做最后一件事来利用我们的管理界面:为项目实体及其提交处理程序声明一个简单的添加/编辑表单:

/**
 * Form definition for adding / editing a project.
 */
function project_form($form, &$form_state, $project = NULL) {

  $form['name'] = array(
    '#title' => t('Project name'),
    '#type' => 'textfield',
    '#default_value' => isset($project->name) ? $project->name : '',
    '#required' => TRUE,
  );

  $form['description'] = array(
    '#title' => t('Project description'),
    '#type' => 'textarea',
    '#default_value' => isset($project->description) ? $project->description : '',
    '#required' => TRUE,
  );

  $form['deadline'] = array(
    '#title' => t('Project deadline'),
    '#type' => 'textfield',
    '#default_value' => isset($project->deadline) ? $project->deadline : '',
    '#required' => TRUE,
  );  

  $form['submit'] = array(
    '#type' => 'submit', 
    '#value' => isset($project->id) ? t('Update project') : t('Save project'),
    '#weight' => 50,
  );

  return $form;
}

/**
 * Submit handler for the project add/edit form.
 */
function project_form_submit($form, &$form_state) {
  $project = entity_ui_form_submit_build_entity($form, $form_state);
  $project->save();
  drupal_set_message(t('The project: @name has been saved.', array('@name' => $project->name)));
  $form_state['redirect'] = 'admin/projects';
}

For the deadline field, I went with a simple text field just to make this demonstration quicker. Normally, you’d want to use the contrib Date module for a nice widget and then save that value as a timestamp. But this will do for our example.

对于deadline字段,我使用了一个简单的文本字段,只是为了使演示更快。 通常,您希望将contrib Date模块用于一个漂亮的小部件,然后将该值保存为时间戳。 但这将为我们的示例所做的。

As for the rest, there is nothing major going on. A few things you should keep in mind though. In order for the Entity API to pick up automatically on the fact that this is the form for the project entities, the declaring function name needs to be exactly that. If the entity type was called chocolate, the function name would have been chocolate_form(). You’ll also notice that we pass the $project entity as a third parameter. This will be handled by the Entity API for the edit form. And finally, in the submit handler, you notice the use of the entity_ui_form_submit_build_entity() function. This is a great helper that will take all the values from the $form_state array (the user input) and populate the entity properties with them.

至于其余的,没有什么大不了的。 不过,您应该记住一些注意事项。 为了使Entity API在项目实体的表单上自动获取,声明函数的名称必须与此完全相同。 如果实体类型称为chocolate ,则函数名称应为chocolate_form() 。 您还会注意到,我们将$project实体作为第三个参数传递。 这将由编辑表单的Entity API处理。 最后,在提交处理程序中,您注意到了entity_ui_form_submit_build_entity()函数的使用。 这是一个很好的帮手,它将从$form_state数组(用户输入)中获取所有值,并使用它们填充实体属性。

And that’s it. We can clear the cache and navigate to http://example.com/admin/projects where we should see a table of our project entities, with links to view, edit and delete them + an additional one for adding new ones.

就是这样。 我们可以清除缓存并导航到http://example.com/admin/projects ,在该处我们应该看到项目实体的表格,其中包含用于查看,编辑和删除它们的链接以及一个用于添加新实体的链接。

Earlier I mentioned that I will let you know why we had to override the Entity class and change the default URI for the entity type. The link Drupal placed behind the project names are generated based on this information. So as long as the path exists, you should now have a full blown CRUD system + pages for displaying individual entities. Not bad.

早先我提到过,我会让您知道为什么我们必须重写Entity类并更改实体类型的默认URI。 基于此信息生成位于项目名称后面的链接Drupal。 因此,只要路径存在,您现在就应该拥有完整的CRUD系统+用于显示单个实体的页面。 不错。

领域 (Fields)

The next thing we’ll see is how to make our entities fieldable. Let’s again edit the hook_entity_info() implementation and add some more information there:

我们将看到的下一件事是如何使我们的实体可域化。 让我们再次编辑hook_entity_info()实现,并在其中添加更多信息:

...

'fieldable' => TRUE,
'bundles' => array(
  'project' => array(
    'label' => t('Project'),
    'admin' => array(
      'path' => 'admin/projects',
    ),
  ),
),

...

In the first line we tell Drupal that this entity type should use fields and in the following lines we define a bundle they can be attached to. Bundles are to what we attach fields in Drupal and any entity type can have multiple bundles. For example, in a fresh Drupal install, the node entity has the article and page bundles (content types).

在第一行中,我们告诉Drupal该实体类型应使用字段,在接下来的几行中,我们定义可以附加到它们的捆绑包。 捆绑包是我们在Drupal中附加字段的对象,任何实体类型都可以具有多个捆绑包。 例如,在全新的Drupal安装中,节点实体具有文章和页面捆绑(内容类型)。

We define a single one, called project and specify some basic information. Now if you clear the cache and go to admin/projects you should see two new tabs at the top of the page resembling what you see when you add fields to regular content types. Now we can add fields to our entity.

我们定义一个project并指定一些基本信息。 现在,如果您清除缓存并转到admin/projects ,则应该在页面顶部看到两个新选项卡,类似于将字段添加到常规内容类型时看到的内容。 现在我们可以将字段添加到我们的实体中。

You’ll also notice that after you add some fields through the UI and try to edit or add a project, you don’t see the fields in the form. That’s because we need to include them. Edit the project_form() function we wrote earlier and right before the submit element, paste the following:

您还将注意到,在通过UI添加一些字段并尝试编辑或添加项目之后,您在窗体中看不到这些字段。 那是因为我们需要包括它们。 编辑我们之前编写的project_form()函数,然后在Submit元素之前,粘贴以下内容:

field_attach_form('project', $project, $form, $form_state);

Using the Field API field_attach_form(), we attach to the form all the necessary elements declared through the UI. Now go to the form again and you should see the new fields. And even on the individual project entity display page the field values get rendered as you configure them through the UI.

使用Field API field_attach_form() ,我们将通过UI声明的所有必要元素附加到表单上。 现在再次转到该表格,您应该看到新字段。 甚至在单个项目实体显示页面上,当您通过UI配置字段值时,它们也会呈现出来。

将实体类型暴露给视图 (Exposing the entity type to Views)

The final thing we’re going to look at is how to expose our project entities to Views. The most basic thing we can do in this respect is to edit the hook_entity_info() implementation and specify another controller class that would handle this functionality:

我们要看的最后一件事是如何向Views公开我们的项目实体。 在这方面,我们可以做的最基本的事情是编辑hook_entity_info()实现,并指定另一个控制器类来处理此功能:

...

'views controller class' => 'EntityDefaultViewsController',

...

Now you can just clear the cache and create a new View. Make sure you choose Project over Content and you’ll have all the entity properties available. One thing to note is that Views cannot interpret the kind of values we are storing in those properties. The deadline field, for instance, is actually a date and not a simple integer. So if you add that field, it will treat it as a simple numeric value.

现在,您只需清除缓存并创建一个新的视图。 确保选择Project Content Project ,并且所有实体属性都可用。 需要注意的一件事是,视图无法解释我们存储在这些属性中的值的类型。 例如, deadline字段实际上是日期,而不是简单的整数。 因此,如果您添加该字段,它将把它当作一个简单的数值。

To fix this, we need to implement hook_entity_property_info() and specify exactly what kind of data the project properties are storing:

为了解决这个问题,我们需要实现hook_entity_property_info()并确切指定项目属性存储的数据类型:

/**
 * Implements hook_entity_property_info().
 */
function demo_entity_property_info() {

  $info = array();

  $info['project']['properties']['id'] = array(
    'label' => t('Project ID'),
    'description' => t('The ID of the project.'),
    'type' => 'integer',
    'schema field' => 'id',
  );

  $info['project']['properties']['name'] = array(
    'label' => t('Project name'),
    'description' => t('Name of the project.'),
    'type' => 'text',
    'schema field' => 'name',
  );
  $info['project']['properties']['description'] = array(
    'label' => t('Project description'),
    'description' => t('Description of the project.'),
    'type' => 'text',
    'schema field' => 'description',
  );
  $info['project']['properties']['deadline'] = array(
    'label' => t('Deadline'),
    'description' => t('Project deadline.'),
    'type' => 'date',
    'schema field' => 'deadline',
  );

  return $info;
}

As you can see, it’s a big nested array situation in which for the project entity we map its properties to their schema column and specify what type of data is found there. Now if you clear the cache and add these fields in your View, Views will know what values are stored in the properties. For the deadline field, it will use its date handler this time and transform the timestamp into a date string for us.

如您所见,这是一个很大的嵌套数组情况,在这种情况下,对于project实体,我们将其属性映射到其架构列并指定在其中找到哪种数据类型。 现在,如果您清除缓存并在视图中添加这些字段,则视图将知道哪些值存储在属性中。 对于deadline字段,这次将使用其日期处理程序,并将时间戳转换为日期字符串。

An important thing to keep in mind when implementing this hook: you cannot do it only for one property. As soon as you implemented and described one of your properties, you need to add the rest as well. Otherwise Views won’t show the rest at all anymore.

实现此挂钩时要记住的重要事项:您不能仅对一个属性执行此操作。 一旦实现并描述了其中一个属性,就还需要添加其余属性。 否则,“查看”将不再显示其余内容。

结论 (Conclusion)

We’ve reached the end of our exploration of Drupal entities. And although we covered quite a lot, there is loads more you can do to perfect and customize your entity types. We’ve seen in this part how to integrate with Views, how to add fields to our entities and even how to create an admin interface for them. But there’s more you can do: view modes, revisions, etc.

我们已经完成了对Drupal实体的探索。 尽管我们进行了很多介绍,但您还有很多工作要做,以完善和自定义实体类型。 我们已经在这一部分中看到了如何与Views集成,如何向我们的实体添加字段,甚至如何为它们创建管理界面。 但是您还可以做更多的事情:查看模式,修订等。

We’ve written some example code and created some awesome functionality. And yes, from a strictly “boy this is a long read” perspective, it was quite intense and complex. But if you take a step back and think about what we achieved with what I guarantee you is almost no code at all, you’ll understand why the Drupal entity system is so great.

我们编写了一些示例代码,并创建了一些很棒的功能。 是的,从严格的“男孩,这是长期阅读”的角度来看,这是非常激烈和复杂的。 但是,如果您退后一步,考虑一下我保证几乎完全没有代码的成就,您将理解为什么Drupal实体系统如此出色。

翻译自: https://www.sitepoint.com/build-custom-drupal-entities/

drupal8 自定义实体

 类似资料: