You are here

KeyValueStoreExpirable.php in MongoDB 8.2

File

modules/mongodb_storage/src/KeyValueStoreExpirable.php
View source
<?php

declare (strict_types=1);
namespace Drupal\mongodb_storage;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use MongoDB\BSON\UTCDateTime;

/**
 * KeyValueStore provides a KeyValueStoreExpirable as a MongoDB collection.
 */
class KeyValueStoreExpirable extends KeyValueStore implements KeyValueStoreExpirableInterface {

  /**
   * The datetime.time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * {@inheritdoc}
   *
   * @see \Drupal\mongodb_storage\KeyValueStoreExpirable::setTimeService()
   */
  public function __construct($collection, $storeCollection) {
    parent::__construct($collection, $storeCollection);
    $this
      ->ensureIndexes();
  }

  /**
   * Deletes all items from the key/value store.
   */
  public function deleteAll() {
    $this->mongoDbCollection
      ->drop();
    $this
      ->ensureIndexes();
  }

  /**
   * Ensure a TTL index for server-side expirations.
   */
  public function ensureIndexes() {
    $name = $this->mongoDbCollection
      ->getCollectionName();
    $indexMissing = TRUE;
    foreach ($this->mongoDbCollection
      ->listIndexes() as $index) {
      if ($index
        ->isTtl()) {
        $indexMissing = FALSE;
        break;
      }
    }
    if ($indexMissing) {
      $indexes = [
        [
          'expireAfterSeconds' => 0,
          'key' => [
            'expire' => 1,
          ],
          'name' => "ttl_" . $name,
        ],
      ];
      $this->mongoDbCollection
        ->createIndexes($indexes);
    }
  }

  /**
   * Convert a UNIX timestamp to a BSON one for document insertion.
   *
   * @param int $expire
   *   The source timestamp.
   *
   * @return \MongoDB\BSON\UTCDateTime
   *   Its ready-to-insert counterpart.
   */
  protected function getBsonExpire(int $expire) : UTCDateTime {
    return new UTCDateTime(1000 * ($this->time
      ->getCurrentTime() + $expire));
  }

  /**
   * Saves an array of values with a time to live.
   *
   * @param array $data
   *   An array of data to store.
   * @param int $expire
   *   The time to live for items, in seconds.
   */
  public function setMultipleWithExpire(array $data, $expire) {
    foreach ($data as $key => $value) {
      $this
        ->setWithExpire($key, $value, $expire);
    }
  }

  /**
   * Inject the time service. Cannot do it in the constructor for compatibility.
   *
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The datetime.time service.
   */
  public function setTimeService(TimeInterface $time) {
    $this->time = $time;
  }

  /**
   * Saves a value for a given key with a time to live.
   *
   * This does not need microsecond precision, since expires happen with only a
   * multi-second accuracy at best.
   *
   * @param string $key
   *   The key of the data to store.
   * @param mixed $value
   *   The data to store.
   * @param int $expire
   *   The time to live for items, in seconds.
   */
  public function setWithExpire($key, $value, $expire) {
    $selector = [
      '_id' => $this
        ->stringifyKey($key),
    ];
    $replacement = $selector + [
      'expire' => $this
        ->getBsonExpire($expire),
      'value' => serialize($value),
    ];
    $options = [
      'upsert' => TRUE,
    ];
    $this->mongoDbCollection
      ->replaceOne($selector, $replacement, $options);
  }

  /**
   * Sets a value for a given key with a time to live if it does not yet exist.
   *
   * @param string $key
   *   The key of the data to store.
   * @param mixed $value
   *   The data to store.
   * @param int $expire
   *   The time to live for items, in seconds.
   *
   * @return bool
   *   TRUE if the data was set, or FALSE if it already existed.
   */
  public function setWithExpireIfNotExists($key, $value, $expire) {
    $selector = [
      '_id' => $this
        ->stringifyKey($key),
    ];
    $replacement = $selector + [
      'expire' => $this
        ->getBsonExpire($expire),
      'value' => serialize($value),
    ];
    $options = [
      'upsert' => FALSE,
    ];
    $updateResult = $this->mongoDbCollection
      ->replaceOne($selector, $replacement, $options);
    $result = $updateResult
      ->getModifiedCount() ? TRUE : FALSE;
    return $result;
  }

}

Classes

Namesort descending Description
KeyValueStoreExpirable KeyValueStore provides a KeyValueStoreExpirable as a MongoDB collection.