# Drupal 7中每个节点有多个编辑器

One of the things that makes Drupal great is its flexible user permission system. The out of the box permissions grid we are all familiar with covers most uses cases of controlling what users can and cannot do. It is also very easy for module developers to create new permissions and roles that restrict the logic they implement.

Nevertheless, I have encountered a practical use case where the default configuration options are not enough. Namely, if you need to have multiple users with access to edit a particular node of a given type but without them necessarily having access to edit others of the same type. In other words, the next great article should be editable by Laura and Glenn but not by their colleagues. However, out of the box, users of a particular role can be masters either of their own content or of all content of a certain type. So this is not immediately possible.

In this article I am going to show you my solution to this problem in the form of a simple custom module called editor_list. Article nodes will have a field where you can select users and only these users (or those who have full access) will be able to edit that particular node. You can find the module already in this git repository and you can install it on your site for a quick start. Do keep in mind that it has a dependency on the Entity Reference module as we will see in a minute.

I will keep the code comments to a minimum to save space but you can find them in the repository if you want. Basic knowledge of Drupal 7 is assumed in the remainder of this tutorial.

## 脚手架 (Scaffolding)

We first need the editor_list.info file for our module to get us going:

name = Editor List
description = Module illustrating a custom solution for having multiple editors on a node.
core = 7.x
dependencies[] = entityreference

Next, we need our editor_list.module file where most of our business logic will be located. So go ahead and create it and we will populate it as we go on.

Finally, though not covered here, we can have an editor_list.install file where we can implement hook_install() and hook_update hooks to create fields and/or deploy configuration. In the repository, you’ll find that I provided an install hook that already creates an entity reference field called field_editors and attaches it to the Article content type. If you are following along but not using the code in the repository, you should go ahead and create the field manually through the UI. It’s a simple field that references User entities and allows for unlimited selections. Nothing major.

## 节点访问 (Node access)

Going back to our .module file, it’s time to implement our access logic. First though, to make things as flexible and reusable as possible, let’s have a simple function that returns an array of node types to which we apply our access logic:

function editor_list_node_types() {
return array('article');
}

Since we are only targeting articles, this will suffice. But we will use this function in multiple places so in case we need to target other types as well, we just have to update this array.

Next, let’s write another helpful function that returns all the user IDs set in the editors field of a given node. We will also use this in multiple places:

function editor_list_uids_from_list($node) {$users = field_get_items('node', $node, 'field_editors');$allowed_uids = array();
if ($users) {$allowed_uids = array_map(function($user) { return$user['target_id'];
}, $users); } return$allowed_uids;
}

I believe the function is quite self explanatory so I won’t go into details here. Instead, we can turn to our hook_node_access() implementation that gets called by Drupal whenever a user tries to do something with a node (view, edit or delete):

/**
* Implements hook_node_access().
*/
function editor_list_node_access($node,$op, $account) {$node_types = editor_list_node_types();

if ( ! is_object($node) || ! in_array($node->type, $node_types) ||$op !== 'update') {
return NODE_ACCESS_IGNORE;
}

$allowed_uids = editor_list_uids_from_list($node);

if (empty($allowed_uids)) { return NODE_ACCESS_IGNORE; } if (in_array($account->uid, $allowed_uids)) { return NODE_ACCESS_ALLOW; } } So what’s happening here? 那么这是怎么回事？ First, we use our previously declared helper function to get the list of node types we want to target, and we basically ignore the situation and return if the node type of the currently accessed node is not within our list or if the operation the user is attempting is not of the type “update”. Then we use our other helper function to check if there are any users in the editor list for this node and again ignore the situation if there aren’t. However, if there are, and our accessing user is among them, we return the NODE_ACCESS_ALLOW constant which basically gives the user access to perform the attempted operation. And that’s it. 首先，我们使用先前声明的helper函数来获取要定位的节点类型的列表，并且如果当前访问的节点的节点类型不在我们的列表中或者用户的操作是否在列表中，则我们基本上会忽略这种情况并返回尝试的类型不是“更新”。 然后，我们使用其他帮助器功能来检查该节点的编辑器列表中是否有任何用户，如果没有，则再次忽略该情况。 但是，如果有，并且正在访问的用户在其中，我们将返回NODE_ACCESS_ALLOW常量，该常量基本上使用户能够执行尝试的操作。 就是这样。 You can check out the documentation for more information about how this hook works. 您可以查看文档以获取有关此挂钩如何工作的更多信息。 Let’s say you have admin users who can create and edit any type of content and regular authenticated users who cannot edit articles (apart from maybe the ones they created themselves). Adding one of these latter users to a node’s editor list would give them access to that particular node. And another great thing is that since this is all nicely integrated, contextual filters and tabs also take these dynamic permissions into account. 假设您有可以创建和编辑任何类型的内容的管理员用户，以及不能编辑文章(可能是他们自己创建的文章)的常规身份验证用户。 将这些用户之一添加到节点的编辑器列表中，将使他们能够访问该特定节点。 另一个很棒的事情是，由于这一切都很好地集成在一起，因此上下文过滤器和选项卡也将这些动态权限考虑在内。 ## 现场访问 (Field access) We now have a working module that does what I initially set out for it to do. But let’s say that your admin users are the only ones responsible for adding users to the editor lists. In other words, you are afraid that if your editors can edit their nodes and remove themselves from the list, they’ll get locked out of the node they are supposed to work on. 现在，我们有一个工作模块，该模块可以完成我最初打算要做的事情。 但是，假设您的管理员用户是唯一负责将用户添加到编辑器列表的用户。 换句话说，您担心如果您的编辑者可以编辑其节点并将其从列表中删除，他们将被锁定在他们应该处理的节点之外。 To account for this situation, we need to implement a field access check and remove the possibility that editors tamper with that field. Implementing hook_field_access should do the trick nicely. And if you are wondering, this hook is similar to hook_node_access() but is responsible for individual fields rather than the entire node (+ a couple of other small differences). 为了解决这种情况，我们需要实施字段访问检查，并消除编辑者篡改该字段的可能性。 实现hook_field_access应该很好。 而且，如果您想知道，该钩子类似于hook_node_access()但它负责单个字段而不是整个节点(加上一些其他小的区别)。 /** * Implements hook_field_access(). */ function editor_list_field_access($op, $field,$entity_type, $entity,$account) {
$node_types = editor_list_node_types(); if ($entity_type === 'node' && is_object($entity) && in_array($entity->type, $node_types)) { return editor_list_control_field_access($op, $field,$entity_type, $entity,$account);
}
}

And here we have it. There are a few more parameters because this hook gets called for all entities, not just nodes. But again, we check if the currently accessed node is one of those we defined earlier (and that the entity is in fact a node) and this time delegate to another function to keep things tidier:

function editor_list_control_field_access($op,$field, $entity_type,$entity, $account) { if ($op !== 'edit') {
return;
}

$uids = editor_list_uids_from_list($entity);
if (!in_array($account->uid,$uids)) {
return;
}

$deny = array('field_editors'); if (in_array($field['field_name'], $deny)) { return false; } }} Since we only care if the user is trying to update a particular field, we return nothing if this is not the case. Keep in mind that the op string here is edit and not update as it was in the other hook. This is just one of those Drupal quirks of inconsistency we all came to love so much. And like before, we ignore the situation if the current user is not part of the editor list. 由于我们只关心用户是否尝试更新特定字段，因此如果不是这种情况，我们将不返回任何内容。 请记住，此处的操作字符串是可edit ，不会像在另一个挂钩中那样进行update 。 这只是我们所有人都非常喜欢的那些Drupal不一致的怪癖之一。 和以前一样，如果当前用户不属于编辑器列表，我们将忽略这种情况。 Then, we define an array of field names we want to deny access to (in our case only one but we can add to it depending on the use case). Finally, we return false if the currently accessed field is part of our $deny array. Yet another difference here in that we have to return a boolean instead of a constant like we did before.

$form['#after_build'][] = 'editor_list_node_form_after_build'; } We went with the BASE_FORM_ID of the article nodes here so if we extend our application to other types we would do the same for those as well. Inside, we just define an #after_build function to be triggered when the form has finished building. This is to ensure all the form alterations have been already done by contributed modules. All that is left to be done is to write the function responsible for making changes to the form: 我们在这里使用了BASE_FORM_ID节点的BASE_FORM_ID ，因此，如果将应用程序扩展到其他类型，我们也将对它们进行同样的处理。 在内部，我们仅定义一个#after_build函数，当表单完成构建时将触发该函数。 这是为了确保所有表单更改都已由贡献模块完成。 剩下要做的就是编写负责更改表单的函数： function editor_list_node_form_after_build($form, &$form_state) {$field = field_info_field('field_editors');
if ( ! field_access('edit', $field, 'node',$form['#entity'])) {
return $form; } if ($form['author']['#access'] === 0) {
return $form; }$field_editors = $form['field_editors'];$field_editors['#weight'] = 0;
$form['author']['additional_authors'] =$field_editors;
$form['field_editors'] = array(); return$form;
}

This looks complicated but it really isn’t. We begin by loading the field definition of our editor list field. This is so that we can run the field_access check on it and just return the form array unchanged if the current user doesn’t have access to the field. Next, we do the same if the current user does not have access to the author group on the form (this is the Authoring information group we want to place the field into). And lastly, we make a copy of the field definition, change its weight and place it into the group, followed by unsetting the original definition to avoid having duplicates.

And that is pretty much it. Now the editors list field should be tucked in with the rest of the information related to authorship.

## 结论 (Conclusion)

In this article, we created a solution to a content editing problem that Drupal 7 could not fix out of the box. However, it did provide us with the development tools necessary to make this an easy task inside of a custom module.

We now have an editor list field on the article node form by which we can specify exactly which users have access to that particular node. Though do keep in mind that in order for this to be of any use, the users you add to these lists must not have a role that allows them to edit all article nodes. Otherwise you won’t see much of a difference.

• 0
点赞
• 0
收藏 更改收藏夹
• 0
评论
06-24 90
07-31 1077
02-16 561
12-12 66
04-05 6142
09-11 8万+
03-28 3279
10-23 760

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。