views_bulk_operations_handler_field_operations.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. * @file
  4. * Views field handler. Contains all relevant VBO options and related logic.
  5. * Implements the Views Form API.
  6. */
  7. class views_bulk_operations_handler_field_operations extends views_handler_field {
  8. var $revision = FALSE;
  9. function init(&$view, &$options) {
  10. parent::init($view, $options);
  11. // Update old settings
  12. if (!empty($options['vbo']) && empty($this->options['vbo_operations'])) {
  13. $this->options['vbo_operations'] = $options['vbo']['operations'];
  14. unset($options['vbo']['operations']);
  15. $this->options['vbo_settings'] = $options['vbo'] + $this->options['vbo_settings'];
  16. }
  17. // When updating old Views it is possible for this value to stay empty.
  18. if (empty($this->options['vbo_settings']['entity_load_capacity'])) {
  19. $this->options['vbo_settings']['entity_load_capacity'] = 10;
  20. }
  21. foreach ($this->options['vbo_operations'] as $operation_id => &$operation_options) {
  22. // Prefix all un-prefixed operations.
  23. if (strpos($operation_id, '::') === FALSE) {
  24. $operations = views_bulk_operations_get_operation_info();
  25. // Basically, guess.
  26. foreach (array('action', 'rules_component') as $operation_type) {
  27. $new_operation_id = $operation_type . '::' . $operation_id;
  28. if (isset($operations[$new_operation_id])) {
  29. $this->options['vbo_operations'][$new_operation_id] = $operation_options;
  30. break;
  31. }
  32. }
  33. // Remove the old operation in any case.
  34. unset($this->options['vbo_operations'][$operation_id]);
  35. }
  36. // Rename the use_queue setting.
  37. if (isset($operation_options['use_queue']) && !isset($operation_options['postpone_processing'])) {
  38. $operation_options['postpone_processing'] = $operation_options['use_queue'];
  39. unset($operation_options['use_queue']);
  40. }
  41. }
  42. }
  43. function option_definition() {
  44. $options = parent::option_definition();
  45. $options['vbo_settings'] = array(
  46. 'contains' => array(
  47. 'display_type' => array('default' => 0),
  48. 'enable_select_all_pages' => array('default' => TRUE),
  49. 'force_single' => array('default' => FALSE),
  50. 'entity_load_capacity' => array('default' => 10),
  51. ),
  52. );
  53. $options['vbo_operations'] = array(
  54. 'default' => array(),
  55. );
  56. return $options;
  57. }
  58. function options_form(&$form, &$form_state) {
  59. parent::options_form($form, $form_state);
  60. $form['vbo_settings'] = array(
  61. '#type' => 'fieldset',
  62. '#title' => t('Bulk operations settings'),
  63. '#collapsible' => TRUE,
  64. '#collapsed' => TRUE,
  65. );
  66. $form['vbo_settings']['display_type'] = array(
  67. '#type' => 'radios',
  68. '#title' => t('Display operations as'),
  69. '#default_value' => $this->options['vbo_settings']['display_type'],
  70. '#options' => array(
  71. t('Dropdown selectbox with Submit button'),
  72. t('Each action as a separate button'),
  73. ),
  74. );
  75. $form['vbo_settings']['enable_select_all_pages'] = array(
  76. '#type' => 'checkbox',
  77. '#title' => t('Enable "Select all items on all pages"'),
  78. '#default_value' => $this->options['vbo_settings']['enable_select_all_pages'],
  79. '#description' => t('Check this box to enable the ability to select all items on all pages.'),
  80. );
  81. $form['vbo_settings']['force_single'] = array(
  82. '#type' => 'checkbox',
  83. '#title' => t('Force single'),
  84. '#default_value' => $this->options['vbo_settings']['force_single'],
  85. '#description' => t('Check this box to restrict selection to a single value.'),
  86. );
  87. $form['vbo_settings']['entity_load_capacity'] = array(
  88. '#type' => 'textfield',
  89. '#title' => t('Number of entities to load at once'),
  90. '#description' => t("Improve execution performance at the cost of memory usage. Set to '1' if you're having problems."),
  91. '#default_value' => $this->options['vbo_settings']['entity_load_capacity'],
  92. );
  93. // Display operations and their settings.
  94. $form['vbo_operations'] = array(
  95. '#tree' => TRUE,
  96. '#type' => 'fieldset',
  97. '#title' => t('Selected bulk operations'),
  98. '#collapsible' => TRUE,
  99. '#collapsed' => FALSE,
  100. );
  101. $entity_type = $this->get_entity_type();
  102. $options = $this->options['vbo_operations'];
  103. foreach (views_bulk_operations_get_applicable_operations($entity_type, $options) as $operation_id => $operation) {
  104. $operation_options = !empty($options[$operation_id]) ? $options[$operation_id] : array();
  105. $dom_id = 'edit-options-vbo-operations-' . str_replace(array('_', ':'), array('-', ''), $operation_id);
  106. $form['vbo_operations'][$operation_id]['selected'] = array(
  107. '#type' => 'checkbox',
  108. '#title' => $operation->adminLabel(),
  109. '#default_value' => !empty($operation_options['selected']),
  110. );
  111. if (!$operation->aggregate()) {
  112. $form['vbo_operations'][$operation_id]['postpone_processing'] = array(
  113. '#type' => 'checkbox',
  114. '#title' => t('Enqueue the operation instead of executing it directly'),
  115. '#default_value' => !empty($operation_options['postpone_processing']),
  116. '#dependency' => array(
  117. $dom_id . '-selected' => array(1),
  118. ),
  119. );
  120. }
  121. $form['vbo_operations'][$operation_id]['skip_confirmation'] = array(
  122. '#type' => 'checkbox',
  123. '#title' => t('Skip confirmation step'),
  124. '#default_value' => !empty($operation_options['skip_confirmation']),
  125. '#dependency' => array(
  126. $dom_id . '-selected' => array(1),
  127. ),
  128. );
  129. $form['vbo_operations'][$operation_id] += $operation->adminOptionsForm($dom_id);
  130. }
  131. }
  132. function options_validate(&$form, &$form_state) {
  133. parent::options_validate($form, $form_state);
  134. $entity_type = $this->get_entity_type();
  135. foreach ($form_state['values']['options']['vbo_operations'] as $operation_id => &$options) {
  136. if (empty($options['selected'])) {
  137. continue;
  138. }
  139. $operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options);
  140. $fake_form = $form['vbo_operations'][$operation_id];
  141. $fake_form_state = array('values' => &$options);
  142. $error_element_base = 'vbo_operations][' . $operation_id . '][';
  143. $operation->adminOptionsFormValidate($fake_form, $fake_form_state, $error_element_base);
  144. }
  145. }
  146. function options_submit(&$form, &$form_state) {
  147. parent::options_submit($form, $form_state);
  148. $entity_type = $this->get_entity_type();
  149. foreach ($form_state['values']['options']['vbo_operations'] as $operation_id => &$options) {
  150. if (empty($options['selected'])) {
  151. continue;
  152. }
  153. $operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options);
  154. $fake_form = $form['vbo_operations'][$operation_id];
  155. $fake_form_state = array('values' => &$options);
  156. $operation->adminOptionsFormSubmit($fake_form, $fake_form_state);
  157. }
  158. }
  159. /**
  160. * Returns the value of a vbo option.
  161. */
  162. function get_vbo_option($key, $default = NULL) {
  163. return isset($this->options['vbo_settings'][$key]) ? $this->options['vbo_settings'][$key] : $default;
  164. }
  165. /**
  166. * If the view is using a table style, provide a
  167. * placeholder for a "select all" checkbox.
  168. */
  169. function label() {
  170. if (!empty($this->view->style_plugin) && $this->view->style_plugin instanceof views_plugin_style_table && !$this->options['vbo_settings']['force_single']) {
  171. return '<!--views-bulk-operations-select-all-->';
  172. }
  173. else {
  174. return parent::label();
  175. }
  176. }
  177. function render($values) {
  178. return '<!--form-item-' . $this->options['id'] . '--' . $this->view->row_index . '-->';
  179. }
  180. /**
  181. * The form which replaces the placeholder from render().
  182. */
  183. function views_form(&$form, &$form_state) {
  184. // The view is empty, abort.
  185. if (empty($this->view->result)) {
  186. return;
  187. }
  188. $form[$this->options['id']] = array(
  189. '#tree' => TRUE,
  190. );
  191. // At this point, the query has already been run, so we can access the results
  192. // in order to get the base key value (for example, nid for nodes).
  193. foreach ($this->view->result as $row_index => $row) {
  194. $entity_id = $this->get_value($row);
  195. if ($this->options['vbo_settings']['force_single']) {
  196. $form[$this->options['id']][$row_index] = array(
  197. '#type' => 'radio',
  198. '#parents' => array($this->options['id']),
  199. '#return_value' => $entity_id,
  200. );
  201. }
  202. else {
  203. $form[$this->options['id']][$row_index] = array(
  204. '#type' => 'checkbox',
  205. '#return_value' => $entity_id,
  206. '#default_value' => FALSE,
  207. '#attributes' => array('class' => array('vbo-select')),
  208. );
  209. }
  210. }
  211. }
  212. public function get_selected_operations() {
  213. global $user;
  214. $selected = drupal_static(__FUNCTION__);
  215. if (!isset($selected)) {
  216. $entity_type = $this->get_entity_type();
  217. $selected = array();
  218. foreach ($this->options['vbo_operations'] as $operation_id => $options) {
  219. if (empty($options['selected'])) {
  220. continue;
  221. }
  222. $operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options);
  223. if (!$operation || !$operation->access($user)) {
  224. continue;
  225. }
  226. $selected[$operation_id] = $operation;
  227. }
  228. }
  229. return $selected;
  230. }
  231. /**
  232. * Returns the options stored for the provided operation id.
  233. */
  234. public function get_operation_options($operation_id) {
  235. $options = $this->options['vbo_operations'];
  236. return isset($options[$operation_id]) ? $options[$operation_id] : array();
  237. }
  238. /**
  239. * Determine the base table of the VBO field, and then use it to determine
  240. * the entity type that VBO is operating on.
  241. */
  242. public function get_entity_type() {
  243. $base_table = $this->view->base_table;
  244. // If the current field is under a relationship you can't be sure that the
  245. // base table of the view is the base table of the current field.
  246. // For example a field from a node author on a node view does have users as base table.
  247. if (!empty($this->options['relationship']) && $this->options['relationship'] != 'none') {
  248. $relationships = $this->view->display_handler->get_option('relationships');
  249. $options = $relationships[$this->options['relationship']];
  250. $data = views_fetch_data($options['table']);
  251. $base_table = $data[$options['field']]['relationship']['base'];
  252. }
  253. // The base table is now known, use it to determine the entity type.
  254. foreach (entity_get_info() as $entity_type => $info) {
  255. if (isset($info['base table']) && $info['base table'] == $base_table) {
  256. return $entity_type;
  257. }
  258. elseif (isset($info['revision table']) && $info['revision table'] == $base_table) {
  259. $this->revision = TRUE;
  260. return $entity_type;
  261. }
  262. }
  263. // This should never happen.
  264. _views_bulk_operations_report_error("Could not determine the entity type for VBO field on views base table %table", array('%table' => $base_table));
  265. return FALSE;
  266. }
  267. }