views_bulk_operations.rules.inc 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. <?php
  2. /**
  3. * @file
  4. * Views Bulk Operations conditions and actions for Rules.
  5. */
  6. /**
  7. * Implements hook_rules_condition_info().
  8. */
  9. function views_bulk_operations_rules_condition_info() {
  10. $conditions = array();
  11. $conditions['views_bulk_operations_condition_result_count'] = array(
  12. 'label' => t('Check number of results returned by a VBO View'),
  13. 'parameter' => array(
  14. 'view' => array(
  15. 'type' => 'text',
  16. 'label' => t('View and display'),
  17. 'options list' => 'views_bulk_operations_views_list',
  18. 'description' => t('Select the VBO view and display you want to check'),
  19. 'restriction' => 'input',
  20. ),
  21. 'args' => array(
  22. 'type' => 'text',
  23. 'label' => t('Arguments'),
  24. 'description' => t('Any arguments to pass to the view, one per line.
  25. You may use token replacement patterns.'),
  26. 'optional' => TRUE,
  27. ),
  28. 'minimum' => array(
  29. 'type' => 'integer',
  30. 'label' => t('Minimum number of results'),
  31. 'description' => t('This condition returns TRUE if the view has at
  32. least the given number of results.'),
  33. ),
  34. ),
  35. 'group' => t('Views Bulk Operations'),
  36. );
  37. return $conditions;
  38. }
  39. /**
  40. * Implements hook_rules_action_info().
  41. */
  42. function views_bulk_operations_rules_action_info() {
  43. $actions = array();
  44. $actions['views_bulk_operations_action_load_list'] = array(
  45. 'label' => t('Load a list of entity objects from a VBO View.'),
  46. 'parameter' => array(
  47. 'view' => array(
  48. 'type' => 'text',
  49. 'label' => t('View and display'),
  50. 'options list' => 'views_bulk_operations_views_list',
  51. 'description' => t('Select the view and display you want to use to
  52. create a list.'),
  53. 'restriction' => 'input',
  54. ),
  55. 'args' => array(
  56. 'type' => 'text',
  57. 'label' => t('Arguments'),
  58. 'description' => t('Any arguments to pass to the view, one per line.
  59. You may use token replacement patterns.'),
  60. 'optional' => TRUE,
  61. ),
  62. ),
  63. 'provides' => array(
  64. 'entity_list' => array(
  65. 'type' => 'list<entity>',
  66. 'label' => t('A list of entities'),
  67. ),
  68. ),
  69. 'group' => t('Views Bulk Operations'),
  70. );
  71. $actions['views_bulk_operations_action_load_id_list'] = array(
  72. 'label' => t('Load a list of entity ids from a VBO View.'),
  73. 'parameter' => array(
  74. 'view' => array(
  75. 'type' => 'text',
  76. 'label' => t('View and display'),
  77. 'options list' => 'views_bulk_operations_views_list',
  78. 'description' => t('Select the view and display you want to use to
  79. create a list.'),
  80. 'restriction' => 'input',
  81. ),
  82. 'args' => array(
  83. 'type' => 'text',
  84. 'label' => t('Arguments'),
  85. 'description' => t('Any arguments to pass to the view, one per line.
  86. You may use token replacement patterns.'),
  87. 'optional' => TRUE,
  88. ),
  89. ),
  90. 'provides' => array(
  91. 'entity_id_list' => array(
  92. 'type' => 'list<integer>',
  93. 'label' => t('A list of entity ids'),
  94. ),
  95. ),
  96. 'group' => t('Views Bulk Operations'),
  97. );
  98. return $actions;
  99. }
  100. /**
  101. * Lists all available VBO Views and their displays.
  102. * Naturally, only the displays that contain a VBO field are listed.
  103. *
  104. * @return array
  105. * An array of all views and their displays on the form 'view|display',
  106. * formatted to be used as an select list.
  107. */
  108. function views_bulk_operations_views_list() {
  109. $selectable_displays = array();
  110. foreach (views_get_enabled_views() as $name => $base_view) {
  111. $view = $base_view->clone_view();
  112. foreach ($base_view->display as $display_name => $display) {
  113. if (!$view->set_display($display_name)) {
  114. continue;
  115. }
  116. // Initialize the style plugin and only continue to initialize handlers
  117. // if the style uses fields.
  118. if (!$view->init_style() || !$view->style_plugin->uses_fields()) {
  119. continue;
  120. }
  121. $view->init_handlers($display_name);
  122. if (_views_bulk_operations_get_field($view)) {
  123. $selectable_displays[$view->name . '|' . $display_name] = check_plain($view->human_name . ' | ' . $display->display_title);
  124. }
  125. }
  126. }
  127. return $selectable_displays;
  128. }
  129. /**
  130. * The 'views_bulk_operations_condition_result_count' condition.
  131. *
  132. * @param $view
  133. * A string in the format "$view_name|$display_name".
  134. * @param $args
  135. * Arguments that should be passed to the View.
  136. * @param $minimum
  137. * An integer representing the minimum number of results that satisfies the
  138. * condition.
  139. *
  140. * @return
  141. * TRUE if the view has more than $minimum results, FALSE otherwise.
  142. */
  143. function views_bulk_operations_condition_result_count($view, $args, $minimum) {
  144. $vbo = _views_bulk_operations_rules_get_field($view, $args);
  145. return (count($vbo->view->result) >= $minimum);
  146. }
  147. /**
  148. * The 'views_bulk_operations_action_views_load_list' action.
  149. *
  150. * @param $view
  151. * A string in the format "$view_name|$display_name".
  152. * @param $args
  153. * Arguments that should be passed to the View.
  154. * @return array
  155. * Array containing the entity_list, an array of entity objects.
  156. * - array('entity_list' => array(...))
  157. */
  158. function views_bulk_operations_action_load_list($view, $args) {
  159. $vbo = _views_bulk_operations_rules_get_field($view, $args);
  160. // Get all entities, pass ids to the wrapper for lazy loading.
  161. $entity_type = $vbo->get_entity_type();
  162. $entities = entity_metadata_wrapper("list<$entity_type>", array());
  163. foreach ($vbo->view->result as $row_index => $result) {
  164. // Grab the entire entity if it's already loaded or fall back to the
  165. // entity identifier.
  166. $entity = $vbo->get_value($result);
  167. $data = $entity ? $entity : $result->{$vbo->real_field};
  168. $entities[] = entity_metadata_wrapper($entity_type, $data);
  169. }
  170. return array('entity_list' => $entities);
  171. }
  172. /**
  173. * The 'views_bulk_operations_action_views_load_id_list' action.
  174. *
  175. * @param $view
  176. * A string in the format "$view_name|$display_name".
  177. * @param $args
  178. * Arguments that should be passed to the View.
  179. * @return array
  180. * Array containing the entity_id_list, an Array of entity ids as integer
  181. * values.
  182. * - array('entity_list' => array(...))
  183. */
  184. function views_bulk_operations_action_load_id_list($view, $args) {
  185. $vbo = _views_bulk_operations_rules_get_field($view, $args);
  186. // Get all entity ids.
  187. $ids = array();
  188. foreach ($vbo->view->result as $row_index => $result) {
  189. $ids[] = $vbo->get_value($result);
  190. }
  191. return array('entity_id_list' => $ids);
  192. }
  193. /**
  194. * Info alteration callback for the 'views_bulk_operations_action_views_load_list' action.
  195. *
  196. * The info hook specifies that the action returns a generic list of entities
  197. * (list<entity>). All actions that require entities of specific type can't
  198. * use such entities, so this alter hook specifies the exact entity type
  199. * after the action has been configured, allowing the view to be loaded
  200. * and its entity type extracted.
  201. */
  202. function views_bulk_operations_action_load_list_info_alter(&$element_info, RulesAbstractPlugin $element) {
  203. // The action hasn't been configured yet, hence no view. Abort.
  204. if (empty($element->settings['view'])) {
  205. return;
  206. }
  207. $entity_type = _views_bulk_operations_rules_get_entity_type($element->settings['view']);
  208. if ($entity_type) {
  209. $element_info['provides']['entity_list']['type'] = "list<$entity_type>";
  210. }
  211. }
  212. /**
  213. * Helper function that loads and builds (but doesn't execute) the specified view,
  214. * then determines the entity type on which the VBO field operates.
  215. *
  216. * @param $view_target
  217. * A string in the format "$view_name|$display_name".
  218. *
  219. * @return
  220. * The entity type on which the VBO field operates.
  221. */
  222. function _views_bulk_operations_rules_get_entity_type($view_target) {
  223. $entity_types = &drupal_static(__FUNCTION__);
  224. if (!isset($entity_types[$view_target])) {
  225. $views_settings = explode('|', $view_target);
  226. if ($view = views_get_view($views_settings[0])) {
  227. $view->set_display($views_settings[1]);
  228. $view->build();
  229. $vbo = _views_bulk_operations_get_field($view);
  230. }
  231. $entity_type = !empty($vbo) ? $vbo->get_entity_type() : '';
  232. $entity_types[$view_target] = $entity_type;
  233. }
  234. return $entity_types[$view_target];
  235. }
  236. /**
  237. * Helper function that loads, builds and executes the specified view,
  238. * then returns its VBO field.
  239. *
  240. * @param $view_target
  241. * A string in the format "$view_name|$display_name".
  242. * @param $args
  243. * Arguments that should be passed to the View.
  244. *
  245. * @return
  246. * The VBO field. Contains a reference to the View.
  247. */
  248. function _views_bulk_operations_rules_get_field($view_target, $args) {
  249. $views = &drupal_static(__FUNCTION__);
  250. $views_settings = explode('|', $view_target);
  251. $view_name = $views_settings[0];
  252. $display_name = $views_settings[1];
  253. // Create an array of arguments.
  254. $view_arguments = explode("\n", $args);
  255. $view_arguments = array_map('trim', $view_arguments);
  256. $view_arguments = array_filter($view_arguments, 'strlen');
  257. // Append the filtered list of arguments to $views_target, so that the correct
  258. // View is fetched from cache.
  259. if (!empty($view_arguments)) {
  260. $view_target .= '|' . implode('&', $view_arguments);
  261. }
  262. // Don't execute the requested View more than once in a single page request.
  263. if (isset($views[$view_target])) {
  264. $vbo = _views_bulk_operations_get_field($views[$view_target]);
  265. return $vbo;
  266. }
  267. // Load the view and set the properties.
  268. $view = views_get_view($view_name);
  269. $view->set_display($display_name);
  270. $view->set_arguments($view_arguments);
  271. $view->build();
  272. $vbo = _views_bulk_operations_get_field($view);
  273. // Unset every field except the VBO one (which holds the entity id).
  274. // That way the performance hit becomes much smaller, because there is no
  275. // chance of views_handler_field_field::post_execute() firing entity_load().
  276. foreach ($view->field as $field_name => $field) {
  277. if ($field_name != $vbo->options['id']) {
  278. unset($view->field[$field_name]);
  279. }
  280. }
  281. $view->execute($view->current_display);
  282. // Save the view in the static cache.
  283. $views[$view_target] = $view;
  284. return $vbo;
  285. }