queue_example.module 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. /**
  3. * @file
  4. * Examples demonstrating the Drupal Queue API.
  5. */
  6. /**
  7. * @defgroup queue_example Example: Queue
  8. * @ingroup examples
  9. * @{
  10. * Demonstrating the Queue API
  11. *
  12. * The Queue API provides a traditional FIFO (first-in-first-out) queue,
  13. * but also provides the concepts of:
  14. * - "Creating" a queued item, which means inserting it into a queue.
  15. * - "Claiming" a queued item, which essentially means requesting the next item
  16. * from the queue and holding a lock on that item for a specified period of
  17. * time.
  18. * - "Releasing" an item, which means giving up a claim but leaving the item in
  19. * the queue.
  20. * - "Deleting" an item, which means finally removing it from the queue.
  21. *
  22. * This example demonstrates only basic queue functionality, and will use the
  23. * default queue implementation, which is SystemQueue, managed using
  24. * persistent database storage.
  25. *
  26. * Further resources include the limited @link queue @endlink documentation.
  27. * More:
  28. *
  29. * @link http://www.ent.iastate.edu/it/Batch_and_Queue.pdf Batch vs Queue Presentation slides by John VanDyk @endlink
  30. * @link http://sf2010.drupal.org/conference/sessions/batch-vs-queue-api-smackdown session video. @endlink
  31. *
  32. * @see system.queue.inc
  33. */
  34. /**
  35. * Implements hook_menu().
  36. */
  37. function queue_example_menu() {
  38. $items = array();
  39. $items['queue_example/insert_remove'] = array(
  40. 'title' => 'Queue Example: Insert and remove',
  41. 'page callback' => 'drupal_get_form',
  42. 'page arguments' => array('queue_example_add_remove_form'),
  43. 'access callback' => TRUE,
  44. );
  45. return $items;
  46. }
  47. /**
  48. * Form generator for managing the queue.
  49. *
  50. * Provides an interface to add items to the queue, to retrieve (claim)
  51. * an item from the head of the queue, and to claim and delete. Also
  52. * allows the user to run cron manually, so that claimed items can be
  53. * released.
  54. */
  55. function queue_example_add_remove_form($form, &$form_state) {
  56. // Simple counter that makes it possible to put auto-incrementing default
  57. // string into the string to insert.
  58. if (empty($form_state['storage']['insert_counter'])) {
  59. $form_state['storage']['insert_counter'] = 1;
  60. }
  61. $queue_name = !empty($form_state['values']['queue_name']) ? $form_state['values']['queue_name'] : 'queue_example_first_queue';
  62. $items = queue_example_retrieve_queue($queue_name);
  63. // Add CSS to make the form a bit denser.
  64. $form['#attached']['css'] = array(drupal_get_path('module', 'queue_example') . '/queue_example.css');
  65. $form['help'] = array(
  66. '#type' => 'markup',
  67. '#markup' => '<div>' . t('This page is an interface on the Drupal queue API. You can add new items to the queue, "claim" one (retrieve the next item and keep a lock on it), and delete one (remove it from the queue). Note that claims are not expired until cron runs, so there is a special button to run cron to perform any necessary expirations.') . '</div>',
  68. );
  69. $form['queue_name'] = array(
  70. '#type' => 'select',
  71. '#title' => t('Choose queue to examine'),
  72. '#options' => drupal_map_assoc(array('queue_example_first_queue', 'queue_example_second_queue')),
  73. '#default_value' => $queue_name,
  74. );
  75. $form['queue_show'] = array(
  76. '#type' => 'submit',
  77. '#value' => t('Show queue'),
  78. '#submit' => array('queue_example_show_queue'),
  79. );
  80. $form['status_fieldset'] = array(
  81. '#type' => 'fieldset',
  82. '#title' => t('Queue status for @name', array('@name' => $queue_name)),
  83. '#collapsible' => TRUE,
  84. );
  85. $form['status_fieldset']['status'] = array(
  86. '#type' => 'markup',
  87. '#markup' => theme('queue_items', array('items' => $items)),
  88. );
  89. $form['insert_fieldset'] = array(
  90. '#type' => 'fieldset',
  91. '#title' => t('Insert into @name', array('@name' => $queue_name)),
  92. );
  93. $form['insert_fieldset']['string_to_add'] = array(
  94. '#type' => 'textfield',
  95. '#size' => 10,
  96. '#default_value' => t('item @counter', array('@counter' => $form_state['storage']['insert_counter'])),
  97. );
  98. $form['insert_fieldset']['add_item'] = array(
  99. '#type' => 'submit',
  100. '#value' => t('Insert into queue'),
  101. '#submit' => array('queue_example_add_remove_form_insert'),
  102. );
  103. $form['claim_fieldset'] = array(
  104. '#type' => 'fieldset',
  105. '#title' => t('Claim from queue'),
  106. '#collapsible' => TRUE,
  107. );
  108. $form['claim_fieldset']['claim_time'] = array(
  109. '#type' => 'radios',
  110. '#title' => t('Claim time, in seconds'),
  111. '#options' => array(
  112. 0 => t('none'),
  113. 5 => t('5 seconds'),
  114. 60 => t('60 seconds'),
  115. ),
  116. '#description' => t('This time is only valid if cron runs during this time period. You can run cron manually below.'),
  117. '#default_value' => !empty($form_state['values']['claim_time']) ? $form_state['values']['claim_time'] : 5,
  118. );
  119. $form['claim_fieldset']['claim_item'] = array(
  120. '#type' => 'submit',
  121. '#value' => t('Claim the next item from the queue'),
  122. '#submit' => array('queue_example_add_remove_form_claim'),
  123. );
  124. $form['claim_fieldset']['claim_and_delete_item'] = array(
  125. '#type' => 'submit',
  126. '#value' => t('Claim the next item and delete it'),
  127. '#submit' => array('queue_example_add_remove_form_delete'),
  128. );
  129. $form['claim_fieldset']['run_cron'] = array(
  130. '#type' => 'submit',
  131. '#value' => t('Run cron manually to expire claims'),
  132. '#submit' => array('queue_example_add_remove_form_run_cron'),
  133. );
  134. $form['delete_queue'] = array(
  135. '#type' => 'submit',
  136. '#value' => t('Delete the queue and items in it'),
  137. '#submit' => array('queue_example_add_remove_form_clear_queue'),
  138. );
  139. return $form;
  140. }
  141. /**
  142. * Submit function for the insert-into-queue button.
  143. */
  144. function queue_example_add_remove_form_insert($form, &$form_state) {
  145. // Get a queue (of the default type) called 'queue_example_queue'.
  146. // If the default queue class is SystemQueue this creates a queue that stores
  147. // its items in the database.
  148. $queue = DrupalQueue::get($form_state['values']['queue_name']);
  149. // There is no harm in trying to recreate existing.
  150. $queue->createQueue();
  151. // Queue the string.
  152. $queue->createItem($form_state['values']['string_to_add']);
  153. $count = $queue->numberOfItems();
  154. drupal_set_message(t('Queued your string (@string_to_add). There are now @count items in the queue.', array('@count' => $count, '@string_to_add' => $form_state['values']['string_to_add'])));
  155. // Setting 'rebuild' to TRUE allows us to keep information in $form_state.
  156. $form_state['rebuild'] = TRUE;
  157. // Unsetting the string_to_add allows us to set the incremented default value
  158. // for the user so they don't have to type anything.
  159. unset($form_state['input']['string_to_add']);
  160. $form_state['storage']['insert_counter']++;
  161. }
  162. /**
  163. * Submit function for the show-queue button.
  164. */
  165. function queue_example_show_queue($form, &$form_state) {
  166. $queue = DrupalQueue::get($form_state['values']['queue_name']);
  167. // There is no harm in trying to recreate existing.
  168. $queue->createQueue();
  169. // Get the number of items.
  170. $count = $queue->numberOfItems();
  171. // Update the form item counter.
  172. $form_state['storage']['insert_counter'] = $count + 1;
  173. // Unset the string_to_add textbox.
  174. unset($form_state['input']['string_to_add']);
  175. $form_state['rebuild'] = TRUE;
  176. }
  177. /**
  178. * Submit function for the "claim" button.
  179. *
  180. * Claims (retrieves) an item from the queue and reports the results.
  181. */
  182. function queue_example_add_remove_form_claim($form, &$form_state) {
  183. $queue = DrupalQueue::get($form_state['values']['queue_name']);
  184. // There is no harm in trying to recreate existing.
  185. $queue->createQueue();
  186. $item = $queue->claimItem($form_state['values']['claim_time']);
  187. $count = $queue->numberOfItems();
  188. if (!empty($item)) {
  189. drupal_set_message(
  190. t('Claimed item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.',
  191. array(
  192. '@count' => $count,
  193. '@item_id' => $item->item_id,
  194. '@string' => $item->data,
  195. '@seconds' => $form_state['values']['claim_time'],
  196. )
  197. )
  198. );
  199. }
  200. else {
  201. drupal_set_message(t('There were no items in the queue available to claim. There are @count items in the queue.', array('@count' => $count)));
  202. }
  203. $form_state['rebuild'] = TRUE;
  204. }
  205. /**
  206. * Submit function for "Claim and delete" button.
  207. */
  208. function queue_example_add_remove_form_delete($form, &$form_state) {
  209. $queue = DrupalQueue::get($form_state['values']['queue_name']);
  210. // There is no harm in trying to recreate existing.
  211. $queue->createQueue();
  212. $count = $queue->numberOfItems();
  213. $item = $queue->claimItem(60);
  214. if (!empty($item)) {
  215. drupal_set_message(
  216. t('Claimed and deleted item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.',
  217. array(
  218. '@count' => $count,
  219. '@item_id' => $item->item_id,
  220. '@string' => $item->data,
  221. '@seconds' => $form_state['values']['claim_time'],
  222. )
  223. )
  224. );
  225. $queue->deleteItem($item);
  226. $count = $queue->numberOfItems();
  227. drupal_set_message(t('There are now @count items in the queue.', array('@count' => $count)));
  228. }
  229. else {
  230. $count = $queue->numberOfItems();
  231. drupal_set_message(t('There were no items in the queue available to claim/delete. There are currently @count items in the queue.', array('@count' => $count)));
  232. }
  233. $form_state['rebuild'] = TRUE;
  234. }
  235. /**
  236. * Submit function for "run cron" button.
  237. *
  238. * Runs cron (to release expired claims) and reports the results.
  239. */
  240. function queue_example_add_remove_form_run_cron($form, &$form_state) {
  241. drupal_cron_run();
  242. $queue = DrupalQueue::get($form_state['values']['queue_name']);
  243. // There is no harm in trying to recreate existing.
  244. $queue->createQueue();
  245. $count = $queue->numberOfItems();
  246. drupal_set_message(t('Ran cron. If claimed items expired, they should be expired now. There are now @count items in the queue', array('@count' => $count)));
  247. $form_state['rebuild'] = TRUE;
  248. }
  249. /**
  250. * Submit handler for clearing/deleting the queue.
  251. */
  252. function queue_example_add_remove_form_clear_queue($form, &$form_state) {
  253. $queue = DrupalQueue::get($form_state['values']['queue_name']);
  254. $queue->deleteQueue();
  255. drupal_set_message(t('Deleted the @queue_name queue and all items in it', array('@queue_name' => $form_state['values']['queue_name'])));
  256. }
  257. /**
  258. * Retrieves the queue from the database for display purposes only.
  259. *
  260. * It is not recommended to access the database directly, and this is only here
  261. * so that the user interface can give a good idea of what's going on in the
  262. * queue.
  263. *
  264. * @param array $queue_name
  265. * The name of the queue from which to fetch items.
  266. */
  267. function queue_example_retrieve_queue($queue_name) {
  268. $items = array();
  269. $result = db_query("SELECT item_id, data, expire, created FROM {queue} WHERE name = :name ORDER BY item_id",
  270. array(':name' => $queue_name),
  271. array('fetch' => PDO::FETCH_ASSOC));
  272. foreach ($result as $item) {
  273. $items[] = $item;
  274. }
  275. return $items;
  276. }
  277. /**
  278. * Themes the queue display.
  279. *
  280. * Again, this is not part of the demonstration of the queue API, but is here
  281. * just to make the user interface more understandable.
  282. *
  283. * @param array $variables
  284. * Our variables.
  285. */
  286. function theme_queue_items($variables) {
  287. $items = $variables['items'];
  288. $rows = array();
  289. foreach ($items as &$item) {
  290. if ($item['expire'] > 0) {
  291. $item['expire'] = t("Claimed: expires %expire", array('%expire' => date('r', $item['expire'])));
  292. }
  293. else {
  294. $item['expire'] = t('Unclaimed');
  295. }
  296. $item['created'] = date('r', $item['created']);
  297. $item['content'] = check_plain(unserialize($item['data']));
  298. unset($item['data']);
  299. $rows[] = $item;
  300. }
  301. if (!empty($rows)) {
  302. $header = array(
  303. t('Item ID'),
  304. t('Claimed/Expiration'),
  305. t('Created'),
  306. t('Content/Data'),
  307. );
  308. $output = theme('table', array('header' => $header, 'rows' => $rows));
  309. return $output;
  310. }
  311. else {
  312. return t('There are no items in the queue.');
  313. }
  314. }
  315. /**
  316. * Implements hook_theme().
  317. */
  318. function queue_example_theme() {
  319. return array(
  320. 'queue_items' => array(
  321. 'variables' => array('items' => NULL),
  322. ),
  323. );
  324. }
  325. /**
  326. * @} End of "defgroup queue_example".
  327. */