Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Apress.Pro.Drupal.7.Development.3rd.Edition.Dec.2010.pdf
Скачиваний:
54
Добавлен:
14.03.2016
Размер:
12.64 Mб
Скачать

CHAPTER 3 HOOKS, ACTIONS, AND TRIGGERS

Finally, it is time to write the advanced action itself:

/**

* Configurable action. Beeps a specified number of times. */

function beep_multiple_beep_action($object, $context) { for ($i = 0; $i < $context['beeps']; $i++) {

beep_beep();

}

}

You’ll notice that the action accepts two parameters, $object and $context. This is in contrast to the simple action we wrote earlier, which used no parameters.

Note Simple actions can take the same parameters as configurable actions. Because PHP ignores parameters that are passed to a function but do not appear in the function’s signature, we could simply change the function signature of our simple action from beep_beep_action() to beep_beep_action($object, $context) if we had a need to know something about the current context. All actions are called with the $object and $context parameters.

Using the Context in Actions

We’ve established that the function signature for actions is example_action($object, $context). Let’s examine each of those parameters in detail.

$object: Many actions act on one of Drupal’s built-in objects: nodes, users, taxonomy terms, and so on. When an action is executed by trigger.module, the object that is currently being acted upon is passed along to the action in the $object parameter. For example, if an action is set to execute when a new node is created, the $object parameter will contain the node object.

$context: An action can be called in many different contexts. Actions declare which triggers they support by defining the hooks key in hook_action_info(). But actions that support multiple triggers need some way of determining the context in which they were called. That way, an action can act differently depending on the context.

How the Trigger Module Prepares the Context

Let’s set up a scenario. Suppose you are running a web site that presents controversial issues. Here’s the business model: users pay to register and may leave only a single comment on the web site. Once they have posted their comment, they are blocked and must pay again to get unblocked. Ignoring the economic prospects for such a site, let’s focus on how we could implement this with triggers and actions.

45

CHAPTER 3 HOOKS, ACTIONS, AND TRIGGERS

We will need an action that blocks the current user. Examining user.module, we see that Drupal already provides this action for us:

/**

* Implements hook_action_info(). */

function user_action_info() { return array(

'user_block_user_action' => array( 'label' => t('Block current user'), 'type' => 'user',

'configurable' => FALSE, 'triggers' => array(),

),

);

}

However, this action does not show up on the triggers assignment page, because they do not declare any supported hooks; the triggers key is just an empty array. If only we could change that! But we can.

Changing Existing Actions with action_info_alter()

When Drupal runs the action_info hook so that each module can declare the actions it provides, Drupal also gives modules a chance to modify that information—including information provided by other modules. Here is how we would make the “Block current user” action available to the comment insert trigger:

/**

*Implementation of hook_drupal_alter(). Called by Drupal after

*hook_action_info() so modules may modify the action_info array.

*@param array $info

*The result of calling hook_action_info() on all modules.

*/

function beep_action_info_alter(&$info) {

//Make the "Block current user" action available to the

//comment insert trigger.

if (!in_array("comment_insert", $info['user_block_user_action']['triggers'])) { $info['user_block_user_action']['triggers'][] = 'comment_insert';

}

}

The end result is that the “Block current user action” is now assignable, as shown in Figure 3-6.

46

CHAPTER 3 HOOKS, ACTIONS, AND TRIGGERS

Figure 3-6. Assigning the “Block current user” action to the comment insert trigger

Establishing the Context

Because of the action we have assigned, when a new comment is posted, the current user will be blocked. Let’s take a closer look at how that happens. We already know that Drupal’s way of notifying modules that certain events are happening is to fire a hook. In this case, it is the comment hook. The particular operation that is happening is the insert operation, since a new comment is being added. The trigger module implements the comment hook. Inside this hook, it asks the database if there are any actions assigned to this particular trigger. The database gives it information about the “Block current user” action that we assigned. Now the trigger module gets ready to execute the action, which has the standard action function signature example_action($object, $context).

But we have a problem. The action that is about to be executed is an action of type user, not comment. It expects the object it receives to be a user object! But here, a user action is being called in the context of a comment hook. Information about the comment was passed to the hook, not information about the user. What should we do? What actually happens is that the trigger module determines that our action is a user action and loads the $user object that a user action expects. Here is code from modules/trigger/trigger.module that shows how this happens:

47

CHAPTER 3 HOOKS, ACTIONS, AND TRIGGERS

/**

*Loads associated objects for comment triggers.

*When an action is called in a context that does not match its type, the

*object that the action expects must be retrieved. For example, when an action

*that works on nodes is called during the comment hook, the node object is not

*available since the comment hook doesn't pass it. So here we load the object

*the action expects.

*

*@param $type

*The type of action that is about to be called.

*@param $comment

*The comment that was passed via the comment hook.

*@return

*The object expected by the action that is about to be called.

*/

function _trigger_normalize_comment_context($type, $comment) { switch ($type) {

//An action that works with nodes is being called in a comment context. case 'node':

return node_load(is_array($comment) ? $comment['nid'] : $comment->nid);

//An action that works on users is being called in a comment context. case 'user':

return user_load(is_array($comment) ? $comment['uid'] : $comment->uid);

}

}

When the preceding code executes for our user action, the second case matches so the user object is loaded and then our user action is executed. The information that the comment hook knows about (for example, the comment’s subject) is passed along to the action in the $context parameter. Note how the action looks for the user’s ID first in the object and then the context, and finally falls back to the global $user:

/**

*Blocks the current user.

*@ingroup actions

*/

function user_block_user_action(&$entity, $context = array()) { if (isset($entity->uid)) {

$uid = $entity->uid;

}

elseif (isset($context['uid'])) { $uid = $context['uid'];

}

else {

global $user; $uid = $user->uid;

}

48

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]