Chinaunix首页 | 论坛 | 博客
  • 博客访问: 72663
  • 博文数量: 29
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 345
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-01 17:24
文章分类
文章存档

2011年(1)

2008年(28)

我的朋友
最近访客

分类:

2008-10-31 15:30:03

How do I create a new action?

There are two steps. First, we must describe the action to Drupal using hook_action_info(). Then, we must actually write the code that will execute.

Describing an action with hook_action_info()

Let's take a look at the user module's implementation of hook_action_info():


/**
* Implementation of hook_action_info().
*/
function user_action_info
() {
  return array(
   
'user_block_user_action'
=> array(
     
'description' => t('Block current user'
),
     
'type' => 'user'
,
     
'configurable' => FALSE
,
     
'hooks'
=> array(
       
'nodeapi' => array('presave', 'delete', 'insert', 'update', 'view'
),
       
'comment' => array('view', 'insert', 'update', 'delete'
),
       
'user' => array('logout'
),
        ),
      ),
   
'user_block_ip_action'
=> array(
     
'description' => t('Ban IP address of current user'
),
     
'type' => 'user'
,
     
'configurable' => FALSE
,
     
'hooks'
=> array(
       
'nodeapi' => array('presave', 'delete', 'insert', 'update', 'view'
),
       
'comment' => array('view', 'insert', 'update', 'delete'
),
       
'user' => array('logout'
),
      )
    ),
  );
}
?>

hook_action_info() must return an array, keyed by the function names of the actions being described. In user.module, we are describing two actions. We'll focus on the first one. The array key of the first action being described is 'user_block_user_action'. That's the name of the function that will actually be executed when this action runs. The name of the function is constructed by using the following convention:

modulename + description of what the function does + '_action'

In this case it is

user + block user + action

which gives us 'user_block_user_action'.

Next, we need to provide some information in the array using the following keys:

description: an easy-to-understand description of what the action does

type: the type is determined by what object the action acts on. Possible choices are node, user, comment, and system. Or your own custom type.

configurable: TRUE or FALSE. This determines the interface that Drupal will use when configuring actions. When set to FALSE we have the simplest case, where there is no interface to configure the action. In our example, the "Block current user" action does not need any additional information since the current user can be easily determined by Drupal at runtime. A more complicated action, such as a "Send email" action, would need to know things like who to send the email to, what to put in the subject line and the body of the email, etc.

hooks: this is an array of all of the operations this action is appropriate for, keyed by hook name. The actions module uses this to filter out inappropriate actions when presenting the interface for assigning actions to events. For example, the "Block current user" action defines the 'logout' operation of the 'user' hook, but not the 'login' operation. That's because it would be kind of silly to block a user as soon as the user logged in. It should be noted that this is an interface issue only; Drupal does not enforce these restrictions on execution of actions. Note: if you are writing actions in your own modules and you simply want to declare support for all possible hooks, you can set 'hooks' => array('any' => TRUE).

Writing an action

Now that we've described the action to Drupal, we can write the actual code that runs when the action is executed. Let's look at the code for the "Block current user" action:

/**
* Implementation of a Drupal action.
* Blocks the current user.
*/
function user_block_user_action(&$object, $context
= array()) {
  if (isset(
$object->uid
)) {
   
$uid = $object->uid
;
  }
  elseif (isset(
$context['uid'
])) {
   
$uid = $context['uid'
];
  }
  else {
    global
$user
;
   
$uid = $user->uid
;
  }
 
db_query("UPDATE {users} SET status = 0 WHERE uid = %d", $uid
);
 
sess_destroy_uid($uid
);
 
watchdog('action', 'Blocked user %name.', array('%name' => check_plain($user->name
)));
}
?>

First, let's look at the function signature for the action. Two parameters are passed, an object and an array.

$object: this is the object on which the action expects to act. It corresponds with the 'type' that was declared for this action in hook_action_info(). For example, if the type 'user' was declared, the action will be passed a user object.

$context: this is an array that contains additional information that may be helpful for the action to look at to determine the context under which the action is currently running. For example, the actions module sets the 'hook' and 'op' keys of the context array (e.g., 'hook' may be 'nodeapi' and 'op' may be 'insert') so that the action can examine them and make various decisions if necessary.

Next, let's look at the action itself. It really has two parts. First, it determines the user to block by first looking at the user object it has been passed; failing that, it looks in the context array for the uid; failing that, it uses the global $user to determine the uid to block itself. Some of you may be curious about this. Why have these fallback positions? Why not require the passage of the "correct" first parameter? The answer is twofold. First, with actions we want a function signature that is universal so the underlying actions engine has to do less work, so we can have better performance. Second, suppose you want to block 50 users. Doing a full user_load() on each one just to get an object you can pass to an action is not performant when you can hand over the uid in the context array instead.

The second part of the action is where the user is actually blocked and a watchdog entry recorded.

Now you know how to make a nonconfigurable action. A configurable action must also provide form handlers in order for the administrator to set the action's stored parameters. Look at the "Unpublish comment containing keyword(s)" action in comment.module for an example, specifically at the functions comment_unpublish_by_keyword_action_form(), comment_unpublish_by_keyword_action_submit(), and comment_unpublish_by_keyword_action().

I've written a module that provides hooks. How can I assign actions to run when those hooks run?

Use hook_hook_info() to describe your hooks to Drupal. This hook associates hook-op combinations with easy-to-read descriptions. See node_hook_info() or comment_hook_info() or user_hook_info() for examples.

I want to execute an action but I don't want to use actions.module.

OK. You can run any action directly from code by using the actions_do() function, which lives in includes/actions.inc.

阅读(763) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~