You are here

class QueueExampleForm in Examples for Developers 3.x

Form with examples on how to use queue.

Hierarchy

Expanded class hierarchy of QueueExampleForm

1 string reference to 'QueueExampleForm'
queue_example.routing.yml in modules/queue_example/queue_example.routing.yml
modules/queue_example/queue_example.routing.yml

File

modules/queue_example/src/Form/QueueExampleForm.php, line 19

Namespace

Drupal\queue_example\Form
View source
class QueueExampleForm extends FormBase {

  /**
   * The queue object.
   *
   * @var \Drupal\Core\Queue\QueueFactory
   */
  protected $queueFactory;

  /**
   * The database object.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $database;

  /**
   * The CronInterface object.
   *
   * @var \Drupal\Core\CronInterface
   */
  protected $cron;

  /**
   * What kind of queue backend are we using?
   *
   * @var string
   */
  protected $queueType;

  /**
   * Constructor.
   *
   * @param \Drupal\Core\Queue\QueueFactory $queue_factory
   *   Queue factory service to get new/existing queues for use.
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection to be used.
   * @param Drupal\Core\CronInterface $cron
   *   The cron service.
   * @param Drupal\Core\Site\Settings $settings
   *   The site settings.
   */
  public function __construct(QueueFactory $queue_factory, Connection $database, CronInterface $cron, Settings $settings) {
    $this->queueFactory = $queue_factory;
    $this->queueType = $settings
      ->get('queue_default', 'queue.database');
    $this->database = $database;
    $this->cron = $cron;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $form = new static($container
      ->get('queue'), $container
      ->get('database'), $container
      ->get('cron'), $container
      ->get('settings'));
    $form
      ->setMessenger($container
      ->get('messenger'));
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {

    // Return a string that is the unique ID of our form. Best practice here is
    // to namespace the form based on your module's name.
    return 'queue_example';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    // Simple counter that makes it possible to put auto-incrementing default
    // string into the string to insert.
    if (empty($form_state
      ->get('insert_counter'))) {
      $form_state
        ->set('insert_counter', 1);
    }
    $queue_name = $form_state
      ->getValue('queue_name') ?: 'queue_example_first_queue';
    $items = $this
      ->retrieveQueue($queue_name);
    $form['help'] = [
      '#type' => 'markup',
      '#markup' => '<div>' . $this
        ->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>',
    ];
    $form['wrong_queue_warning'] = [
      '#type' => 'markup',
      '#markup' => '<div>' . $this
        ->t('Note: the example works only with the default queue implementation, which is not currently configured!!') . '</div>',
      '#access' => !$this
        ->doesQueueUseDB(),
    ];
    $queue_names = [
      'queue_example_first_queue',
      'queue_example_second_queue',
    ];
    $form['queue_name'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Choose queue to examine'),
      '#options' => array_combine($queue_names, $queue_names),
      '#default_value' => $queue_name,
    ];
    $form['queue_show'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Show queue'),
      '#submit' => [
        '::submitShowQueue',
      ],
    ];
    $form['status_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Queue status for @name', [
        '@name' => $queue_name,
      ]),
      '#collapsible' => TRUE,
    ];
    if (count($items) > 0) {
      $form['status_fieldset']['status'] = [
        '#theme' => 'table',
        '#header' => [
          $this
            ->t('Item ID'),
          $this
            ->t('Claimed/Expiration'),
          $this
            ->t('Created'),
          $this
            ->t('Content/Data'),
        ],
        '#rows' => array_map([
          $this,
          'processQueueItemForTable',
        ], $items),
      ];
    }
    else {
      $form['status_fieldset']['status'] = [
        '#type' => 'markup',
        '#markup' => $this
          ->t('There are no items in the queue.'),
      ];
    }
    $form['insert_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Insert into @name', [
        '@name' => $queue_name,
      ]),
    ];
    $form['insert_fieldset']['string_to_add'] = [
      '#type' => 'textfield',
      '#size' => 10,
      '#default_value' => $this
        ->t('item @counter', [
        '@counter' => $form_state
          ->get('insert_counter'),
      ]),
    ];
    $form['insert_fieldset']['add_item'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Insert into queue'),
      '#submit' => [
        '::submitAddQueueItem',
      ],
    ];
    $form['claim_fieldset'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Claim from queue'),
      '#collapsible' => TRUE,
    ];
    $form['claim_fieldset']['claim_time'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('Claim time, in seconds'),
      '#options' => [
        0 => $this
          ->t('none'),
        5 => $this
          ->t('5 seconds'),
        60 => $this
          ->t('60 seconds'),
      ],
      '#description' => $this
        ->t('This time is only valid if cron runs during this time period. You can run cron manually below.'),
      '#default_value' => $form_state
        ->getValue('claim_time') ?: 5,
    ];
    $form['claim_fieldset']['claim_item'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Claim the next item from the queue'),
      '#submit' => [
        '::submitClaimItem',
      ],
    ];
    $form['claim_fieldset']['claim_and_delete_item'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Claim the next item and delete it'),
      '#submit' => [
        '::submitClaimDeleteItem',
      ],
    ];
    $form['claim_fieldset']['run_cron'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Run cron manually to expire claims'),
      '#submit' => [
        '::submitRunCron',
      ],
    ];
    $form['delete_queue'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Delete the queue and items in it'),
      '#submit' => [
        '::submitDeleteQueue',
      ],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $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 string $queue_name
   *   The name of the queue from which to fetch items.
   *
   * @return array
   *   An array of item arrays.
   */
  public function retrieveQueue($queue_name) {
    $items = [];

    // This example requires the default queue implementation to work,
    // so we bail if some other queue implementation has been installed.
    if (!$this
      ->doesQueueUseDb()) {
      return $items;
    }

    // Make sure there are queue items available. The queue will not create our
    // database table if there are no items.
    if ($this->queueFactory
      ->get($queue_name)
      ->numberOfItems() >= 1) {
      $result = $this->database
        ->query('SELECT item_id, data, expire, created FROM {' . DatabaseQueue::TABLE_NAME . '} WHERE name = :name ORDER BY item_id', [
        ':name' => $queue_name,
      ], [
        'fetch' => \PDO::FETCH_ASSOC,
      ]);
      foreach ($result as $item) {
        $items[] = $item;
      }
    }
    return $items;
  }

  /**
   * Check if we are using the default database queue.
   *
   * @return bool
   *   TRUE if we are using the default database queue implementation.
   */
  protected function doesQueueUseDb() {
    return $this->queueType == 'queue.database';
  }

  /**
   * Submit function for the show-queue button.
   *
   * @param array $form
   *   Form definition array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   */
  public function submitShowQueue(array &$form, FormStateInterface $form_state) {
    $queue = $this->queueFactory
      ->get($form_state
      ->getValue('queue_name'));

    // There is no harm in trying to recreate existing.
    $queue
      ->createQueue();

    // Get the number of items.
    $count = $queue
      ->numberOfItems();

    // Update the form item counter.
    $form_state
      ->set('insert_counter', $count + 1);

    // Unset the string_to_add textbox.
    $form_state
      ->unsetValue('string_to_add');
    $form_state
      ->setRebuild();
  }

  /**
   * Submit function for the insert-into-queue button.
   *
   * @param array $form
   *   Form definition array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   */
  public function submitAddQueueItem(array &$form, FormStateInterface $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 = $this->queueFactory
      ->get($form_state
      ->getValue('queue_name'));

    // There is no harm in trying to recreate existing.
    $queue
      ->createQueue();

    // Queue the string.
    $queue
      ->createItem($form_state
      ->getValue('string_to_add'));
    $count = $queue
      ->numberOfItems();
    $this
      ->messenger()
      ->addMessage($this
      ->t('Queued your string (@string_to_add). There are now @count items in the queue.', [
      '@count' => $count,
      '@string_to_add' => $form_state
        ->getValue('string_to_add'),
    ]));

    // Allows us to keep information in $form_state.
    $form_state
      ->setRebuild();

    // Unsetting the string_to_add allows us to set the incremented default
    // value for the user so they don't have to type anything.
    $form_state
      ->unsetValue('string_to_add');
    $form_state
      ->set('insert_counter', $count + 1);
  }

  /**
   * Submit function for the "claim" button.
   *
   * Claims (retrieves) an item from the queue and reports the results.
   *
   * @param array $form
   *   Form definition array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   */
  public function submitClaimItem(array &$form, FormStateInterface $form_state) {
    $queue = $this->queueFactory
      ->get($form_state
      ->getValue('queue_name'));

    // There is no harm in trying to recreate existing.
    $queue
      ->createQueue();
    $item = $queue
      ->claimItem($form_state
      ->getValue('claim_time'));
    $count = $queue
      ->numberOfItems();
    if (!empty($item)) {
      $this
        ->messenger()
        ->addMessage($this
        ->t('Claimed item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.', [
        '@count' => $count,
        '@item_id' => $item->item_id,
        '@string' => $item->data,
        '@seconds' => $form_state
          ->getValue('claim_time'),
      ]));
    }
    else {
      $this
        ->messenger()
        ->addMessage($this
        ->t('There were no items in the queue available to claim. There are @count items in the queue.', [
        '@count' => $count,
      ]));
    }
    $form_state
      ->setRebuild();
  }

  /**
   * Submit function for "Claim and delete" button.
   *
   * @param array $form
   *   Form definition array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   */
  public function submitClaimDeleteItem(array &$form, FormStateInterface $form_state) {
    $queue = $this->queueFactory
      ->get($form_state
      ->getValue('queue_name'));

    // There is no harm in trying to recreate existing.
    $queue
      ->createQueue();
    $count = $queue
      ->numberOfItems();
    $item = $queue
      ->claimItem(60);
    if (!empty($item)) {
      $this
        ->messenger()
        ->addMessage($this
        ->t('Claimed and deleted item id=@item_id string=@string for @seconds seconds. There are @count items in the queue.', [
        '@count' => $count,
        '@item_id' => $item->item_id,
        '@string' => $item->data,
        '@seconds' => $form_state
          ->getValue('claim_time'),
      ]));
      $queue
        ->deleteItem($item);
      $count = $queue
        ->numberOfItems();
      $this
        ->messenger()
        ->addMessage($this
        ->t('There are now @count items in the queue.', [
        '@count' => $count,
      ]));
    }
    else {
      $count = $queue
        ->numberOfItems();
      $this
        ->messenger()
        ->addMessage($this
        ->t('There were no items in the queue available to claim/delete. There are currently @count items in the queue.', [
        '@count' => $count,
      ]));
    }
    $form_state
      ->setRebuild();
  }

  /**
   * Submit function for "run cron" button.
   *
   * Runs cron (to release expired claims) and reports the results.
   *
   * @param array $form
   *   Form definition array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   */
  public function submitRunCron(array &$form, FormStateInterface $form_state) {
    $this->cron
      ->run();
    $queue = $this->queueFactory
      ->get($form_state
      ->getValue('queue_name'));

    // @see https://www.drupal.org/node/2705809
    if ($queue instanceof QueueGarbageCollectionInterface) {
      $queue
        ->garbageCollection();
    }

    // There is no harm in trying to recreate existing.
    $queue
      ->createQueue();
    $count = $queue
      ->numberOfItems();
    $this
      ->messenger()
      ->addMessage($this
      ->t('Ran cron. If claimed items expired, they should be expired now. There are now @count items in the queue', [
      '@count' => $count,
    ]));
    $form_state
      ->setRebuild();
  }

  /**
   * Submit handler for clearing/deleting the queue.
   *
   * @param array $form
   *   Form definition array.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   Form state object.
   */
  public function submitDeleteQueue(array &$form, FormStateInterface $form_state) {
    $queue = $this->queueFactory
      ->get($form_state
      ->getValue('queue_name'));
    $queue
      ->deleteQueue();
    $this
      ->messenger()
      ->addMessage($this
      ->t('Deleted the @queue_name queue and all items in it', [
      '@queue_name' => $form_state
        ->getValue('queue_name'),
    ]));
  }

  /**
   * Helper method to format a queue item for display in a summary table.
   *
   * @param array $item
   *   Queue item array with keys for item_id, expire, created, and data.
   *
   * @return array
   *   An array with the queue properties in the right order for display in a
   *   summary table.
   */
  private function processQueueItemForTable(array $item) {
    if ($item['expire'] > 0) {
      $item['expire'] = $this
        ->t('Claimed: expires %expire', [
        '%expire' => date('r', $item['expire']),
      ]);
    }
    else {
      $item['expire'] = $this
        ->t('Unclaimed');
    }
    $item['created'] = date('r', $item['created']);
    $item['content'] = Html::escape(unserialize($item['data']));
    unset($item['data']);
    return $item;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
FormBase::$configFactory protected property The config factory. 3
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::config protected function Retrieves a configuration object.
FormBase::configFactory protected function Gets the config factory for this form. 3
FormBase::container private function Returns the service container.
FormBase::currentUser protected function Gets the current user.
FormBase::getRequest protected function Gets the request object.
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route.
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
FormBase::validateForm public function Form validation handler. Overrides FormInterface::validateForm 72
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 27
MessengerTrait::messenger public function Gets the messenger. 27
MessengerTrait::setMessenger public function Sets the messenger.
QueueExampleForm::$cron protected property The CronInterface object.
QueueExampleForm::$database protected property The database object.
QueueExampleForm::$queueFactory protected property The queue object.
QueueExampleForm::$queueType protected property What kind of queue backend are we using?
QueueExampleForm::buildForm public function Form constructor. Overrides FormInterface::buildForm
QueueExampleForm::create public static function Instantiates a new instance of this class. Overrides FormBase::create
QueueExampleForm::doesQueueUseDb protected function Check if we are using the default database queue.
QueueExampleForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
QueueExampleForm::processQueueItemForTable private function Helper method to format a queue item for display in a summary table.
QueueExampleForm::retrieveQueue public function Retrieves the queue from the database for display purposes only.
QueueExampleForm::submitAddQueueItem public function Submit function for the insert-into-queue button.
QueueExampleForm::submitClaimDeleteItem public function Submit function for "Claim and delete" button.
QueueExampleForm::submitClaimItem public function Submit function for the "claim" button.
QueueExampleForm::submitDeleteQueue public function Submit handler for clearing/deleting the queue.
QueueExampleForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
QueueExampleForm::submitRunCron public function Submit function for "run cron" button.
QueueExampleForm::submitShowQueue public function Submit function for the show-queue button.
QueueExampleForm::__construct public function Constructor.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.