diff --git a/queue_example/lib/Drupal/queue_example/Forms/QueueExampleForm.php b/queue_example/lib/Drupal/queue_example/Forms/QueueExampleForm.php
new file mode 100644
index 0000000..114f2dd
--- /dev/null
+++ b/queue_example/lib/Drupal/queue_example/Forms/QueueExampleForm.php
@@ -0,0 +1,270 @@
+retrieveQueue($queue_name);
+
+ // Add CSS to make the form a bit denser.
+ // $form['#attached']['css'] = array(drupal_get_path('module', 'queue_example') . '/queue_example.css');
+
+ $form['help'] = array(
+ '#type' => 'markup',
+ '#markup' => '
' . 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.') . '
',
+ );
+
+ $form['queue_name'] = array(
+ '#type' => 'select',
+ '#title' => t('Choose queue to examine'),
+ '#options' => MapArray::copyValuesToKeys(array('queue_example_first_queue', 'queue_example_second_queue')),
+ '#default_value' => $queue_name,
+ );
+ $form['queue_show'] = array(
+ '#type' => 'submit',
+ '#value' => t('Show queue'),
+ '#submit' => array(array($this, 'submitShowQueue')),
+ );
+ $form['status_fieldset'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Queue status for @name', array('@name' => $queue_name)),
+ '#collapsible' => TRUE,
+ );
+ $form['status_fieldset']['status'] = array(
+ '#type' => 'markup',
+ '#markup' => theme('queue_items', array('items' => $items)),
+ );
+ $form['insert_fieldset'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Insert into @name', array('@name' => $queue_name)),
+ );
+ $form['insert_fieldset']['string_to_add'] = array(
+ '#type' => 'textfield',
+ '#size' => 10,
+ '#default_value' => t('item @counter', array('@counter' => $form_state['storage']['insert_counter'])),
+ );
+ $form['insert_fieldset']['add_item'] = array(
+ '#type' => 'submit',
+ '#value' => t('Insert into queue'),
+ '#submit' => array(array($this, 'submitAddQueueItem')),
+ );
+ $form['claim_fieldset'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Claim from queue'),
+ '#collapsible' => TRUE,
+ );
+
+ $form['claim_fieldset']['claim_time'] = array(
+ '#type' => 'radios',
+ '#title' => t('Claim time, in seconds'),
+ '#options' => array(0 => t('none'), 5 => t('5 seconds'), 60 => t('60 seconds')),
+ '#description' => t('This time is only valid if cron runs during this time period. You can run cron manually below.'),
+ '#default_value' => !empty($form_state['values']['claim_time']) ? $form_state['values']['claim_time'] : 5,
+ );
+ $form['claim_fieldset']['claim_item'] = array(
+ '#type' => 'submit',
+ '#value' => t('Claim the next item from the queue'),
+ '#submit' => array(array($this, 'submitClaimItem')),
+ );
+ $form['claim_fieldset']['claim_and_delete_item'] = array(
+ '#type' => 'submit',
+ '#value' => t('Claim the next item and delete it'),
+ '#submit' => array(array($this, 'submitClaimDeleteItem')),
+ );
+ $form['claim_fieldset']['run_cron'] = array(
+ '#type' => 'submit',
+ '#value' => t('Run cron manually to expire claims'),
+ '#submit' => array(array($this, 'submitRunCron')),
+ );
+ $form['delete_queue'] = array(
+ '#type' => 'submit',
+ '#value' => t('Delete the queue and items in it'),
+ '#submit' => array(array($this, 'submitDeleteQueue')),
+ );
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateForm(array &$form, array &$form_state) {
+
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, array &$form_state) {
+
+ }
+
+ /**
+ * Retrieves the queue from the database for display purposes only.
+ *
+ * It is not recommended to access the database directly, and this is only here
+ * so that the user interface can give a good idea of what's going on in the
+ * queue.
+ *
+ * @param $queue_name
+ * The name of the queue from which to fetch items.
+ *
+ * @return array
+ */
+ public function retrieveQueue($queue_name) {
+ $items = array();
+ $result = db_query("SELECT item_id, data, expire, created FROM {queue} WHERE name = :name ORDER BY item_id",
+ array(':name' => $queue_name),
+ array('fetch' => \PDO::FETCH_ASSOC));
+ foreach ($result as $item) {
+ $items[] = $item;
+ }
+ return $items;
+ }
+
+ /**
+ * Submit function for the show-queue button.
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+ public function submitShowQueue(array &$form, array &$form_state) {
+ $queue = \Drupal::queue($form_state['values']['queue_name']);
+ $queue->createQueue(); // There is no harm in trying to recreate existing.
+
+ // Get the number of items.
+ $count = $queue->numberOfItems();
+
+ // Update the form item counter.
+ $form_state['storage']['insert_counter'] = $count +1;
+
+ // Unset the string_to_add textbox.
+ unset($form_state['input']['string_to_add']);
+
+ $form_state['rebuild'] = TRUE;
+ }
+
+ /**
+ * Submit function for the insert-into-queue button.
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+ public function submitAddQueueItem(array &$form, array &$form_state) {
+ // Get a queue (of the default type) called 'queue_example_queue'.
+ // If the default queue class is SystemQueue this creates a queue that stores
+ // its items in the database.
+ $queue = \Drupal::queue($form_state['values']['queue_name']);
+ $queue->createQueue(); // There is no harm in trying to recreate existing.
+
+ // Queue the string.
+ $queue->createItem($form_state['values']['string_to_add']);
+ $count = $queue->numberOfItems();
+ 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'])));
+ $form_state['rebuild'] = TRUE; // Allows us to keep information in $form_state.
+
+ // Unsetting the string_to_add allows us to set the incremented default value
+ // for the user so they don't have to type anything.
+ unset($form_state['input']['string_to_add']);
+ $form_state['storage']['insert_counter']++;
+ }
+
+ /**
+ * Submit function for the "claim" button. Claims (retrieves) an item from
+ * the queue and reports the results.
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+ public function submitClaimItem(array &$form, array &$form_state) {
+ $queue = \Drupal::queue($form_state['values']['queue_name']);
+ $queue->createQueue(); // There is no harm in trying to recreate existing.
+ $item = $queue->claimItem($form_state['values']['claim_time']);
+ $count = $queue->numberOfItems();
+ if (!empty($item)) {
+ drupal_set_message(t('Claimed item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.', array('@count' => $count, '@item_id' => $item->item_id, '@string' => $item->data, '@seconds' => $form_state['values']['claim_time'])));
+ }
+ else {
+ drupal_set_message(t('There were no items in the queue available to claim. There are @count items in the queue.', array('@count' => $count)));
+ }
+ $form_state['rebuild'] = TRUE;
+ }
+
+ /**
+ * Submit function for "Claim and delete" button.
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+ public function submitClaimDeleteItem(array &$form, array &$form_state) {
+ $queue = \Drupal::queue($form_state['values']['queue_name']);
+ $queue->createQueue(); // There is no harm in trying to recreate existing.
+ $count = $queue->numberOfItems();
+ $item = $queue->claimItem(60);
+ if (!empty($item)) {
+ drupal_set_message(t('Claimed and deleted item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.', array('@count' => $count, '@item_id' => $item->item_id, '@string' => $item->data, '@seconds' => $form_state['values']['claim_time'])));
+ $queue->deleteItem($item);
+ $count = $queue->numberOfItems();
+ drupal_set_message(t('There are now @count items in the queue.', array('@count' => $count)));
+ }
+ else {
+ $count = $queue->numberOfItems();
+ 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)));
+ }
+ $form_state['rebuild'] = TRUE;
+ }
+
+ /**
+ * Submit function for "run cron" button.
+ *
+ * Runs cron (to release expired claims) and reports the results.
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+ public function submitRunCron(array &$form, array &$form_state) {
+ drupal_cron_run();
+ $queue = \Drupal::queue($form_state['values']['queue_name']);
+ $queue->createQueue(); // There is no harm in trying to recreate existing.
+ $count = $queue->numberOfItems();
+ 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)));
+ $form_state['rebuild'] = TRUE;
+ }
+
+ /**
+ * Submit handler for clearing/deleting the queue.
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+ public function submitDeleteQueue(array &$form, array &$form_state) {
+ $queue = \Drupal::queue($form_state['values']['queue_name']);
+ $queue->deleteQueue();
+ drupal_set_message(t('Deleted the @queue_name queue and all items in it', array('@queue_name' => $form_state['values']['queue_name'])));
+ }
+
+}
diff --git a/queue_example/lib/Drupal/queue_example/Tests/QueueExampleTestCase.php b/queue_example/lib/Drupal/queue_example/Tests/QueueExampleTestCase.php
new file mode 100644
index 0000000..801b12c
--- /dev/null
+++ b/queue_example/lib/Drupal/queue_example/Tests/QueueExampleTestCase.php
@@ -0,0 +1,82 @@
+ 'Queue Example functionality',
+ 'description' => 'Test Queue Example functionality',
+ 'group' => 'Examples',
+ );
+ }
+
+ /**
+ * Enable modules and create user with specific permissions.
+ */
+ function setUp() {
+ parent::setUp();
+ }
+
+ /**
+ * Login user, create an example node, and test blog functionality through the admin and user interfaces.
+ */
+ function testQueueExampleBasic() {
+
+ // Load the queue with 5 items.
+ for ($i = 1; $i <= 5; $i++) {
+ $edit = array('queue_name' => 'queue_example_first_queue', 'string_to_add' => "boogie$i");
+ $this->drupalPostForm('queue_example/insert_remove', $edit, t('Insert into queue'));
+ $this->assertText(t('There are now @number items in the queue', array('@number' => $i)));
+ }
+ // Claim each of the 5 items with a claim time of 0 seconds.
+ for ($i = 1; $i <= 5; $i++) {
+ $edit = array('queue_name' => 'queue_example_first_queue', 'claim_time' => 0);
+ $this->drupalPostForm(NULL, $edit, t('Claim the next item from the queue'));
+ $this->assertPattern(t('%Claimed item id=.*string=@string for 0 seconds.%', array('@string' => "boogie$i")));
+ }
+ $edit = array('queue_name' => 'queue_example_first_queue', 'claim_time' => 0);
+ $this->drupalPostForm(NULL, $edit, t('Claim the next item from the queue'));
+ $this->assertText(t('There were no items in the queue available to claim'));
+
+ // Sleep a second so we can make sure that the timeouts actually time out.
+ // Local systems work fine with this but apparently the PIFR server is so
+ /// fast that it needs a sleep before the cron run.
+ sleep(1);
+
+ // Run cron to release expired items.
+ $this->drupalPostForm(NULL, array(), t('Run cron manually to expire claims'));
+
+ // Claim and delete each of the 5 items which should now be available.
+ for ($i = 1; $i <= 5; $i++) {
+ $edit = array('queue_name' => 'queue_example_first_queue', 'claim_time' => 0);
+ $this->drupalPostForm(NULL, $edit, t('Claim the next item and delete it'));
+ $this->assertPattern(t('%Claimed and deleted item id=.*string=@string for 0 seconds.%', array('@string' => "boogie$i")));
+ }
+ // Verify that nothing is left to claim.
+ $edit = array('queue_name' => 'queue_example_first_queue', 'claim_time' => 0);
+ $this->drupalPostForm(NULL, $edit, t('Claim the next item from the queue'));
+ $this->assertText(t('There were no items in the queue available to claim'));
+ }
+
+}
+
+/**
+ * @} End of "addtogroup queue_example".
+ */
diff --git a/queue_example/queue_example.info.yml b/queue_example/queue_example.info.yml
new file mode 100644
index 0000000..e7d94ff
--- /dev/null
+++ b/queue_example/queue_example.info.yml
@@ -0,0 +1,5 @@
+name: Queue example
+type: module
+description: Examples of using the Drupal Queue API.
+package: Example modules
+core: 8.x
diff --git a/queue_example/queue_example.module b/queue_example/queue_example.module
new file mode 100644
index 0000000..7ba0ab4
--- /dev/null
+++ b/queue_example/queue_example.module
@@ -0,0 +1,68 @@
+ array(
+ 'variables' => array('items' => NULL),
+ ),
+ );
+}
+
+/**
+ * Themes the queue display.
+ *
+ * Again, this is not part of the demonstration of the queue API, but is here
+ * just to make the user interface more understandable.
+ *
+ * @param $variables
+ *
+ * @return string
+ */
+function theme_queue_items($variables) {
+ $items = $variables['items'];
+ $rows = array();
+ foreach ($items as &$item) {
+ if ($item['expire'] > 0) {
+ $item['expire'] = t("Claimed: expires %expire", array('%expire' => date('r', $item['expire'])));
+ }
+ else {
+ $item['expire'] = t('Unclaimed');
+ }
+ $item['created'] = date('r', $item['created']);
+ $item['content'] = check_plain(unserialize($item['data']));
+ unset($item['data']);
+ $rows[] = $item;
+ }
+ if (!empty($rows)) {
+ $header = array(t('Item ID'), t('Claimed/Expiration'), t('Created'), t('Content/Data'));
+ $output = theme('table', array('header' => $header, 'rows' => $rows));
+ return $output;
+ }
+ else {
+ return t('There are no items in the queue.');
+ }
+}
+
+
+/**
+ * @} End of "defgroup queue_example".
+ */
diff --git a/queue_example/queue_example.routing.yml b/queue_example/queue_example.routing.yml
new file mode 100644
index 0000000..a07bacb
--- /dev/null
+++ b/queue_example/queue_example.routing.yml
@@ -0,0 +1,6 @@
+queue_example:
+ path: 'queue_example/insert_remove'
+ defaults:
+ _form: '\Drupal\queue_example\Forms\QueueExampleForm'
+ requirements:
+ _access: 'TRUE'