contrib modules security updates
This commit is contained in:
@@ -18,6 +18,7 @@ function views_bulk_operations_archive_action_info() {
|
||||
// "Create an advanced action" dropdown on admin/config/system/actions.
|
||||
'configurable' => FALSE,
|
||||
'vbo_configurable' => TRUE,
|
||||
'behavior' => array('views_property'),
|
||||
'triggers' => array('any'),
|
||||
);
|
||||
}
|
||||
|
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements actions for managing books (book.module).
|
||||
*/
|
||||
|
||||
function views_bulk_operations_book_action_info() {
|
||||
$actions = array();
|
||||
if (module_exists('book')) {
|
||||
$actions['views_bulk_operations_move_to_book_action'] = array(
|
||||
'type' => 'node',
|
||||
'label' => t('Move to book'),
|
||||
'configurable' => TRUE,
|
||||
'behavior' => array('changes_property'),
|
||||
'triggers' => array('any'),
|
||||
);
|
||||
$actions['views_bulk_operations_remove_from_book_action'] = array(
|
||||
'type' => 'node',
|
||||
'label' => t('Remove from book'),
|
||||
'configurable' => FALSE,
|
||||
'triggers' => array('any'),
|
||||
);
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
function views_bulk_operations_move_to_book_action_form($context) {
|
||||
$form = array();
|
||||
if (!isset($context['book'])) {
|
||||
$context['book'] = '';
|
||||
}
|
||||
$options = array();
|
||||
$books = book_get_books();
|
||||
foreach ($books as $value) {
|
||||
$options[$value['nid']] = $value['title'];
|
||||
}
|
||||
|
||||
if (empty($options)) {
|
||||
drupal_set_message(t('You have no books.'), 'error');
|
||||
return array();
|
||||
}
|
||||
|
||||
$form['book'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Choose a parent book'),
|
||||
'#options' => $options,
|
||||
'#description' => t('Select the parent book page you wish to move the book page into'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
function views_bulk_operations_move_to_book_action_submit($form, $form_state) {
|
||||
return array('book' => $form_state['values']['book']);
|
||||
}
|
||||
|
||||
function views_bulk_operations_move_to_book_action($node, $context = array()) {
|
||||
if (isset($context['book'])) {
|
||||
$book_node = node_load($context['book']);
|
||||
$mlid = db_select('menu_links' , 'ml')
|
||||
->condition('ml.link_path' , 'node/' . $node->nid)
|
||||
->fields('ml' , array('mlid'))
|
||||
->execute()
|
||||
->fetchField();
|
||||
$node->book['mlid'] = $mlid;
|
||||
$node->book['bid'] = $book_node->nid;
|
||||
$node->book['plid'] = $book_node->book['mlid'];
|
||||
$node->book['module'] = 'book';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the action 'Remove node from a parent book'
|
||||
*/
|
||||
function views_bulk_operations_remove_from_book_action($node, $context) {
|
||||
$book = $node->book['mlid'];
|
||||
book_node_delete($node);
|
||||
}
|
@@ -14,6 +14,13 @@ function views_bulk_operations_delete_action_info() {
|
||||
'behavior' => array('deletes_property'),
|
||||
'triggers' => array('any'),
|
||||
),
|
||||
'views_bulk_operations_delete_revision' => array(
|
||||
'type' => 'entity',
|
||||
'label' => t('Delete revision'),
|
||||
'configurable' => FALSE,
|
||||
'behavior' => array('deletes_property'),
|
||||
'triggers' => array('any'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,3 +30,9 @@ function views_bulk_operations_delete_item($entity, $context) {
|
||||
|
||||
entity_delete($context['entity_type'], $entity_id);
|
||||
}
|
||||
|
||||
function views_bulk_operations_delete_revision($entity, $context) {
|
||||
$info = entity_get_info($context['entity_type']);
|
||||
$revision_id = $entity->{$info['entity keys']['revision']};
|
||||
entity_revision_delete($context['entity_type'], $revision_id);
|
||||
}
|
||||
|
@@ -29,15 +29,19 @@ function views_bulk_operations_modify_action_info() {
|
||||
*/
|
||||
function views_bulk_operations_modify_action($entity, $context) {
|
||||
list(,,$bundle_name) = entity_extract_ids($context['entity_type'], $entity);
|
||||
|
||||
// Handle Field API fields.
|
||||
if (!empty($context['selected']['bundle_' . $bundle_name])) {
|
||||
// The pseudo entity is cloned so that changes to it don't get carried
|
||||
// over to the next execution.
|
||||
$pseudo_entity = clone $context['entities'][$bundle_name];
|
||||
foreach ($context['selected']['bundle_' . $bundle_name] as $key) {
|
||||
// Get this field's language. We can just pull it from the pseudo entity
|
||||
// as it was created using field_attach_form and entity_language so it's
|
||||
// already been figured out if this field is translatable or not and
|
||||
// applied the appropriate language code to the field
|
||||
$language = key($pseudo_entity->{$key});
|
||||
// Replace any tokens that might exist in the field columns.
|
||||
foreach ($pseudo_entity->{$key}[LANGUAGE_NONE] as $delta => &$item) {
|
||||
foreach ($pseudo_entity->{$key}[$language] as $delta => &$item) {
|
||||
foreach ($item as $column => $value) {
|
||||
if (is_string($value)) {
|
||||
$item[$column] = token_replace($value, array($context['entity_type'] => $entity), array('sanitize' => FALSE));
|
||||
@@ -46,11 +50,11 @@ function views_bulk_operations_modify_action($entity, $context) {
|
||||
}
|
||||
|
||||
if (in_array($key, $context['append']['bundle_' . $bundle_name]) && !empty($entity->$key)) {
|
||||
$entity->{$key}[LANGUAGE_NONE] = array_merge($entity->{$key}[LANGUAGE_NONE], $pseudo_entity->{$key}[LANGUAGE_NONE]);
|
||||
$entity->{$key}[$language] = array_merge($entity->{$key}[$language], $pseudo_entity->{$key}[$language]);
|
||||
|
||||
// Check if we breached cardinality, and notify the user.
|
||||
$field_info = field_info_field($key);
|
||||
$field_count = count($entity->{$key}[LANGUAGE_NONE]);
|
||||
$field_count = count($entity->{$key}[$language]);
|
||||
if ($field_info['cardinality'] != FIELD_CARDINALITY_UNLIMITED && $field_count > $field_info['cardinality']) {
|
||||
$entity_label = entity_label($context['entity_type'], $entity);
|
||||
$warning = t('Tried to set !field_count values for field !field_name that supports a maximum of !cardinality.',
|
||||
@@ -59,9 +63,14 @@ function views_bulk_operations_modify_action($entity, $context) {
|
||||
'!cardinality' => $field_info['cardinality']));
|
||||
drupal_set_message($warning, 'warning', FALSE);
|
||||
}
|
||||
|
||||
// Prevent storing duplicate references.
|
||||
if (strpos($field_info['type'], 'reference') !== FALSE) {
|
||||
$entity->{$key}[$language] = array_unique($entity->{$key}[LANGUAGE_NONE], SORT_REGULAR);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$entity->$key = $pseudo_entity->$key;
|
||||
$entity->{$key}[$language] = $pseudo_entity->{$key}[$language];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +82,11 @@ function views_bulk_operations_modify_action($entity, $context) {
|
||||
// The wrapper will automatically modify $entity itself.
|
||||
$wrapper = entity_metadata_wrapper($context['entity_type'], $entity);
|
||||
foreach ($context['selected']['properties'] as $key) {
|
||||
if (!$wrapper->$key->access('update')) {
|
||||
// No access.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($key, $context['append']['properties'])) {
|
||||
$old_values = $wrapper->$key->value();
|
||||
$wrapper->$key->set($context['properties'][$key]);
|
||||
@@ -125,7 +139,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
if (!empty($properties)) {
|
||||
$form['properties'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => 'Properties',
|
||||
'#title' => t('Properties'),
|
||||
);
|
||||
$form['properties']['show_value'] = array(
|
||||
'#suffix' => '<div class="clearfix"></div>',
|
||||
@@ -148,6 +162,11 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
),
|
||||
),
|
||||
);
|
||||
// The default #maxlength for textfields is 128, while most varchar
|
||||
// columns hold 255 characters, which makes it a saner default here.
|
||||
if ($determined_type == 'textfield') {
|
||||
$form['properties'][$key]['#maxlength'] = 255;
|
||||
}
|
||||
|
||||
if (!empty($property['options list'])) {
|
||||
$form['properties'][$key]['#type'] = 'select';
|
||||
@@ -170,6 +189,8 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
}
|
||||
}
|
||||
|
||||
// Going to need this for multilingual nodes
|
||||
global $language;
|
||||
foreach ($bundles as $bundle_name => $bundle) {
|
||||
$bundle_key = $info['entity keys']['bundle'];
|
||||
$default_values = array();
|
||||
@@ -177,6 +198,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
if (!empty($bundle_key)) {
|
||||
$default_values[$bundle_key] = $bundle_name;
|
||||
}
|
||||
$default_values['language'] = $language->language;
|
||||
$entity = entity_create($context['entity_type'], $default_values);
|
||||
$form_state['entities'][$bundle_name] = $entity;
|
||||
|
||||
@@ -195,7 +217,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
'#title' => $label,
|
||||
'#parents' => array($form_key),
|
||||
);
|
||||
field_attach_form($context['entity_type'], $entity, $form[$form_key], $form_state, LANGUAGE_NONE);
|
||||
field_attach_form($context['entity_type'], $entity, $form[$form_key], $form_state, entity_language($context['entity_type'], $entity));
|
||||
// Now that all the widgets have been added, sort them by #weight.
|
||||
// This ensures that they will stay in the correct order when they get
|
||||
// assigned new weights.
|
||||
@@ -206,8 +228,10 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
$weight = 0;
|
||||
foreach (element_get_visible_children($form[$form_key]) as $field_name) {
|
||||
// For our use case it makes no sense for any field widget to be required.
|
||||
$language = $form[$form_key][$field_name]['#language'];
|
||||
_views_bulk_operations_modify_action_unset_required($form[$form_key][$field_name][$language]);
|
||||
if (isset($form[$form_key][$field_name]['#language'])) {
|
||||
$field_language = $form[$form_key][$field_name]['#language'];
|
||||
_views_bulk_operations_modify_action_unset_required($form[$form_key][$field_name][$field_language]);
|
||||
}
|
||||
|
||||
// The admin has specified which fields to display, but this field didn't
|
||||
// make the cut. Hide it with #access => FALSE and move on.
|
||||
@@ -216,32 +240,34 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field = $instances[$field_name];
|
||||
$form[$form_key]['show_value'][$field_name] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $field['label'],
|
||||
);
|
||||
$form[$form_key][$field_name]['#states'] = array(
|
||||
'visible' => array(
|
||||
'#edit-bundle-' . str_replace('_', '-', $bundle_name) . '-show-value-' . str_replace('_', '-', $field_name) => array('checked' => TRUE),
|
||||
),
|
||||
);
|
||||
// All field widgets get reassigned weights so that additional elements
|
||||
// added between them (such as "_append") can be properly ordered.
|
||||
$form[$form_key][$field_name]['#weight'] = $weight++;
|
||||
|
||||
$field_info = field_info_field($field_name);
|
||||
if ($field_info['cardinality'] != 1) {
|
||||
$form[$form_key]['_append::' . $field_name] = array(
|
||||
if (isset($instances[$field_name])) {
|
||||
$field = $instances[$field_name];
|
||||
$form[$form_key]['show_value'][$field_name] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Add new value(s) to %label, instead of overwriting the existing values.', array('%label' => $field['label'])),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
'#edit-bundle-' . str_replace('_', '-', $bundle_name) . '-show-value-' . str_replace('_', '-', $field_name) => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
'#weight' => $weight++,
|
||||
'#title' => $field['label'],
|
||||
);
|
||||
$form[$form_key][$field_name]['#states'] = array(
|
||||
'visible' => array(
|
||||
'#edit-bundle-' . str_replace('_', '-', $bundle_name) . '-show-value-' . str_replace('_', '-', $field_name) => array('checked' => TRUE),
|
||||
),
|
||||
);
|
||||
// All field widgets get reassigned weights so that additional elements
|
||||
// added between them (such as "_append") can be properly ordered.
|
||||
$form[$form_key][$field_name]['#weight'] = $weight++;
|
||||
|
||||
$field_info = field_info_field($field_name);
|
||||
if ($field_info['cardinality'] != 1) {
|
||||
$form[$form_key]['_append::' . $field_name] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Add new value(s) to %label, instead of overwriting the existing values.', array('%label' => $field['label'])),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
'#edit-bundle-' . str_replace('_', '-', $bundle_name) . '-show-value-' . str_replace('_', '-', $field_name) => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
'#weight' => $weight++,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +303,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) {
|
||||
$token_type = str_replace('_', '-', $entity_type);
|
||||
$form['tokens'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => 'Available tokens',
|
||||
'#title' => t('Available tokens'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#weight' => 998,
|
||||
@@ -411,8 +437,12 @@ function _views_bulk_operations_modify_action_get_properties($entity_type, $disp
|
||||
// List of supported types.
|
||||
$supported_types = array('text', 'token', 'integer', 'decimal', 'date', 'duration',
|
||||
'boolean', 'uri', 'list');
|
||||
|
||||
$property_info = entity_get_property_info($entity_type);
|
||||
if (empty($property_info['properties'])) {
|
||||
// Stop here if no properties were found.
|
||||
return array();
|
||||
}
|
||||
|
||||
foreach ($property_info['properties'] as $key => $property) {
|
||||
if (in_array($key, $disabled_properties)) {
|
||||
continue;
|
||||
@@ -463,27 +493,38 @@ function _views_bulk_operations_modify_action_get_bundles($entity_type, $context
|
||||
$bundles = array();
|
||||
|
||||
$view = $context['view'];
|
||||
$vbo = _views_bulk_operations_get_field($view);
|
||||
$display_values = $context['settings']['display_values'];
|
||||
$info = entity_get_info($entity_type);
|
||||
$bundle_key = $info['entity keys']['bundle'];
|
||||
|
||||
// Check if this View has a filter on the bundle key and assemble a list
|
||||
// of allowed bundles according to the filter.
|
||||
$filtered_bundles = array();
|
||||
if (!empty($bundle_key) && isset($view->filter[$bundle_key]) && !empty($view->filter[$bundle_key]->value)) {
|
||||
$operator = $view->filter[$bundle_key]->operator;
|
||||
if ($operator == 'in') {
|
||||
$filtered_bundles = $view->filter[$bundle_key]->value;
|
||||
}
|
||||
elseif ($operator == 'not in') {
|
||||
$bundle_names = array_keys($info['bundles']);
|
||||
$filtered_bundles = array_diff($bundle_names, $view->filter[$bundle_key]->value);
|
||||
$filtered_bundles = array_keys($info['bundles']);
|
||||
|
||||
// Go over all the filters and find any relevant ones.
|
||||
foreach ($view->filter as $key => $filter) {
|
||||
// Check it's the right field on the right table.
|
||||
if ($filter->table == $vbo->table && $filter->field == $bundle_key) {
|
||||
// Exposed filters may have no bundles, so check that there is a value.
|
||||
if (empty($filter->value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$operator = $filter->operator;
|
||||
if ($operator == 'in') {
|
||||
$filtered_bundles = array_intersect($filtered_bundles, $filter->value);
|
||||
}
|
||||
elseif ($operator == 'not in') {
|
||||
$filtered_bundles = array_diff($filtered_bundles, $filter->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($info['bundles'] as $bundle_name => $bundle) {
|
||||
// The view is limited to specific bundles, but this bundle isn't one of
|
||||
// them. Ignore it.
|
||||
if (!empty($filtered_bundles) && !in_array($bundle_name, $filtered_bundles)) {
|
||||
if (!in_array($bundle_name, $filtered_bundles)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -575,6 +616,7 @@ function views_bulk_operations_modify_action_views_bulk_operations_form($options
|
||||
'#multiple' => TRUE,
|
||||
'#description' => t('Select which values the action form should present to the user.'),
|
||||
'#default_value' => $options['display_values'],
|
||||
'#size' => 10,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* VBO action to cancel user accounts.
|
||||
*/
|
||||
|
||||
function views_bulk_operations_user_cancel_action_info() {
|
||||
return array('views_bulk_operations_user_cancel_action' => array(
|
||||
'type' => 'user',
|
||||
'label' => t('Cancel user account'),
|
||||
'configurable' => TRUE,
|
||||
'behavior' => array('deletes_property'),
|
||||
'triggers' => array('any'),
|
||||
));
|
||||
}
|
||||
|
||||
function views_bulk_operations_user_cancel_action_form($context) {
|
||||
module_load_include('inc', 'user', 'user.pages');
|
||||
$form['user_cancel_method'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('When cancelling these accounts'),
|
||||
);
|
||||
$form['user_cancel_method'] += user_cancel_methods();
|
||||
// Remove method descriptions.
|
||||
foreach (element_children($form['user_cancel_method']) as $element) {
|
||||
unset($form['user_cancel_method'][$element]['#description']);
|
||||
}
|
||||
$admin_access = user_access('administer users');
|
||||
$default_notify = variable_get('user_mail_status_canceled_notify', FALSE);
|
||||
$form['user_cancel_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Notify user when account is canceled.'),
|
||||
'#default_value' => ($admin_access ? FALSE : $default_notify),
|
||||
'#access' => $admin_access && $default_notify,
|
||||
'#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
function views_bulk_operations_user_cancel_action_submit($form, $form_state) {
|
||||
return array(
|
||||
'user_cancel_method' => $form_state['values']['user_cancel_method'],
|
||||
'user_cancel_notify' => $form_state['values']['user_cancel_notify'],
|
||||
);
|
||||
}
|
||||
|
||||
function views_bulk_operations_user_cancel_action($account, $context) {
|
||||
global $user;
|
||||
// Prevent the user from cancelling itself.
|
||||
if ($account->uid == $user->uid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow other modules to react on the cancellation.
|
||||
if ($context['user_cancel_method'] != 'user_cancel_delete') {
|
||||
module_invoke_all('user_cancel', array(), $account, $context['user_cancel_method']);
|
||||
}
|
||||
|
||||
switch ($context['user_cancel_method']) {
|
||||
case 'user_cancel_block':
|
||||
case 'user_cancel_block_unpublish':
|
||||
default:
|
||||
// Send account blocked notification if option was checked.
|
||||
if (!empty($context['user_cancel_notify'])) {
|
||||
_user_mail_notify('status_blocked', $account);
|
||||
}
|
||||
user_save($account, array('status' => 0));
|
||||
watchdog('user', 'Blocked user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
|
||||
break;
|
||||
|
||||
case 'user_cancel_reassign':
|
||||
case 'user_cancel_delete':
|
||||
// Send account canceled notification if option was checked.
|
||||
if (!empty($context['user_cancel_notify'])) {
|
||||
_user_mail_notify('status_canceled', $account);
|
||||
}
|
||||
user_delete($account->uid);
|
||||
watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
|
||||
break;
|
||||
}
|
||||
}
|
@@ -45,24 +45,19 @@ function views_bulk_operations_user_roles_action_submit($form, $form_state) {
|
||||
);
|
||||
}
|
||||
|
||||
function views_bulk_operations_user_roles_action(&$user, $context) {
|
||||
$roles = $user->roles;
|
||||
$selected = (is_array($context['add_roles']) ? $context['add_roles'] : array()) +
|
||||
(is_array($context['remove_roles']) ? $context['remove_roles'] : array());
|
||||
$result = db_query("SELECT rid, name FROM {role} WHERE rid IN (:selected)", array(':selected' => array_keys($selected)));
|
||||
foreach ($result as $role) {
|
||||
if (isset($context['add_roles'][$role->rid])) {
|
||||
$add_roles[$role->rid] = $role->name;
|
||||
}
|
||||
if (isset($context['remove_roles'][$role->rid])) {
|
||||
$remove_roles[$role->rid] = $role->name;
|
||||
}
|
||||
function views_bulk_operations_user_roles_action($user, $context) {
|
||||
$wrapper = entity_metadata_wrapper('user', $user);
|
||||
if (!$wrapper->roles->access("update")) {
|
||||
// No access.
|
||||
return;
|
||||
}
|
||||
if (!empty($add_roles)) {
|
||||
$roles += $add_roles;
|
||||
$roles = $wrapper->roles->value();
|
||||
if (is_array($context['add_roles'])) {
|
||||
$roles = array_merge($roles, $context['add_roles']);
|
||||
}
|
||||
if (!empty($remove_roles)) {
|
||||
$roles = array_diff($roles, $remove_roles);
|
||||
if (is_array($context['remove_roles'])) {
|
||||
$roles = array_diff($roles, $context['remove_roles']);
|
||||
}
|
||||
user_save($user, array('roles' => $roles));
|
||||
$wrapper->roles->set($roles);
|
||||
$wrapper->save();
|
||||
}
|
||||
|
@@ -3,9 +3,9 @@ description = Provides permission-based access control for actions. Used by View
|
||||
package = Administration
|
||||
core = 7.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-12-03
|
||||
version = "7.x-3.1"
|
||||
; Information added by Drupal.org packaging script on 2015-07-01
|
||||
version = "7.x-3.3"
|
||||
core = "7.x"
|
||||
project = "views_bulk_operations"
|
||||
datestamp = "1354500015"
|
||||
datestamp = "1435764542"
|
||||
|
||||
|
@@ -46,21 +46,23 @@
|
||||
});
|
||||
|
||||
// Set up the ability to click anywhere on the row to select it.
|
||||
$('.views-table tbody tr', form).click(function(event) {
|
||||
if (event.target.tagName.toLowerCase() != 'input' && event.target.tagName.toLowerCase() != 'a') {
|
||||
$('input[id^="edit-views-bulk-operations"]:not(:disabled)', this).each(function() {
|
||||
var checked = this.checked;
|
||||
// trigger() toggles the checkmark *after* the event is set,
|
||||
// whereas manually clicking the checkbox toggles it *beforehand*.
|
||||
// that's why we manually set the checkmark first, then trigger the
|
||||
// event (so that listeners get notified), then re-set the checkmark
|
||||
// which the trigger will have toggled. yuck!
|
||||
this.checked = !checked;
|
||||
$(this).trigger('click');
|
||||
this.checked = !checked;
|
||||
});
|
||||
}
|
||||
});
|
||||
if (Drupal.settings.vbo.row_clickable) {
|
||||
$('.views-table tbody tr', form).click(function(event) {
|
||||
if (event.target.tagName.toLowerCase() != 'input' && event.target.tagName.toLowerCase() != 'a') {
|
||||
$('input[id^="edit-views-bulk-operations"]:not(:disabled)', this).each(function() {
|
||||
var checked = this.checked;
|
||||
// trigger() toggles the checkmark *after* the event is set,
|
||||
// whereas manually clicking the checkbox toggles it *beforehand*.
|
||||
// that's why we manually set the checkmark first, then trigger the
|
||||
// event (so that listeners get notified), then re-set the checkmark
|
||||
// which the trigger will have toggled. yuck!
|
||||
this.checked = !checked;
|
||||
$(this).trigger('click');
|
||||
this.checked = !checked;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Drupal.vbo.tableSelectAllPages = function(form) {
|
||||
|
@@ -20,7 +20,7 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
|
||||
*/
|
||||
public function getAccessMask() {
|
||||
// Assume edit by default.
|
||||
if (!isset($this->operationInfo['behavior'])) {
|
||||
if (empty($this->operationInfo['behavior'])) {
|
||||
$this->operationInfo['behavior'] = array('changes_property');
|
||||
}
|
||||
|
||||
@@ -141,9 +141,11 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
|
||||
* @param $dom_id
|
||||
* The dom path to the level where the admin options form is embedded.
|
||||
* Needed for #dependency.
|
||||
* @param $field_handler
|
||||
* The Views field handler object for the VBO field.
|
||||
*/
|
||||
public function adminOptionsForm($dom_id) {
|
||||
$form = parent::adminOptionsForm($dom_id);
|
||||
public function adminOptionsForm($dom_id, $field_handler) {
|
||||
$form = parent::adminOptionsForm($dom_id, $field_handler);
|
||||
|
||||
$settings_form_callback = $this->operationInfo['callback'] . '_views_bulk_operations_form';
|
||||
if (function_exists($settings_form_callback)) {
|
||||
|
@@ -173,8 +173,10 @@ abstract class ViewsBulkOperationsBaseOperation {
|
||||
* @param $dom_id
|
||||
* The dom path to the level where the admin options form is embedded.
|
||||
* Needed for #dependency.
|
||||
* @param $field_handler
|
||||
* The Views field handler object for the VBO field.
|
||||
*/
|
||||
public function adminOptionsForm($dom_id) {
|
||||
public function adminOptionsForm($dom_id, $field_handler) {
|
||||
$label = $this->getAdminOption('label', '');
|
||||
|
||||
$form = array();
|
||||
|
@@ -124,6 +124,8 @@ class ViewsBulkOperationsRulesComponent extends ViewsBulkOperationsBaseOperation
|
||||
else {
|
||||
$element = rules_action('component_' . $this->operationInfo['parameters']['component_key']);
|
||||
}
|
||||
$element->execute($data);
|
||||
$wrapper_type = is_array($data) ? "list<{$this->entityType}>" : $this->entityType;
|
||||
$wrapper = entity_metadata_wrapper($wrapper_type, $data);
|
||||
$element->execute($wrapper);
|
||||
}
|
||||
}
|
||||
|
@@ -55,17 +55,50 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
|
||||
'contains' => array(
|
||||
'display_type' => array('default' => 0),
|
||||
'enable_select_all_pages' => array('default' => TRUE),
|
||||
'row_clickable' => array('default' => TRUE),
|
||||
'force_single' => array('default' => FALSE),
|
||||
'entity_load_capacity' => array('default' => 10),
|
||||
'skip_batching' => array('default' => 0),
|
||||
),
|
||||
);
|
||||
$options['vbo_operations'] = array(
|
||||
'default' => array(),
|
||||
'unpack_translatable' => 'unpack_operations',
|
||||
'export' => 'export_vbo_operations',
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function export_vbo_operations($indent, $prefix, $storage, $option, $definition, $parents) {
|
||||
// Anti-recursion, since we use the parent export helper.
|
||||
unset($definition['export']);
|
||||
|
||||
// Find and remove all unselected/disabled operations.
|
||||
foreach ($storage['vbo_operations'] as $operation_id => $operation) {
|
||||
if (empty($operation['selected'])) {
|
||||
unset($storage['vbo_operations'][$operation_id]);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::export_option($indent, $prefix, $storage, $option, $definition, $parents);
|
||||
}
|
||||
|
||||
function unpack_operations(&$translatable, $storage, $option, $definition, $parents, $keys) {
|
||||
$translatable[] = array(
|
||||
'value' => t('- Choose an operation -'),
|
||||
'keys' => array_merge($keys, array('noop')),
|
||||
);
|
||||
foreach ($storage[$option] as $key => $operation) {
|
||||
if (!empty($operation['override_label']) && !empty($operation['label'])) {
|
||||
$translatable[] = array(
|
||||
'value' => $operation['label'],
|
||||
'keys' => array_merge($keys, array($key)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
@@ -90,6 +123,12 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
|
||||
'#default_value' => $this->options['vbo_settings']['enable_select_all_pages'],
|
||||
'#description' => t('Check this box to enable the ability to select all items on all pages.'),
|
||||
);
|
||||
$form['vbo_settings']['row_clickable'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Make the whole row clickable'),
|
||||
'#default_value' => $this->options['vbo_settings']['row_clickable'],
|
||||
'#description' => t('Check this box to select an item when its row has been clicked. Requires JavaScript.'),
|
||||
);
|
||||
$form['vbo_settings']['force_single'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Force single'),
|
||||
@@ -102,6 +141,12 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
|
||||
'#description' => t("Improve execution performance at the cost of memory usage. Set to '1' if you're having problems."),
|
||||
'#default_value' => $this->options['vbo_settings']['entity_load_capacity'],
|
||||
);
|
||||
$form['vbo_settings']['skip_batching'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Skip batching'),
|
||||
'#default_value' => $this->options['vbo_settings']['skip_batching'],
|
||||
'#description' => '<b>' . t('Warning:') . '</b> ' . t('This will cause timeouts for larger amounts of selected items.'),
|
||||
);
|
||||
|
||||
// Display operations and their settings.
|
||||
$form['vbo_operations'] = array(
|
||||
@@ -142,7 +187,7 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
|
||||
),
|
||||
);
|
||||
|
||||
$form['vbo_operations'][$operation_id] += $operation->adminOptionsForm($dom_id);
|
||||
$form['vbo_operations'][$operation_id] += $operation->adminOptionsForm($dom_id, $this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,13 +4,14 @@ dependencies[] = entity
|
||||
dependencies[] = views
|
||||
package = Views
|
||||
core = 7.x
|
||||
php = 5.2.9
|
||||
|
||||
files[] = plugins/operation_types/base.class.php
|
||||
files[] = views/views_bulk_operations_handler_field_operations.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2012-12-03
|
||||
version = "7.x-3.1"
|
||||
; Information added by Drupal.org packaging script on 2015-07-01
|
||||
version = "7.x-3.3"
|
||||
core = "7.x"
|
||||
project = "views_bulk_operations"
|
||||
datestamp = "1354500015"
|
||||
datestamp = "1435764542"
|
||||
|
||||
|
@@ -41,19 +41,20 @@ function views_bulk_operations_load_action_includes() {
|
||||
// The list of VBO actions is fairly static, so it's hardcoded for better
|
||||
// performance (hitting the filesystem with file_scan_directory(), and then
|
||||
// caching the result has its cost).
|
||||
$path = drupal_get_path('module', 'views_bulk_operations') . '/actions/';
|
||||
$files = array(
|
||||
'archive.action.inc',
|
||||
'argument_selector.action.inc',
|
||||
'delete.action.inc',
|
||||
'modify.action.inc',
|
||||
'script.action.inc',
|
||||
'user_roles.action.inc',
|
||||
'archive.action',
|
||||
'argument_selector.action',
|
||||
'book.action',
|
||||
'delete.action',
|
||||
'modify.action',
|
||||
'script.action',
|
||||
'user_roles.action',
|
||||
'user_cancel.action',
|
||||
);
|
||||
|
||||
if (!$loaded) {
|
||||
foreach ($files as $file) {
|
||||
include_once $path . $file;
|
||||
module_load_include('inc', 'views_bulk_operations', 'actions/' . $file);
|
||||
}
|
||||
$loaded = TRUE;
|
||||
}
|
||||
@@ -75,7 +76,7 @@ function views_bulk_operations_load_action_includes() {
|
||||
function views_bulk_operations_cron() {
|
||||
db_delete('queue')
|
||||
->condition('name', db_like('views_bulk_operations_active_queue_'), 'LIKE')
|
||||
->condition('created', REQUEST_TIME - 864000, '<')
|
||||
->condition('created', REQUEST_TIME - 86400, '<')
|
||||
->execute();
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ function views_bulk_operations_theme() {
|
||||
'variables' => array('view' => NULL, 'enable_select_all_pages' => TRUE),
|
||||
),
|
||||
'views_bulk_operations_confirmation' => array(
|
||||
'variables' => array('rows' => NULL, 'vbo' => NULL),
|
||||
'variables' => array('rows' => NULL, 'vbo' => NULL, 'operation' => NULL, 'select_all_pages' => FALSE),
|
||||
),
|
||||
);
|
||||
$files = views_bulk_operations_load_action_includes();
|
||||
@@ -300,6 +301,29 @@ function views_bulk_operations_form_alter(&$form, &$form_state, $form_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add basic VBO functionality.
|
||||
if ($form_state['step'] == 'views_form_views_form') {
|
||||
// The submit button added by Views Form API might be used by a non-VBO Views
|
||||
// Form handler. If there's no such handler on the view, hide the button.
|
||||
$has_other_views_form_handlers = FALSE;
|
||||
foreach ($vbo->view->field as $field) {
|
||||
if (property_exists($field, 'views_form_callback') || method_exists($field, 'views_form')) {
|
||||
if (!($field instanceof views_bulk_operations_handler_field_operations)) {
|
||||
$has_other_views_form_handlers = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$has_other_views_form_handlers) {
|
||||
$form['actions']['#access'] = FALSE;
|
||||
}
|
||||
// The VBO field is excluded from display, stop here.
|
||||
if (!empty($vbo->options['exclude'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form = views_bulk_operations_form($form, $form_state, $vbo);
|
||||
}
|
||||
|
||||
// Cache the built form to prevent it from being rebuilt prior to validation
|
||||
// and submission, which could lead to data being processed incorrectly,
|
||||
// because the views rows (and thus, the form elements as well) have changed
|
||||
@@ -319,15 +343,25 @@ function views_bulk_operations_form_alter(&$form, &$form_state, $form_id) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add basic VBO functionality.
|
||||
if ($form_state['step'] == 'views_form_views_form') {
|
||||
$form = views_bulk_operations_form($form, $form_state, $vbo);
|
||||
}
|
||||
|
||||
// Give other modules a chance to alter the form.
|
||||
drupal_alter('views_bulk_operations_form', $form, $form_state, $vbo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_views_post_build().
|
||||
*
|
||||
* Hides the VBO field if no operations are available.
|
||||
* This causes the entire VBO form to be hidden.
|
||||
*
|
||||
* @see views_bulk_operations_form_alter().
|
||||
*/
|
||||
function views_bulk_operations_views_post_build(&$view) {
|
||||
$vbo = _views_bulk_operations_get_field($view);
|
||||
if ($vbo && count($vbo->get_selected_operations()) < 1) {
|
||||
$vbo->options['exclude'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 'select all' div that gets inserted below the table header row
|
||||
* (for table style plugins with grouping disabled), or above the view results
|
||||
@@ -385,7 +419,7 @@ function theme_views_bulk_operations_select_all($variables) {
|
||||
if ($enable_select_all_pages) {
|
||||
$form['select_all']['or'] = array(
|
||||
'#type' => 'markup',
|
||||
'#markup' => '<em>OR</em>',
|
||||
'#markup' => '<em>' . t('OR') . '</em>',
|
||||
);
|
||||
$form['select_all']['all_pages'] = array(
|
||||
'#type' => 'checkbox',
|
||||
@@ -408,8 +442,20 @@ function theme_views_bulk_operations_select_all($variables) {
|
||||
*/
|
||||
function views_bulk_operations_form($form, &$form_state, $vbo) {
|
||||
$form['#attached']['js'][] = drupal_get_path('module', 'views_bulk_operations') . '/js/views_bulk_operations.js';
|
||||
$form['#attached']['js'][] = array(
|
||||
'data' => array('vbo' => array(
|
||||
'row_clickable' => $vbo->get_vbo_option('row_clickable'),
|
||||
)),
|
||||
'type' => 'setting',
|
||||
);
|
||||
|
||||
$form['#attached']['css'][] = drupal_get_path('module', 'views_bulk_operations') . '/css/views_bulk_operations.css';
|
||||
$form['#prefix'] = '<div class="vbo-views-form">';
|
||||
// Wrap the form in a div with specific classes for JS targeting and theming.
|
||||
$class = 'vbo-views-form';
|
||||
if (empty($vbo->view->result)) {
|
||||
$class .= ' vbo-views-form-empty';
|
||||
}
|
||||
$form['#prefix'] = '<div class="' . $class . '">';
|
||||
$form['#suffix'] = '</div>';
|
||||
|
||||
// Force browser to reload the page if Back is hit.
|
||||
@@ -426,25 +472,10 @@ function views_bulk_operations_form($form, &$form_state, $vbo) {
|
||||
'#attributes' => array('class' => 'select-all-rows'),
|
||||
'#default_value' => FALSE,
|
||||
);
|
||||
|
||||
// The submit button added by Views Form API might be used by a non-VBO Views
|
||||
// Form handler. If there's no such handler on the view, hide the button.
|
||||
$has_other_views_form_handlers = FALSE;
|
||||
foreach ($vbo->view->field as $field) {
|
||||
if (property_exists($field, 'views_form_callback') || method_exists($field, 'views_form')) {
|
||||
if (!($field instanceof views_bulk_operations_handler_field_operations)) {
|
||||
$has_other_views_form_handlers = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$has_other_views_form_handlers) {
|
||||
$form['actions']['submit']['#access'] = FALSE;
|
||||
}
|
||||
|
||||
$form['select'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Operations'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsible' => FALSE,
|
||||
'#attributes' => array('class' => array('container-inline')),
|
||||
);
|
||||
if ($vbo->get_vbo_option('display_type') == 0) {
|
||||
@@ -570,14 +601,23 @@ function views_bulk_operations_confirm_form($form, &$form_state, $view, $output)
|
||||
$operation = $form_state['operation'];
|
||||
$rows = $form_state['selection'];
|
||||
$query = drupal_get_query_parameters($_GET, array('q'));
|
||||
$title = t('Are you sure you want to perform %operation on the selected items?', array('%operation' => $operation->label()));
|
||||
$form = confirm_form($form,
|
||||
t('Are you sure you want to perform %operation on the selected items?', array('%operation' => $operation->label())),
|
||||
$title,
|
||||
array('path' => $view->get_url(), 'query' => $query),
|
||||
theme('views_bulk_operations_confirmation', array('rows' => $rows, 'vbo' => $vbo, 'select_all_pages' => $form_state['select_all_pages']))
|
||||
theme('views_bulk_operations_confirmation', array('rows' => $rows, 'vbo' => $vbo, 'operation' => $operation, 'select_all_pages' => $form_state['select_all_pages']))
|
||||
);
|
||||
// Add VBO's submit handler to the Confirm button added by config_form().
|
||||
$form['actions']['submit']['#submit'] = array('views_bulk_operations_form_submit');
|
||||
|
||||
// We can't set the View title here as $view is just a copy of the original,
|
||||
// and our settings changes won't "stick" for the first page load of the
|
||||
// confirmation form. We also can't just call drupal_set_title() directly
|
||||
// because our title will be clobbered by the actual View title later. So
|
||||
// let's tuck the title away in the form for use later.
|
||||
// @see views_bulk_operations_preprocess_views_view()
|
||||
$form['#vbo_confirm_form_title'] = $title;
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
@@ -593,7 +633,7 @@ function theme_views_bulk_operations_confirmation($variables) {
|
||||
// Load the entities from the current page, and show their titles.
|
||||
$entities = _views_bulk_operations_entity_load($entity_type, array_values($rows), $vbo->revision);
|
||||
foreach ($entities as $entity) {
|
||||
$items[] = check_plain(_views_bulk_operations_entity_label($entity_type, $entity));
|
||||
$items[] = check_plain(entity_label($entity_type, $entity));
|
||||
}
|
||||
// All rows on all pages have been selected, so show a count of additional items.
|
||||
if ($select_all_pages) {
|
||||
@@ -606,6 +646,29 @@ function theme_views_bulk_operations_confirmation($variables) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_preprocess_page().
|
||||
*
|
||||
* Hide action links on the configure and confirm pages.
|
||||
*/
|
||||
function views_bulk_operations_preprocess_page(&$variables) {
|
||||
if (isset($_POST['select_all'], $_POST['operation'])) {
|
||||
$variables['action_links'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_preprocess_views_view().
|
||||
*/
|
||||
function views_bulk_operations_preprocess_views_view($variables) {
|
||||
// If we've stored a title for the confirmation form, retrieve it here and
|
||||
// retitle the View.
|
||||
// @see views_bulk_operations_confirm_form()
|
||||
if (array_key_exists('rows', $variables) && is_array($variables['rows']) && array_key_exists('#vbo_confirm_form_title', $variables['rows'])) {
|
||||
$variables['view']->set_title($variables['rows']['#vbo_confirm_form_title']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through the submitted values, and returns
|
||||
* an array of selected rows, in the form of
|
||||
@@ -676,8 +739,8 @@ function views_bulk_operations_form_submit($form, &$form_state) {
|
||||
* Entry point for executing the chosen operation upon selected rows.
|
||||
*
|
||||
* If the selected operation is an aggregate operation (requiring all selected
|
||||
* items to be passed at the same time), or the execution is being triggered
|
||||
* through Drush, the operation is executed directly.
|
||||
* items to be passed at the same time), restricted to a single value, or has
|
||||
* the skip_batching option set, the operation is executed directly.
|
||||
* This means that there is no batching & queueing, the PHP execution
|
||||
* time limit is ignored (if allowed), all selected entities are loaded and
|
||||
* processed.
|
||||
@@ -703,9 +766,13 @@ function views_bulk_operations_form_submit($form, &$form_state) {
|
||||
function views_bulk_operations_execute($vbo, $operation, $selection, $select_all_pages = FALSE) {
|
||||
global $user;
|
||||
|
||||
// This is an aggregate operation, and it requires all rows to be selected.
|
||||
// Try to load them without a batch.
|
||||
if ($operation->aggregate() && $select_all_pages) {
|
||||
// Determine if the operation needs to be executed directly.
|
||||
$aggregate = $operation->aggregate();
|
||||
$skip_batching = $vbo->get_vbo_option('skip_batching');
|
||||
$force_single = $vbo->get_vbo_option('force_single');
|
||||
$execute_directly = ($aggregate || $skip_batching || $force_single);
|
||||
// Try to load all rows without a batch if needed.
|
||||
if ($execute_directly && $select_all_pages) {
|
||||
views_bulk_operations_direct_adjust($selection, $vbo);
|
||||
}
|
||||
|
||||
@@ -713,6 +780,15 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
|
||||
$options = array(
|
||||
'revision' => $vbo->revision,
|
||||
'entity_load_capacity' => $vbo->get_vbo_option('entity_load_capacity', 10),
|
||||
// The information needed to recreate the view, to avoid serializing the
|
||||
// whole object. Passed to the executed operation. Also used by
|
||||
// views_bulk_operations_adjust_selection().
|
||||
'view_info' => array(
|
||||
'name' => $vbo->view->name,
|
||||
'display' => $vbo->view->current_display,
|
||||
'arguments' => $vbo->view->args,
|
||||
'exposed_input' => $vbo->view->get_exposed_input(),
|
||||
),
|
||||
);
|
||||
// Create an array of rows in the needed format.
|
||||
$rows = array();
|
||||
@@ -735,8 +811,8 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
|
||||
}
|
||||
}
|
||||
|
||||
// Aggregate operations can only be executed directly.
|
||||
if ($operation->aggregate()) {
|
||||
if ($execute_directly) {
|
||||
// Execute the operation directly and stop here.
|
||||
views_bulk_operations_direct_process($operation, $rows, $options);
|
||||
return;
|
||||
}
|
||||
@@ -763,18 +839,8 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
|
||||
if ($select_all_pages && $vbo->view->query->pager->has_more_records()) {
|
||||
$total_rows = $vbo->view->total_rows;
|
||||
|
||||
// Pass information needed to recreate the view inside a batch,
|
||||
// to avoid having to serialize the current object (which is expensive).
|
||||
$view_info = array(
|
||||
'name' => $vbo->view->name,
|
||||
'display' => $vbo->view->current_display,
|
||||
'arguments' => $vbo->view->args,
|
||||
'exposed_input' => $vbo->view->get_exposed_input(),
|
||||
'entity_load_capacity' => $vbo->get_vbo_option('entity_load_capacity', 10),
|
||||
);
|
||||
|
||||
$batch['operations'][] = array(
|
||||
'views_bulk_operations_adjust_selection', array($view_info, $queue_name, $operation, $options),
|
||||
'views_bulk_operations_adjust_selection', array($queue_name, $operation, $options),
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -808,22 +874,21 @@ function views_bulk_operations_execute($vbo, $operation, $selection, $select_all
|
||||
/**
|
||||
* Batch API callback: loads the view page by page and enqueues all items.
|
||||
*
|
||||
* @param $view_info
|
||||
* An array of information about the view, used to recreate and re-execute it.
|
||||
* @param $queue_name
|
||||
* The name of the queue to which the items should be added.
|
||||
* @param $operation
|
||||
* The operation object.
|
||||
* @param $options
|
||||
* An array of options that affect execution (revision, entity_load_capacity).
|
||||
* Passed along with each new queue item.
|
||||
* An array of options that affect execution (revision, entity_load_capacity,
|
||||
* view_info). Passed along with each new queue item.
|
||||
*/
|
||||
function views_bulk_operations_adjust_selection($view_info, $queue_name, $operation, $options, &$context) {
|
||||
function views_bulk_operations_adjust_selection($queue_name, $operation, $options, &$context) {
|
||||
if (!isset($context['sandbox']['progress'])) {
|
||||
$context['sandbox']['progress'] = 0;
|
||||
$context['sandbox']['max'] = 0;
|
||||
}
|
||||
|
||||
$view_info = $options['view_info'];
|
||||
$view = views_get_view($view_info['name']);
|
||||
$view->set_exposed_input($view_info['exposed_input']);
|
||||
$view->set_arguments($view_info['arguments']);
|
||||
@@ -844,7 +909,7 @@ function views_bulk_operations_adjust_selection($view_info, $queue_name, $operat
|
||||
'views_row' => array(),
|
||||
'position' => array(
|
||||
'current' => ++$context['sandbox']['progress'],
|
||||
'total' => $view->total_rows,
|
||||
'total' => $context['sandbox']['max'],
|
||||
),
|
||||
);
|
||||
// Some operations require full selected rows.
|
||||
@@ -927,7 +992,7 @@ function views_bulk_operations_active_queue_process($queue_name, $operation, $to
|
||||
static $queue;
|
||||
|
||||
// It is still possible to hit the time limit.
|
||||
@set_time_limit(0);
|
||||
drupal_set_time_limit(0);
|
||||
|
||||
// Prepare the sandbox.
|
||||
if (!isset($context['sandbox']['progress'])) {
|
||||
@@ -980,26 +1045,42 @@ function views_bulk_operations_queue_item_process($queue_item_data, &$log = NULL
|
||||
$account = user_load($queue_item_data['uid']);
|
||||
$entity_type = $operation->entityType;
|
||||
$entity_ids = array();
|
||||
foreach ($row_group as $row_id => $row) {
|
||||
foreach ($row_group as $row_index => $row) {
|
||||
$entity_ids[] = $row['entity_id'];
|
||||
}
|
||||
|
||||
$entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
|
||||
foreach ($row_group as $row_id => $row) {
|
||||
foreach ($row_group as $row_index => $row) {
|
||||
$entity_id = $row['entity_id'];
|
||||
// A matching entity couldn't be loaded. Skip this item.
|
||||
if (!isset($entities[$entity_id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entity = $entities[$entity_id];
|
||||
if ($options['revision']) {
|
||||
// Don't reload revisions for now, they are not statically cached and
|
||||
// usually don't run into the edge case described below.
|
||||
$entity = $entities[$entity_id];
|
||||
}
|
||||
else {
|
||||
// A previous action might have resulted in the entity being resaved
|
||||
// (e.g. node synchronization from a prior node in this batch), so try
|
||||
// to reload it. If no change occurred, the entity will be retrieved
|
||||
// from the static cache, resulting in no performance penalty.
|
||||
$entity = entity_load_single($entity_type, $entity_id);
|
||||
if (empty($entity)) {
|
||||
// The entity is no longer valid.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If the current entity can't be accessed, skip it and log a notice.
|
||||
if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) {
|
||||
$message = 'Skipped %operation on @type %title due to insufficient permissions.';
|
||||
$arguments = array(
|
||||
'%operation' => $operation->label(),
|
||||
'@type' => $entity_type,
|
||||
'%title' => _views_bulk_operations_entity_label($entity_type, $entity),
|
||||
'%title' => entity_label($entity_type, $entity),
|
||||
);
|
||||
|
||||
if ($log) {
|
||||
@@ -1014,11 +1095,14 @@ function views_bulk_operations_queue_item_process($queue_item_data, &$log = NULL
|
||||
|
||||
$operation_context = array(
|
||||
'progress' => $row['position'],
|
||||
'rows' => $row['views_row'],
|
||||
'view_info' => $options['view_info'],
|
||||
);
|
||||
if ($operation->needsRows()) {
|
||||
$operation_context['rows'] = array($row_index => $row['views_row']);
|
||||
}
|
||||
$operation->execute($entity, $operation_context);
|
||||
|
||||
unset($row_group[$row_id]);
|
||||
unset($row_group[$row_index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,11 +1139,11 @@ function views_bulk_operations_direct_adjust(&$selection, $vbo) {
|
||||
|
||||
/**
|
||||
* Processes the passed rows directly (without batching and queueing).
|
||||
*
|
||||
* This is a legacy function that is now only used for aggregate operations.
|
||||
*/
|
||||
function views_bulk_operations_direct_process($operation, $rows, $options) {
|
||||
@set_time_limit(0);
|
||||
global $user;
|
||||
|
||||
drupal_set_time_limit(0);
|
||||
|
||||
// Prepare an array of status information. Imitates the Batch API naming
|
||||
// for consistency. Passed to views_bulk_operations_execute_finished().
|
||||
@@ -1067,42 +1151,56 @@ function views_bulk_operations_direct_process($operation, $rows, $options) {
|
||||
$context['results']['progress'] = 0;
|
||||
$context['results']['log'] = array();
|
||||
|
||||
$entity_type = $operation->entityType;
|
||||
$entity_ids = array();
|
||||
foreach ($rows as $row_index => $row) {
|
||||
$entity_ids[] = $row['entity_id'];
|
||||
}
|
||||
$entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
|
||||
|
||||
foreach ($entities as $id => $entity) {
|
||||
if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
|
||||
$context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
|
||||
'%operation' => $operation->label(),
|
||||
'@type' => $entity_type,
|
||||
'%title' => _views_bulk_operations_entity_label($entity_type, $entity),
|
||||
));
|
||||
unset($entities[$id]);
|
||||
}
|
||||
}
|
||||
if (empty($entities)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass the selected rows to the operation if needed.
|
||||
$operation_context = array();
|
||||
if ($operation->needsRows()) {
|
||||
$operation_context['rows'] = array();
|
||||
if ($operation->aggregate()) {
|
||||
// Load all entities.
|
||||
$entity_type = $operation->entityType;
|
||||
$entity_ids = array();
|
||||
foreach ($rows as $row_index => $row) {
|
||||
$operation_context['rows'][$row_index] = $row['views_row'];
|
||||
$entity_ids[] = $row['entity_id'];
|
||||
}
|
||||
$entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']);
|
||||
|
||||
// Filter out entities that can't be accessed.
|
||||
foreach ($entities as $id => $entity) {
|
||||
if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) {
|
||||
$context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array(
|
||||
'%operation' => $operation->label(),
|
||||
'@type' => $entity_type,
|
||||
'%title' => entity_label($entity_type, $entity),
|
||||
));
|
||||
unset($entities[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any entities left, execute the operation on them.
|
||||
if ($entities) {
|
||||
$operation_context = array(
|
||||
'view_info' => $options['view_info'],
|
||||
);
|
||||
// Pass the selected rows to the operation if needed.
|
||||
if ($operation->needsRows()) {
|
||||
$operation_context['rows'] = array();
|
||||
foreach ($rows as $row_index => $row) {
|
||||
$operation_context['rows'][$row_index] = $row['views_row'];
|
||||
}
|
||||
}
|
||||
$operation->execute($entities, $operation_context);
|
||||
}
|
||||
}
|
||||
$operation->execute($entities, $operation_context);
|
||||
else {
|
||||
// Imitate a queue and process the entities one by one.
|
||||
$queue_item_data = array(
|
||||
'uid' => $user->uid,
|
||||
'arguments' => array($rows, $operation, $options),
|
||||
);
|
||||
views_bulk_operations_queue_item_process($queue_item_data, $context['results']['log']);
|
||||
}
|
||||
|
||||
$context['results']['log'][] = t('Performed aggregate %operation on @items.', array(
|
||||
$context['results']['progress'] += count($rows);
|
||||
$context['results']['log'][] = t('Performed %operation on @items.', array(
|
||||
'%operation' => $operation->label(),
|
||||
'@items' => format_plural(count($entities), '1 item', '@count items'),
|
||||
'@items' => format_plural(count($rows), '1 item', '@count items'),
|
||||
));
|
||||
$context['results']['progress'] += count($entities);
|
||||
|
||||
views_bulk_operations_execute_finished(TRUE, $context['results'], array());
|
||||
}
|
||||
@@ -1176,29 +1274,6 @@ function _views_bulk_operations_entity_load($entity_type, $ids, $revision = FALS
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Label function for entities.
|
||||
* Core entities don't declare the "label" key, so entity_label() fails,
|
||||
* and a fallback is needed. This function provides that fallback.
|
||||
*/
|
||||
function _views_bulk_operations_entity_label($entity_type, $entity) {
|
||||
$label = entity_label($entity_type, $entity);
|
||||
if (!$label) {
|
||||
$entity_info = entity_get_info($entity_type);
|
||||
$id_key = $entity_info['entity keys']['id'];
|
||||
// Many entity types (e.g. "user") have a name which fits the label perfectly.
|
||||
if (isset($entity->name)) {
|
||||
$label = $entity->name;
|
||||
}
|
||||
elseif (isset($entity->{$id_key})) {
|
||||
// Fallback to the id key.
|
||||
$label = $entity->{$id_key};
|
||||
}
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to report an error.
|
||||
*/
|
||||
|
@@ -113,8 +113,9 @@ function views_bulk_operations_rules_action_info() {
|
||||
*/
|
||||
function views_bulk_operations_views_list() {
|
||||
$selectable_displays = array();
|
||||
foreach (views_get_enabled_views() as $name => $view) {
|
||||
foreach ($view->display as $display_name => $display) {
|
||||
foreach (views_get_enabled_views() as $name => $base_view) {
|
||||
foreach ($base_view->display as $display_name => $display) {
|
||||
$view = $base_view->clone_view();
|
||||
$view->build($display_name);
|
||||
$vbo = _views_bulk_operations_get_field($view);
|
||||
if ($vbo) {
|
||||
@@ -158,13 +159,12 @@ function views_bulk_operations_condition_result_count($view, $args, $minimum) {
|
||||
function views_bulk_operations_action_load_list($view, $args) {
|
||||
$vbo = _views_bulk_operations_rules_get_field($view, $args);
|
||||
|
||||
// Get all entity ids.
|
||||
$ids = array();
|
||||
// Get all entities, pass ids to the wrapper for lazy loading.
|
||||
$entity_type = $vbo->get_entity_type();
|
||||
$entities = entity_metadata_wrapper("list<$entity_type>", array());
|
||||
foreach ($vbo->view->result as $row_index => $result) {
|
||||
$ids[] = $vbo->get_value($result);
|
||||
$entities[] = entity_metadata_wrapper($entity_type, $vbo->get_value($result));
|
||||
}
|
||||
// And load the entity objects.
|
||||
$entities = entity_load($vbo->get_entity_type(), $ids);
|
||||
|
||||
return array('entity_list' => $entities);
|
||||
}
|
||||
|
Reference in New Issue
Block a user