作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
我们再来看一个例子,批量删除模块batchdelete,这个模块主要用来批量删除节点的,还可以删除自定义区块、词汇表,不过后面两者的删除,没有用到批处理机制。
我们来看一下代码,菜单项定义:
function batchdelete_menu() {
$items['admin/config/development/batchdelete'] = array(
'title' => 'Batch delete node',
'page callback' => 'drupal_get_form',
'page arguments' => array('batchdelete_form'),
'access arguments' => array('administer site configuration'),
'weight' => 1,
'type' => MENU_NORMAL_ITEM,
);
$items['admin/config/development/batchdelete/node'] = array(
'title' => 'Batch delete node',
'page callback' => 'drupal_get_form',
'page arguments' => array('batchdelete_form'),
'access arguments' => array('administer site configuration'),
'weight' => 1,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/config/development/batchdelete/block'] = array(
'title' => 'Batch delete block',
'page callback' => 'drupal_get_form',
'page arguments' => array('batchdelete_block_form'),
'access arguments' => array('administer site configuration'),
'weight' => 2,
'type' => MENU_LOCAL_TASK,
);
$items['admin/config/development/batchdelete/taxonomy'] = array(
'title' => 'Batch delete taxonomy term',
'page callback' => 'drupal_get_form',
'page arguments' => array('batchdelete_taxonomy_form'),
'access arguments' => array('administer site configuration'),
'weight' => 3,
'type' => MENU_LOCAL_TASK,
);
return $items;
}
这里我们为节点、区块、分类,分别定义了一个菜单项,我们来看一下,节点的删除代码。
function batchdelete_form(){
$options = array();
$types = node_type_get_types();
foreach ($types as $key => $values) {
$options[$key] = $values->name;
}
$form['types'] = array(
'#title' => t('Content types to be delete'),
'#type' =>'checkboxes',
'#description' =>t('All nodes of these selected types will be deleted'),
'#options' => $options,
);
$form['submit'] = array(
'#type' =>'submit',
'#value' => t('Delete'),
);
return $form;
}
function batchdelete_form_submit($form,&$form_state){
$types = array_filter($form_state['values']['types']);
$batch =array(
'operations' => array(
array('batchdelete_node_process', array($types)),
),
'finished' => 'batchdelete_node_finished',
'title' => t('删除节点'),
'init_message' => t('开始批量删除.'),
//'progress_message' => t('Reindexed @current out of @total.'),
'error_message' => t('批量删除遇到错误.'),
);
batch_set($batch);
}
function batchdelete_node_process($types, &$context){
$size =100;
//$types_str ='story,page';
//$types_str = "'".implode("','", $types)."'";
//drupal_set_message('types:'.print_r($types));
//debug($types);
if(!isset($context['sandbox']['progress'])){
$context['sandbox']['progress'] = 0;
$context['sandbox']['max'] = db_select('node', 'n')
->condition('n.type', $types, 'IN')
->countQuery()
->execute()
->fetchField();
//drupal_set_message('max:'.$context['sandbox']['max']);
}
//$sql = "SELECT nid FROM {node} WHERE type in ($types_str)";
//$result = db_query_range($sql,0,$size);
$query =db_select('node', 'n')
->fields('n', array('nid'))
->condition('n.type', $types, 'IN')
->range(0, $size);
$result = $query->execute();
foreach ($result as $record) {
//drupal_set_message('123max:'.$result->nid);
node_delete($result->nid);
$context['sandbox']['progress']++;
//$context['message'] = t('删除节点 %nid',array('%nid' => $node['nid']));
}
if($context['sandbox']['progress'] ==$context['sandbox']['max']){
$context['finished'] = 1;
}else{
$context['finished'] = $context['sandbox']['progress']/$context['sandbox']['max'];
}
}
function batchdelete_node_finished($success, $results, $operations){
if ($success) {
// Here we do something meaningful with the results.
$message = t('节点删除完成');
}
else {
// An error occurred.
// $operations contains the operations that remained unprocessed.
$error_operation = reset($operations);
$message = '在删除节点时出现一个错误'. $error_operation[0] .' 其参数为 :'. print_r($error_operation[0], TRUE);
}
drupal_set_message($message);
}
这段代码,和我们前面第一个例子非常类似,其实我们第一个例子里面的代码,就是从这个模块复制过来的。而batchdelete模块,则是从Drupal6下面升级过来的,我们最初编写的是Drupal6下面的,现在升级到了Drupal7。升级的过程中,就遇到了向批处理的处理函数中传递参数的问题,batchdelete_node_process,$types最初是放在后面的,结果后来发现了问题,调试了多次,我们可以看到代码里面还有很多的调试信息,最后才发现参数的顺序问题。
删除自定义区块的代码,还没有升级过来。我们看一下删除词汇表的:
function batchdelete_taxonomy_form(){
$options=array();
$vocabs = taxonomy_get_vocabularies();
foreach($vocabs as $vocab){
$options[$vocab->vid] = $vocab->name;
}
$form['vids'] = array(
'#title' => t('要删除的分类词汇表ID'),
'#type' =>'checkboxes',
'#description' =>t('请选择哪些分类词汇表要被删除。'),
'#options' => $options,
);
$form['submit'] = array(
'#type' =>'submit',
'#value' => t('Delete'),
);
return $form;
}
function batchdelete_taxonomy_form_submit($form,&$form_state){
$vids = array_filter($form_state['values']['vids']);
foreach($vids as $vid){
//taxonomy_del_vocabulary($vid);
$transaction = db_transaction();
try {
// Only load terms without a parent, child terms will get deleted too.
$result = db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid = :vid AND th.parent = 0', array(':vid' => $vid))->fetchCol();
foreach ($result as $tid) {
taxonomy_term_delete($tid);
}
return SAVED_DELETED;
}
catch (Exception $e) {
$transaction->rollback();
watchdog_exception('taxonomy', $e);
throw $e;
}
}
}
我们这里面删除的是词汇表下面的所有分类术语,而没有删除词汇表本身。taxonomy_get_vocabularies,用来获取所有的词汇表;taxonomy_del_vocabulary可以用来删除词汇表,taxonomy_term_delete用来删除分类术语。我们这里在删除的过程中,使用了事务处理,它的代码结构大致是这样的:
$transaction = db_transaction();
try {
//做一些操作.
}
catch (Exception $e) {
$transaction->rollback();
watchdog_exception('taxonomy', $e);
throw $e;
}
其实在编写好batchdelete的最初版本后,发现drupal.org上面有个类似的模块,Bulk delete,也是Drupal6下面的模块,我的模块比它晚写了三个月,所以编写的时候,没有注意到,已经存在这样一个模块了。不过,现在Bulk delete模块已经不再维护,为什么呢?因为VBO模块的存在。