summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBojan Zivanovic2011-12-13 22:44:42 (GMT)
committer Bojan Zivanovic2011-12-13 22:44:42 (GMT)
commitdb38f1d030f3a3eca1eba8b5e2f47b92bd55a57d (patch)
tree722e582c69c8c4344c884d6c4e7a350a9b299ac4
parent1986dd6e033da227f91d9929ff7db329fb587578 (diff)
Issue #1188400: Refactor operation types, the sequel.
-rw-r--r--actions_permissions.module2
-rw-r--r--plugins/operation_types/action.class.php102
-rw-r--r--plugins/operation_types/action.inc62
-rw-r--r--plugins/operation_types/base.class.php112
-rw-r--r--plugins/operation_types/rules_component.inc38
-rw-r--r--views/views_bulk_operations.views_default.inc86
-rw-r--r--views/views_bulk_operations_handler_field_operations.inc193
-rw-r--r--views_bulk_operations.drush.inc18
-rw-r--r--views_bulk_operations.module120
9 files changed, 487 insertions, 246 deletions
diff --git a/actions_permissions.module b/actions_permissions.module
index 5987d1e..8b120b8 100644
--- a/actions_permissions.module
+++ b/actions_permissions.module
@@ -8,7 +8,7 @@ function actions_permissions_permission() {
$actions = actions_list() + _actions_permissions_advanced_actions_list();
foreach ($actions as $callback => $action) {
$key = !empty($action['key']) ? $action['key'] : $callback;
- $permission = actions_permissions_get_perm($action['label'], $callback);
+ $permission = actions_permissions_get_perm($action['label'], $key);
$permissions[$permission] = array(
'title' => t('Execute %label', array('%label' => $action['label'])),
diff --git a/plugins/operation_types/action.class.php b/plugins/operation_types/action.class.php
index 4758152..e564be6 100644
--- a/plugins/operation_types/action.class.php
+++ b/plugins/operation_types/action.class.php
@@ -47,7 +47,7 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
public function access($account) {
// Use actions_permissions if enabled.
if (module_exists('actions_permissions')) {
- $perm = actions_permissions_get_perm($this->operationInfo['label'], $this->operationInfo['callback']);
+ $perm = actions_permissions_get_perm($this->operationInfo['label'], $this->operationInfo['key']);
if (!user_access($perm, $account)) {
return FALSE;
}
@@ -76,6 +76,7 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
* An array of related data provided by the caller.
*/
public function form($form, &$form_state, array $context) {
+ $context['settings'] = $this->getAdminOption('settings', array());
$form_callback = $this->operationInfo['callback'] . '_form';
return $form_callback($context);
}
@@ -90,6 +91,12 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
* An array containing the current state of the form.
*/
public function formValidate($form, &$form_state) {
+ // Some modules (including this one) place their action callbacks
+ // into separate files. At this point those files might no longer be
+ // included due to a page reload, so we call actions_list() to trigger
+ // inclusion. The same thing is done by actions_do() on execute.
+ actions_list();
+
$validation_callback = $this->operationInfo['callback'] . '_validate';
if (function_exists($validation_callback)) {
$validation_callback($form, $form_state);
@@ -107,11 +114,104 @@ class ViewsBulkOperationsAction extends ViewsBulkOperationsBaseOperation {
* An array containing the current state of the form.
*/
public function formSubmit($form, &$form_state) {
+ // Some modules (including this one) place their action callbacks
+ // into separate files. At this point those files might no longer be
+ // included due to a page reload, so we call actions_list() to trigger
+ // inclusion. The same thing is done by actions_do() on execute.
+ actions_list();
+
$submit_callback = $this->operationInfo['callback'] . '_submit';
$this->formOptions = $submit_callback($form, $form_state);
}
/**
+ * Returns the admin options form for the operation.
+ *
+ * The admin options form is embedded into the VBO field settings and used
+ * to configure operation behavior. The options can later be fetched
+ * through the getAdminOption() method.
+ *
+ * @param $dom_id
+ * The dom path to the level where the admin options form is embedded.
+ * Needed for #dependency.
+ */
+ public function adminOptionsForm($dom_id) {
+ $form = parent::adminOptionsForm($dom_id);
+
+ $settings_form_callback = $this->operationInfo['callback'] . '_views_bulk_operations_form';
+ if (function_exists($settings_form_callback)) {
+ $settings = $this->getAdminOption('settings', array());
+
+ $form['settings'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Operation settings'),
+ '#collapsible' => TRUE,
+ '#dependency' => array(
+ $dom_id . '-selected' => array(1),
+ ),
+ );
+ $form['settings'] += $settings_form_callback($settings);
+ }
+
+ return $form;
+ }
+
+ /**
+ * Validates the admin options form.
+ *
+ * @param $form
+ * The admin options form.
+ * @param $form_state
+ * An array containing the current state of the form. Note that this array
+ * is constructed by the VBO views field handler, so it's not a real form
+ * state, it contains only the 'values' key.
+ * @param $error_element_base
+ * The base to prepend to field names when using form_set_error().
+ * Needed because the admin settings form is embedded into a bigger form.
+ */
+ public function adminOptionsFormValidate($form, &$form_state, $error_element_base) {
+ parent::adminOptionsFormValidate($form, $form_state, $error_element_base);
+
+ if (!empty($form['settings'])) {
+ $settings_validation_callback = $this->operationInfo['callback'] . '_views_bulk_operations_form_validate';
+ if (function_exists($settings_validation_callback)) {
+ $fake_form = $form['settings'];
+ $fake_form_state = array('values' => &$form_state['values']['settings']);
+ $error_element_base .= 'settings][';
+
+ $settings_validation_callback($fake_form, $fake_form_state, $error_element_base);
+ }
+ }
+ }
+
+ /**
+ * Handles the submitted admin options form.
+ * Note that there is no need to handle saving the options, that is done
+ * by the VBO views field handler, which also injects the options into the
+ * operation object upon instantiation.
+ *
+ * @param $form
+ * The admin options form.
+ * @param $form_state
+ * An array containing the current state of the form. Note that this array
+ * is constructed by the VBO views field handler, so it's not a real form
+ * state, it contains only the 'values' key.
+ */
+ public function adminOptionsFormSubmit($form, &$form_state) {
+ parent::adminOptionsFormSubmit($form, $form_state);
+
+ if (!empty($form['settings'])) {
+ $settings_submit_callback = $this->operationInfo['callback'] . '_views_bulk_operations_form_submit';
+ if (function_exists($settings_submit_callback)) {
+ $fake_form = $form['settings'];
+ $fake_form_state = array('values' => &$form_state['values']['settings']);
+
+ $settings_submit_callback($form, $form_state);
+ }
+ }
+ }
+
+ /**
* Returns whether the operation needs the full selected views rows to be
* passed to execute() as a part of $context.
*/
diff --git a/plugins/operation_types/action.inc b/plugins/operation_types/action.inc
index 61a6cc5..3476df7 100644
--- a/plugins/operation_types/action.inc
+++ b/plugins/operation_types/action.inc
@@ -14,26 +14,50 @@ $plugin = array(
),
);
-function views_bulk_operations_operation_action_list() {
- $action_operations = actions_list() + views_bulk_operations_operation_advanced_action_list();
- $operations = array();
- foreach ($action_operations as $callback => $operation) {
- $key = isset($operation['key']) ? $operation['key'] : $callback;
- $operations[$key] = array(
- 'plugin' => 'action',
- 'key' => $key,
- 'label' => isset($operation['label']) ? $operation['label'] : '',
- 'callback' => $callback,
- 'parameters' => isset($operation['parameters']) ? $operation['parameters'] : array(),
- 'configurable' => !empty($operation['configurable']),
- 'type' => $operation['type'],
- 'aggregate' => !empty($operation['aggregate']),
- 'behavior' => isset($operation['behavior']) ? $operation['behavior'] : array(),
- 'permissions' => isset($operation['permissions']) ? $operation['permissions'] : NULL,
- 'pass rows' => !empty($operation['pass rows']),
- );
+/**
+ * Returns a prepared list of available actions.
+ *
+ * Actions are fetched by invoking hook_action_info() and by loading
+ * advanced actions from the database.
+ *
+ * @param $operation_id
+ * The full, prefixed operation_id of the operation (in this case, action)
+ * to return, or NULL to return an array with all operations.
+ */
+function views_bulk_operations_operation_action_list($operation_id = NULL) {
+ $operations = &drupal_static(__FUNCTION__);
+
+ if (!isset($operations)) {
+ $actions_list = actions_list() + views_bulk_operations_operation_advanced_action_list();
+ $operations = array();
+ foreach ($actions_list as $callback => $action) {
+ $key = isset($action['key']) ? $action['key'] : $callback;
+ // All operations must be prefixed with the operation type.
+ $new_operation_id = 'action::' . $key;
+
+ $operations[$new_operation_id] = array(
+ 'operation_type' => 'action',
+ 'type' => $action['type'],
+ // Keep the unprefixed key around, for use in admin labels and action permissions.
+ 'key' => $key,
+ 'callback' => $callback,
+ 'label' => isset($action['label']) ? $action['label'] : '',
+ 'parameters' => isset($action['parameters']) ? $action['parameters'] : array(),
+ 'configurable' => !empty($action['configurable']),
+ 'aggregate' => !empty($action['aggregate']),
+ 'behavior' => isset($action['behavior']) ? $action['behavior'] : array(),
+ 'permissions' => isset($action['permissions']) ? $action['permissions'] : NULL,
+ 'pass rows' => !empty($action['pass rows']),
+ );
+ }
+ }
+
+ if (isset($operation_id)) {
+ return isset($operations[$operation_id]) ? $operations[$operation_id] : FALSE;
+ }
+ else {
+ return $operations;
}
- return $operations;
}
/**
diff --git a/plugins/operation_types/base.class.php b/plugins/operation_types/base.class.php
index ee49634..0f9b68b 100644
--- a/plugins/operation_types/base.class.php
+++ b/plugins/operation_types/base.class.php
@@ -7,6 +7,14 @@
abstract class ViewsBulkOperationsBaseOperation {
/**
+ * The id of the operation.
+ *
+ * Composed of the operation_type plugin name and the operation key,
+ * divided by '::'. For example: action::node_publish_action.
+ */
+ public $operationId;
+
+ /**
* The entity type that the operation is operating on.
*
* Not the same as $operationInfo['type'] since that value can be just
@@ -32,6 +40,8 @@ abstract class ViewsBulkOperationsBaseOperation {
/**
* Constructs an operation object.
*
+ * @param $operationId
+ * The id of the operation.
* @param $entityType
* The entity type that the operation is operating on.
* @param $operationInfo
@@ -39,7 +49,8 @@ abstract class ViewsBulkOperationsBaseOperation {
* @param $adminOptions
* An array of options set by the admin.
*/
- public function __construct($entityType, array $operationInfo, array $adminOptions) {
+ public function __construct($operationId, $entityType, array $operationInfo, array $adminOptions) {
+ $this->operationId = $operationId;
$this->entityType = $entityType;
$this->operationInfo = $operationInfo;
$this->adminOptions = $adminOptions;
@@ -61,6 +72,20 @@ abstract class ViewsBulkOperationsBaseOperation {
}
/**
+ * Returns the id of the operation.
+ */
+ public function id() {
+ return $this->operationId;
+ }
+
+ /**
+ * Returns the name of the operation_type plugin that provides the operation.
+ */
+ public function type() {
+ return $this->operationInfo['operation_type'];
+ }
+
+ /**
* Returns the human-readable name of the operation, meant to be shown
* to the user.
*/
@@ -77,6 +102,15 @@ abstract class ViewsBulkOperationsBaseOperation {
}
/**
+ * Returns the human-readable name of the operation, meant to be shown
+ * to the admin.
+ */
+ public function adminLabel() {
+ $label = $this->operationInfo['label'] . ' (' . $this->operationInfo['key'] . ')';
+ return $label;
+ }
+
+ /**
* Returns whether the operation is configurable. Used to determine
* whether the operation's form methods should be invoked.
*/
@@ -130,6 +164,82 @@ abstract class ViewsBulkOperationsBaseOperation {
abstract function formSubmit($form, &$form_state);
/**
+ * Returns the admin options form for the operation.
+ *
+ * The admin options form is embedded into the VBO field settings and used
+ * to configure operation behavior. The options can later be fetched
+ * through the getAdminOption() method.
+ *
+ * @param $dom_id
+ * The dom path to the level where the admin options form is embedded.
+ * Needed for #dependency.
+ */
+ public function adminOptionsForm($dom_id) {
+ $label = $this->getAdminOption('label', '');
+
+ $form = array();
+ $form['override_label'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Override label'),
+ '#default_value' => $label !== '',
+ '#dependency' => array(
+ $dom_id . '-selected' => array(1),
+ ),
+ );
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Provide label'),
+ '#title_display' => 'invisible',
+ '#default_value' => $label,
+ '#dependency' => array(
+ $dom_id . '-selected' => array(1),
+ $dom_id . '-override-label' => array(1),
+ ),
+ '#dependency_count' => 2,
+ );
+
+ return $form;
+ }
+
+ /**
+ * Validates the admin options form.
+ *
+ * @param $form
+ * The admin options form.
+ * @param $form_state
+ * An array containing the current state of the form. Note that this array
+ * is constructed by the VBO views field handler, so it's not a real form
+ * state, it contains only the 'values' key.
+ * @param $error_element_base
+ * The base to prepend to field names when using form_set_error().
+ * Needed because the admin options form is embedded into a bigger form.
+ */
+ public function adminOptionsFormValidate($form, &$form_state, $error_element_base) {
+ // No need to do anything, but make the function have a body anyway
+ // so that it's callable by overriding methods.
+ }
+
+ /**
+ * Handles the submitted admin options form.
+ * Note that there is no need to handle saving the options, that is done
+ * by the VBO views field handler, which also injects the options into the
+ * operation object upon instantiation.
+ *
+ * @param $form
+ * The admin options form.
+ * @param $form_state
+ * An array containing the current state of the form. Note that this array
+ * is constructed by the VBO views field handler, so it's not a real form
+ * state, it contains only the 'values' key.
+ */
+ public function adminOptionsFormSubmit($form, &$form_state) {
+ // If the "Override label" checkbox was deselected, clear the entered value.
+ if (empty($form_state['values']['override_label'])) {
+ $form_state['values']['label'] = '';
+ }
+ }
+
+ /**
* Returns whether the selected entities should be aggregated
* (loaded in bulk and passed in together).
* To be avoided if possible, since aggregation makes it impossible to use
diff --git a/plugins/operation_types/rules_component.inc b/plugins/operation_types/rules_component.inc
index 94a1e74..61f8f71 100644
--- a/plugins/operation_types/rules_component.inc
+++ b/plugins/operation_types/rules_component.inc
@@ -14,7 +14,14 @@ $plugin = array(
),
);
-function views_bulk_operations_operation_rules_component_list() {
+/**
+ * Returns a prepared list of available rules components.
+ *
+ * @param $operation_id
+ * The full, prefixed operation_id of the operation (in this case, rules
+ * component) to return, or NULL to return an array with all operations.
+ */
+function views_bulk_operations_operation_rules_component_list($operation_id = NULL) {
if (!module_exists('rules')) {
return array();
}
@@ -29,8 +36,17 @@ function views_bulk_operations_operation_rules_component_list() {
$list_types[] = "list<$type>";
}
+ $components = array();
+ if (isset($operation_id)) {
+ $id_fragments = explode('::', $operation_id);
+ $components[$id_fragments[1]] = rules_config_load($id_fragments[1]);
+ }
+ else {
+ $components = rules_get_components(FALSE, 'action');
+ }
+
$operations = array();
- foreach (rules_get_components(FALSE, 'action') as $component_key => $component) {
+ foreach ($components as $name => $component) {
$parameter_info = $component->parameterInfo();
$first_parameter = reset($parameter_info);
$parameter_keys = array_keys($parameter_info);
@@ -51,16 +67,24 @@ function views_bulk_operations_operation_rules_component_list() {
$aggregate = FALSE;
}
- $operations[$component_key] = array(
- 'plugin' => 'rules_component',
- 'key' => $component_key,
+ // All operations must be prefixed with the operation type.
+ $new_operation_id = 'rules_component::' . $name;
+ $operations[$new_operation_id] = array(
+ 'operation_type' => 'rules_component',
+ // Keep the unprefixed key around, for use in admin labels.
+ 'key' => $name,
'label' => $component->label,
- 'parameters' => array('component_key' => $component_key, 'entity_key' => $entity_key),
+ 'parameters' => array('component_key' => $name, 'entity_key' => $entity_key),
'configurable' => count($parameter_info) > 1,
'type' => $type,
'aggregate' => $aggregate,
);
}
- return $operations;
+ if (isset($operation_id)) {
+ return isset($operations[$operation_id]) ? $operations[$operation_id] : FALSE;
+ }
+ else {
+ return $operations;
+ }
}
diff --git a/views/views_bulk_operations.views_default.inc b/views/views_bulk_operations.views_default.inc
index e1c6006..d86e1eb 100644
--- a/views/views_bulk_operations.views_default.inc
+++ b/views/views_bulk_operations.views_default.inc
@@ -114,83 +114,83 @@ function views_bulk_operations_views_default_views() {
$handler->display->display_options['fields']['views_bulk_operations']['empty_zero'] = 0;
$handler->display->display_options['fields']['views_bulk_operations']['hide_alter_empty'] = 0;
$handler->display->display_options['fields']['views_bulk_operations']['vbo']['operations'] = array(
- 'node_assign_owner_action' => array(
+ 'action::node_assign_owner_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_delete_item' => array(
+ 'action::views_bulk_operations_delete_item' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_script_action' => array(
+ 'action::views_bulk_operations_script_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_make_sticky_action' => array(
+ 'action::node_make_sticky_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_make_unsticky_action' => array(
+ 'action::node_make_unsticky_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_argument_selector_action' => array(
+ 'action::views_bulk_operations_argument_selector_action' => array(
'selected' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_promote_action' => array(
+ 'action::node_promote_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_publish_action' => array(
+ 'action::node_publish_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_unpromote_action' => array(
+ 'action::node_unpromote_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_save_action' => array(
+ 'action::node_save_action' => array(
'selected' => 0,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_unpublish_action' => array(
+ 'action::node_unpublish_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'node_unpublish_by_keyword_action' => array(
+ 'action::node_unpublish_by_keyword_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
@@ -308,9 +308,9 @@ function views_bulk_operations_views_default_views() {
$handler->display->display_options['fields']['status']['hide_empty'] = 0;
$handler->display->display_options['fields']['status']['empty_zero'] = 0;
$handler->display->display_options['fields']['status']['not'] = 0;
- /* Field: Content: Edit link */
+ /* Field: Node: Edit link */
$handler->display->display_options['fields']['edit_node']['id'] = 'edit_node';
- $handler->display->display_options['fields']['edit_node']['table'] = 'node';
+ $handler->display->display_options['fields']['edit_node']['table'] = 'views_entity_node';
$handler->display->display_options['fields']['edit_node']['field'] = 'edit_node';
$handler->display->display_options['fields']['edit_node']['label'] = 'Edit';
$handler->display->display_options['fields']['edit_node']['alter']['alter_text'] = 0;
@@ -386,31 +386,6 @@ function views_bulk_operations_views_default_views() {
/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page');
$handler->display->display_options['path'] = 'admin/content2';
- $translatables['admin_content'] = array(
- t('Master'),
- t('Content'),
- t('more'),
- t('Apply'),
- t('Reset'),
- t('Sort by'),
- t('Asc'),
- t('Desc'),
- t('Items per page'),
- t('- All -'),
- t('Offset'),
- t('No content available.'),
- t('author'),
- t('Title'),
- t('New?'),
- t('Type'),
- t('Author'),
- t('Published'),
- t('Edit'),
- t('Title contains'),
- t('Node: Type'),
- t('Promoted'),
- t('Page'),
- );
$views[$view->name] = $view;
$view = new view;
@@ -509,42 +484,42 @@ function views_bulk_operations_views_default_views() {
$handler->display->display_options['fields']['views_bulk_operations']['empty_zero'] = 0;
$handler->display->display_options['fields']['views_bulk_operations']['hide_alter_empty'] = 0;
$handler->display->display_options['fields']['views_bulk_operations']['vbo']['operations'] = array(
- 'system_block_ip_action' => array(
+ 'action::system_block_ip_action' => array(
'selected' => 0,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'user_block_user_action' => array(
+ 'action::user_block_user_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_delete_item' => array(
+ 'action::views_bulk_operations_delete_item' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_script_action' => array(
+ 'action::views_bulk_operations_script_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_user_roles_action' => array(
+ 'action::views_bulk_operations_user_roles_action' => array(
'selected' => 1,
'use_queue' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
'label' => '',
),
- 'views_bulk_operations_argument_selector_action' => array(
+ 'action::views_bulk_operations_argument_selector_action' => array(
'selected' => 0,
'skip_confirmation' => 0,
'override_label' => 0,
@@ -718,27 +693,6 @@ function views_bulk_operations_views_default_views() {
/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page');
$handler->display->display_options['path'] = 'admin/people2';
- $translatables['admin_people'] = array(
- t('Master'),
- t('People'),
- t('more'),
- t('Apply'),
- t('Reset'),
- t('Sort by'),
- t('Asc'),
- t('Desc'),
- t('Items per page'),
- t('- All -'),
- t('Offset'),
- t('Username'),
- t('Active'),
- t('Member for'),
- t('Roles'),
- t('Last access'),
- t('Operations'),
- t('Role'),
- t('Page'),
- );
$views[$view->name] = $view;
return $views;
diff --git a/views/views_bulk_operations_handler_field_operations.inc b/views/views_bulk_operations_handler_field_operations.inc
index 86406e0..db5edc0 100644
--- a/views/views_bulk_operations_handler_field_operations.inc
+++ b/views/views_bulk_operations_handler_field_operations.inc
@@ -7,22 +7,36 @@
*/
class views_bulk_operations_handler_field_operations extends views_handler_field {
- var $all_operations = array();
var $revision = FALSE;
function init(&$view, &$options) {
parent::init($view, $options);
- $this->populate_operations();
-
// Update old settings.
if (!empty($options['vbo']['selected_operations'])) {
- foreach (array_filter($options['vbo']['selected_operations']) as $key) {
- $this->options['vbo']['operations'][$key]['selected'] = TRUE;
- $this->options['vbo']['operations'][$key]['skip_confirmation'] = $options['vbo']['skip_confirmation'];
+ foreach (array_filter($options['vbo']['selected_operations']) as $operation_id) {
+ $this->options['vbo']['operations'][$operation_id]['selected'] = TRUE;
+ $this->options['vbo']['operations'][$operation_id]['skip_confirmation'] = $options['vbo']['skip_confirmation'];
}
unset($this->options['vbo']['selected_operations']);
}
+ // Prefix all un-prefixed operations.
+ foreach ($this->options['vbo']['operations'] as $operation_id => &$operation_options) {
+ if (strpos($operation_id, '::') === FALSE) {
+ $operations = views_bulk_operations_get_operation_info();
+ // Basically, guess.
+ foreach (array('action', 'rules_component') as $operation_type) {
+ $new_operation_id = $operation_type . '::' . $operation_id;
+ if (isset($operations[$new_operation_id])) {
+ $this->options['vbo']['operations'][$new_operation_id] = $operation_options;
+ break;
+ }
+ }
+
+ // Remove the old operation in any case.
+ unset($this->options['vbo']['operations'][$operation_id]);
+ }
+ }
}
function option_definition() {
@@ -100,106 +114,71 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
- foreach ($this->get_operations_options() as $key => $label) {
- $options = isset($this->options['vbo']['operations'][$key]) ? $this->options['vbo']['operations'][$key] : array();
- $dom_id = 'edit-options-vbo-operations-' . str_replace(array('_', ':'), array('-', ''), $key);
- $form['vbo']['operations'][$key]['selected'] = array(
+ $entity_type = $this->get_entity_type();
+ $options = $this->options['vbo']['operations'];
+ foreach (views_bulk_operations_get_applicable_operations($entity_type, $options) as $operation_id => $operation) {
+ $operation_options = isset($options[$operation_id]) ? $options[$operation_id] : array();
+
+ $dom_id = 'edit-options-vbo-operations-' . str_replace(array('_', ':'), array('-', ''), $operation_id);
+ $form['vbo']['operations'][$operation_id]['selected'] = array(
'#type' => 'checkbox',
- '#title' => $label,
- '#default_value' => !empty($options['selected']),
+ '#title' => $operation->adminLabel(),
+ '#default_value' => !empty($operation_options['selected']),
);
- if (!$this->all_operations[$key]['aggregate']) {
- $form['vbo']['operations'][$key]['use_queue'] = array(
+ if (!$operation->aggregate()) {
+ $form['vbo']['operations'][$operation_id]['use_queue'] = array(
'#type' => 'checkbox',
'#title' => t('Enqueue the operation instead of executing it directly'),
- '#default_value' => !empty($options['use_queue']),
+ '#default_value' => !empty($operation_options['use_queue']),
'#dependency' => array(
$dom_id . '-selected' => array(1),
),
);
}
- $form['vbo']['operations'][$key]['skip_confirmation'] = array(
+ $form['vbo']['operations'][$operation_id]['skip_confirmation'] = array(
'#type' => 'checkbox',
'#title' => t('Skip confirmation step'),
- '#default_value' => !empty($options['skip_confirmation']),
- '#dependency' => array(
- $dom_id . '-selected' => array(1),
- ),
- );
- $show_label = isset($options['label']) ? $options['label'] : '';
- $form['vbo']['operations'][$key]['override_label'] = array(
- '#type' => 'checkbox',
- '#title' => t('Override label'),
- '#default_value' => $show_label !== '',
- '#dependency' => array(
- $dom_id . '-selected' => array(1),
- ),
- );
- $form['vbo']['operations'][$key]['label'] = array(
- '#type' => 'textfield',
- '#title' => t('Provide label'),
- '#title_display' => 'invisible',
- '#default_value' => $show_label,
+ '#default_value' => !empty($operation_options['skip_confirmation']),
'#dependency' => array(
$dom_id . '-selected' => array(1),
- $dom_id . '-override-label' => array(1),
),
- '#dependency_count' => 2,
);
- $form_function = $this->all_operations[$key]['callback'] . '_views_bulk_operations_form';
- if (function_exists($form_function)) {
- $settings = isset($options['settings']) ? $options['settings'] : array();
- $form_settings = call_user_func($form_function, $settings);
- $form['vbo']['operations'][$key]['settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Operation settings'),
- '#collapsible' => TRUE,
- '#dependency' => array(
- $dom_id . '-selected' => array(1),
- ),
- );
- $form['vbo']['operations'][$key]['settings'] += $form_settings;
- }
+
+ $form['vbo']['operations'][$operation_id] += $operation->adminOptionsForm($dom_id);
}
}
function options_validate(&$form, &$form_state) {
parent::options_validate($form, $form_state);
- foreach ($form_state['values']['options']['vbo']['operations'] as $key => &$options) {
- if (empty($options['selected']) || !isset($options['settings'])) {
+ $entity_type = $this->get_entity_type();
+ foreach ($form_state['values']['options']['vbo']['operations'] as $operation_id => &$options) {
+ if (empty($options['selected'])) {
continue;
}
- $operation = $this->all_operations[$key];
- $form_function = $operation['callback'] . '_views_bulk_operations_form_validate';
- if (function_exists($form_function)) {
- $options['settings']['_error_element_base'] = 'vbo][operations][' . $key . '][settings][';
- call_user_func($form_function, $form, array('values' => $options['settings']));
- }
+
+ $operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options);
+ $fake_form = $form['vbo']['operations'][$operation_id];
+ $fake_form_state = array('values' => &$options);
+ $error_element_base = 'vbo][operations][' . $operation_id . '][';
+ $operation->adminOptionsFormValidate($fake_form, $fake_form_state, $error_element_base);
}
}
function options_submit(&$form, &$form_state) {
parent::options_submit($form, $form_state);
- foreach ($form_state['values']['options']['vbo']['operations'] as $key => &$options) {
+ $entity_type = $this->get_entity_type();
+ foreach ($form_state['values']['options']['vbo']['operations'] as $operation_id => &$options) {
if (empty($options['selected'])) {
continue;
}
- // If the "Override label" checkbox was deselected, clear the entered value.
- if (empty($options['override_label'])) {
- $options['label'] = '';
- }
- // This action has its own settings, call the submit function that
- // should handle them (if any).
- if (!empty($options['settings'])) {
- $operation = $this->all_operations[$key];
- $form_function = $operation['callback'] . '_views_bulk_operations_form_submit';
- if (function_exists($form_function)) {
- call_user_func($form_function, $form, array('values' => $options['settings']));
- }
- }
+
+ $operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options);
+ $fake_form = $form['vbo']['operations'][$operation_id];
+ $fake_form_state = array('values' => &$options);
+ $operation->adminOptionsFormSubmit($fake_form, $fake_form_state);
}
}
@@ -255,77 +234,39 @@ class views_bulk_operations_handler_field_operations extends views_handler_field
}
}
- function get_selected_operations() {
+ public function get_selected_operations() {
global $user;
+ $entity_type = $this->get_entity_type();
$selected = array();
- foreach ($this->options['vbo']['operations'] as $key => $options) {
- if (empty($options['selected']) || !isset($this->all_operations[$key])) {
+ foreach ($this->options['vbo']['operations'] as $operation_id => $options) {
+ if (empty($options['selected'])) {
continue;
}
- $operation = $this->get_operation($key);
- if (!$operation->access($user)) {
+ $operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options);
+ if (!$operation || !$operation->access($user)) {
continue;
}
- $selected[$key] = $operation->label();
- }
- return $selected;
- }
-
- function get_operation($key) {
- if (empty($this->all_operations[$key])) {
- return NULL;
+ $selected[$operation_id] = $operation;
}
- $operations = &drupal_static(__FUNCTION__);
- if (!isset($operations[$key])) {
- $operation_info = $this->all_operations[$key];
- $entity_type = $this->get_entity_type();
- $plugin = views_bulk_operations_get_operation_type($operation_info['plugin']);
-
- $operations[$key] = new $plugin['handler']['class']($entity_type, $operation_info, $this->options['vbo']['operations'][$key]);
- }
- return $operations[$key];
- }
-
- private function get_operations_options() {
- $options = array();
- $entity_type = $this->get_entity_type();
- foreach ($this->all_operations as $key => $operation) {
- if ($operation['type'] == 'entity' || $operation['type'] == 'system') { // Actions that accept any entity type.
- $operation['type'] = $entity_type;
- }
- if ($operation['type'] == $entity_type) {
- $options[$key] = $operation['label'] .' ('. $key .')';
- }
- }
- return $options;
+ return $selected;
}
- private function populate_operations() {
- // The operations have already been populated.
- if (!empty($this->all_operations)) {
- return;
- }
-
- $operations = array();
- $plugins = views_bulk_operations_get_operation_types();
- foreach ($plugins as $plugin) {
- if (isset($plugin['list callback']) && function_exists($plugin['list callback'])) {
- $operations += $plugin['list callback']();
- }
- }
-
- uasort($operations, create_function('$a, $b', 'return strcasecmp($a["label"], $b["label"]);'));
- $this->all_operations = $operations;
+ /**
+ * Returns the options stored for the provided operation id.
+ */
+ public function get_operation_options($operation_id) {
+ $options = $this->options['vbo']['operations'];
+ return isset($options[$operation_id]) ? $options[$operation_id] : array();
}
/**
* Determine the base table of the VBO field, and then use it to determine
* the entity type that VBO is operating on.
*/
- function get_entity_type() {
+ public function get_entity_type() {
$base_table = $this->view->base_table;
// If the current field is under a relationship you can't be sure that the
diff --git a/views_bulk_operations.drush.inc b/views_bulk_operations.drush.inc
index e9dca04..8604434 100644
--- a/views_bulk_operations.drush.inc
+++ b/views_bulk_operations.drush.inc
@@ -25,15 +25,15 @@ function views_bulk_operations_drush_command() {
'description' => 'Execute a bulk operation based on a Views Bulk Operations (VBO) view.',
'arguments' => array(
'vid' => 'ID or name of the view to be executed.',
- 'operation' => 'Callback name of the operation to be applied on the view results.',
+ 'operation_id' => 'ID of the operation to be applied on the view results.',
'type:[name=]value ...' => 'Parameters to be passed as view input filters, view arguments or operation arguments, where type is respectively {input, argument, operation}.',
),
'examples' => array(
- '$ drush vbo-execute admin_content node_publish_action' =>
+ '$ drush vbo-execute action::admin_content node_publish_action' =>
'Publish nodes returned by view admin_content.',
- '$ drush vbo-execute 44 node_assign_owner_action operation:owner_uid=3' =>
+ '$ drush vbo-execute 44 action::node_assign_owner_action operation:owner_uid=3' =>
'Change node ownership on nodes returned by view #44, passing argument owner_uid=3 to the action.',
- '$ drush vbo-execute admin_content node_unpublish_action input:type=expense argument:3' =>
+ '$ drush vbo-execute admin_content action::node_unpublish_action input:type=expense argument:3' =>
'Unpublish nodes returned by view admin_content, filtering results of type expense and passing value 3 as first view argument.',
),
);
@@ -56,8 +56,8 @@ function views_bulk_operations_drush_list() {
$vbo = _views_bulk_operations_get_field($view);
if ($vbo) {
$operations = array();
- foreach ($vbo->get_selected_operations() as $operation => $label) {
- $operations[] = $label .' ('. $operation .')';
+ foreach ($vbo->get_selected_operations() as $operation_id => $operation) {
+ $operations[] = $operation->label() .' ('. $operation_id .')';
}
$operations[] = "---------------";
$rows[] = array(
@@ -74,13 +74,13 @@ function views_bulk_operations_drush_list() {
/**
* Implementation of 'vbo execute' command.
*/
-function views_bulk_operations_drush_execute($vid = NULL, $operation = NULL) {
+function views_bulk_operations_drush_execute($vid = NULL, $operation_id = NULL) {
// Parse arguments.
if (is_null($vid)) {
drush_set_error('VIEWS_BULK_OPERATIONS_MISSING_VID', dt('Please specify a view ID to execute.'));
return;
}
- if (is_null($operation)) {
+ if (is_null($operation_id)) {
drush_set_error('VIEWS_BULK_OPERATIONS_MISSING_OPERATION', dt('Please specify an operation to execute.'));
return;
}
@@ -116,5 +116,5 @@ function views_bulk_operations_drush_execute($vid = NULL, $operation = NULL) {
drupal_save_session(FALSE);
// Execute the VBO.
- views_bulk_operations_execute($vid, $operation, $operation_arguments, $view_exposed_input, $view_arguments);
+ views_bulk_operations_execute($vid, $operation_id, $operation_arguments, $view_exposed_input, $view_arguments);
}
diff --git a/views_bulk_operations.module b/views_bulk_operations.module
index c270b7a..26f2f93 100644
--- a/views_bulk_operations.module
+++ b/views_bulk_operations.module
@@ -101,6 +101,7 @@ function views_bulk_operations_theme() {
$themes += call_user_func($action_theme_fn);
}
}
+
return $themes;
}
@@ -152,6 +153,88 @@ function views_bulk_operations_get_operation_types() {
}
/**
+ * Gets the info array of an operation from the provider plugin.
+ *
+ * @param $operation_id
+ * The id of the operation for which the info shall be returned, or NULL
+ * to return an array with info about all operations.
+ */
+function views_bulk_operations_get_operation_info($operation_id = NULL) {
+ $operations = &drupal_static(__FUNCTION__);
+
+ if (!isset($operations)) {
+ $operations = array();
+ $plugins = views_bulk_operations_get_operation_types();
+ foreach ($plugins as $plugin) {
+ $operations += $plugin['list callback']();
+ }
+
+ uasort($operations, create_function('$a, $b', 'return strcasecmp($a["label"], $b["label"]);'));
+ }
+
+ if (!empty($operation_id)) {
+ return $operations[$operation_id];
+ }
+ else {
+ return $operations;
+ }
+}
+
+/**
+ * Returns an operation instance.
+ *
+ * @param $operation_id
+ * The id of the operation to instantiate.
+ * For example: action::node_publish_action.
+ * @param $entity_type
+ * The entity type on which the operation operates.
+ * @param $options
+ * Options for this operation (label, operation settings, etc.)
+ */
+function views_bulk_operations_get_operation($operation_id, $entity_type, $options) {
+ $operations = &drupal_static(__FUNCTION__);
+
+ if (!isset($operations[$operation_id])) {
+ // Intentionally not using views_bulk_operations_get_operation_info() here
+ // since it's an expensive function that loads all the operations on the
+ // system, despite the fact that we might only need a few.
+ $id_fragments = explode('::', $operation_id);
+ $plugin = views_bulk_operations_get_operation_type($id_fragments[0]);
+ $operation_info = $plugin['list callback']($operation_id);
+
+ if ($operation_info) {
+ $operations[$operation_id] = new $plugin['handler']['class']($operation_id, $entity_type, $operation_info, $options);
+ }
+ else {
+ $operations[$operation_id] = FALSE;
+ }
+ }
+
+ return $operations[$operation_id];
+}
+
+/**
+ * Get all operations that match the current entity type.
+ *
+ * @param $entity_type
+ * Entity type.
+ * @param $options
+ * An array of options for all operations, in the form of
+ * $operation_id => $operation_options.
+ */
+function views_bulk_operations_get_applicable_operations($entity_type, $options) {
+ $operations = array();
+ foreach (views_bulk_operations_get_operation_info() as $operation_id => $operation_info) {
+ if ($operation_info['type'] == $entity_type || $operation_info['type'] == 'entity' || $operation_info['type'] == 'system') {
+ $options[$operation_id] = !empty($options[$operation_id]) ? $options[$operation_id] : array();
+ $operations[$operation_id] = views_bulk_operations_get_operation($operation_id, $entity_type, $options[$operation_id]);
+ }
+ }
+
+ return $operations;
+}
+
+/**
* Gets the VBO field if it exists on the passed-in view.
*
* @return
@@ -323,11 +406,10 @@ function views_bulk_operations_form($form, &$form_state, $vbo) {
'#value' => TRUE,
);
- $selected_operations = array_keys($vbo->get_selected_operations());
- $operation = $vbo->get_operation($selected_operations[0]);
+ $selected_operations = $vbo->get_selected_operations();
+ $operation = reset($selected_operations);
if ($operation->configurable()) {
$context = array(
- 'settings' => $operation->getAdminOption('settings', array()),
// Pass the View along. Needed by views_send 7.x-1.x.
// Has no performance penalty since objects are passed by reference,
// but needing the full views object in a core action is in most cases
@@ -357,10 +439,15 @@ function views_bulk_operations_form($form, &$form_state, $vbo) {
'#attributes' => array('class' => array('container-inline')),
);
if ($vbo->options['vbo']['display_type'] == 0) {
+ $options = array(0 => t('- Choose an operation -'));
+ foreach ($vbo->get_selected_operations() as $operation_id => $operation) {
+ $options[$operation_id] = $operation->label();
+ }
+
// Create dropdown and submit button.
$form['select']['operation'] = array(
'#type' => 'select',
- '#options' => array(0 => t('- Choose an operation -')) + $vbo->get_selected_operations(),
+ '#options' => $options,
);
$form['select']['submit'] = array(
'#type' => 'submit',
@@ -369,11 +456,11 @@ function views_bulk_operations_form($form, &$form_state, $vbo) {
}
else {
// Create buttons for operations.
- foreach ($vbo->get_selected_operations() as $md5 => $description) {
- $form['select'][$md5] = array(
+ foreach ($vbo->get_selected_operations() as $operation_id => $operation) {
+ $form['select'][$operation_id] = array(
'#type' => 'submit',
- '#value' => $description,
- '#hash' => $md5,
+ '#value' => $operation->label(),
+ '#operation_id' => $operation_id,
);
}
}
@@ -408,7 +495,6 @@ function views_bulk_operations_config_form($form, &$form_state, $view, $output)
drupal_set_title(t('Set parameters for %operation', array('%operation' => $operation->label())), PASS_THROUGH);
$context = array(
- 'settings' => $operation->getAdminOption('settings', array()),
// Pass the View along. Needed by views_send 7.x-1.x.
// Has no performance penalty since objects are passed by reference,
// but needing the full views object in a core action is in most cases
@@ -541,8 +627,8 @@ function views_bulk_operations_form_validate($form, &$form_state) {
}
}
else {
- if (!empty($form_state['triggering_element']['#hash'])) {
- $form_state['values']['operation'] = $form_state['triggering_element']['#hash'];
+ if (!empty($form_state['triggering_element']['#operation_id'])) {
+ $form_state['values']['operation'] = $form_state['triggering_element']['#operation_id'];
}
if (!$form_state['values']['operation']) {
form_set_error('operation', t('No operation selected. Please select an operation to perform.'));
@@ -573,6 +659,7 @@ function views_bulk_operations_form_validate($form, &$form_state) {
*/
function views_bulk_operations_form_submit($form, &$form_state) {
$vbo = _views_bulk_operations_get_field($form_state['build_info']['args'][0]);
+ $entity_type = $vbo->get_entity_type();
switch ($form_state['step']) {
case 'views_form_views_form':
@@ -594,7 +681,8 @@ function views_bulk_operations_form_submit($form, &$form_state) {
$form_state['step'] = 'views_bulk_operations_confirm_form';
}
else {
- $form_state['operation'] = $operation = $vbo->get_operation($form_state['values']['operation']);
+ $options = $vbo->get_operation_options($form_state['values']['operation']);
+ $form_state['operation'] = $operation = views_bulk_operations_get_operation($form_state['values']['operation'], $entity_type, $options);
if (!$operation->configurable() && $operation->getAdminOption('skip_confirmation')) {
break; // Go directly to execution
}
@@ -1062,7 +1150,7 @@ function _views_bulk_operations_entity_label($entity_type, $entity) {
/**
* API function to programmatically invoke a VBO.
*/
-function views_bulk_operations_execute($vid, $operation_callback, $operation_arguments = array(), $view_exposed_input = array(), $view_arguments = array()) {
+function views_bulk_operations_execute($vid, $operation_id, $operation_arguments = array(), $view_exposed_input = array(), $view_arguments = array()) {
$view = views_get_view($vid);
if (!is_object($view)) {
_views_bulk_operations_report_error('Could not find view %vid.', array('%vid' => $vid));
@@ -1087,11 +1175,11 @@ function views_bulk_operations_execute($vid, $operation_callback, $operation_arg
// Find the selected operation.
$operations = $vbo->get_selected_operations();
- if (!isset($operations[$operation_callback])) {
- _views_bulk_operations_report_error('Could not find operation %operation in view %vid.', array('%operation' => $operation_callback, '%vid' => $vid));
+ if (!isset($operations[$operation_id])) {
+ _views_bulk_operations_report_error('Could not find operation %operation_id in view %vid.', array('%operation_id' => $operation_id, '%vid' => $vid));
return;
}
- $operation = $vbo->get_operation($operation_callback);
+ $operation = views_bulk_operations_get_operation($operation_id, $vbo->get_entity_type(), $vbo->get_operation_options($operation_id));
if ($operation_arguments) {
$operation->formOptions = $operation_arguments;
}