You are here

class DepcalcCacheBackend in Dependency Calculation 8

Class DepcalcCacheBackend

Provides a depcalc specific cache backend that can invalidate depcalc cache tags in the database table. This class also works as an adapter, so if another cache backend is passed to it, it will proxy calls, including tag invalidation, to that backend.

@package Drupal\depcalc\Cache

Hierarchy

Expanded class hierarchy of DepcalcCacheBackend

File

src/Cache/DepcalcCacheBackend.php, line 24

Namespace

Drupal\depcalc\Cache
View source
class DepcalcCacheBackend implements CacheBackendInterface, CacheTagsInvalidatorInterface {

  /**
   * The cache backend to decorate.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $backend;

  /**
   * The event dispatcher.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected $dispatcher;

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

  /**
   * The bin name.
   *
   * @var string
   */
  protected $bin;

  /**
   * DepcalcCacheBackend constructor.
   *
   * @param \Drupal\Core\Cache\CacheBackendInterface $backend
   *   The CacheBackendInterface object to decorate.
   *
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
   *   The event dispatcher.
   *
   * @throws \ReflectionException
   */
  public function __construct(CacheBackendInterface $backend, EventDispatcherInterface $dispatcher) {
    $this->backend = $backend;
    $this->dispatcher = $dispatcher;
    if ($backend instanceof DatabaseBackend) {
      $this
        ->getProperties($backend);
    }
  }

  /**
   * Get the DatabaseBackend instance's database connection.
   *
   * We don't want to get our own database connection or cache bin, so we just
   * reflect it out of the object we're decorating.
   *
   * @param \Drupal\Core\Cache\DatabaseBackend $backend
   *   The database backend object from which to extract necessary properties.
   *
   * @throws \ReflectionException
   */
  private function getProperties(DatabaseBackend $backend) : void {
    $r = new \ReflectionObject($backend);
    $p = $r
      ->getProperty('connection');
    $p
      ->setAccessible(TRUE);
    $this->connection = $p
      ->getValue($backend);
    $p = $r
      ->getProperty('bin');
    $p
      ->setAccessible(TRUE);
    $this->bin = $p
      ->getValue($backend);
  }

  /**
   * {@inheritdoc}
   */
  public function invalidateMultiple(array $cids, $allow_invalid = FALSE) {
    $original_cids = $cids;

    // $this->getMultiple($cids) removes the successfully obtained $cids.
    // And because it is passed by reference then we need to invalidate
    // the original $cids.
    $cache_objects = $this
      ->getMultiple($cids, $allow_invalid);
    $this->backend
      ->invalidateMultiple($original_cids);
    if (!$cache_objects) {
      return;
    }

    /** @var \Drupal\depcalc\DependentEntityWrapperInterface[] $wrappers */
    $wrappers = array_map(function ($cache) {
      return $cache->data;
    }, $cache_objects);
    $event = new InvalidateDependenciesEvent($wrappers);
    $this->dispatcher
      ->dispatch(DependencyCalculatorEvents::INVALIDATE_DEPENDENCIES, $event);
  }

  /**
   * {@inheritdoc}
   */
  public function get($cid, $allow_invalid = FALSE) {
    return $this->backend
      ->get($cid, $allow_invalid);
  }

  /**
   * {@inheritdoc}
   */
  public function getMultiple(&$cids, $allow_invalid = FALSE) {
    return $this->backend
      ->getMultiple($cids, $allow_invalid);
  }

  /**
   * {@inheritdoc}
   */
  public function set($cid, $data, $expire = Cache::PERMANENT, array $tags = []) {
    $this->backend
      ->set($cid, $data, $expire, $tags);
  }

  /**
   * {@inheritdoc}
   */
  public function setMultiple(array $items) {
    $this->backend
      ->setMultiple($items);
  }

  /**
   * {@inheritdoc}
   */
  public function delete($cid) {

    // Invalidate first to handle the dependencies.
    $this
      ->invalidate($cid);
    $this->backend
      ->delete($cid);
  }

  /**
   * {@inheritdoc}
   */
  public function deleteMultiple(array $cids) {
    $this->backend
      ->deleteMultiple($cids);
  }

  /**
   * {@inheritdoc}
   */
  public function deleteAll() {
    $this->backend
      ->deleteAll();
  }

  /**
   * {@inheritdoc}
   */
  public function invalidate($cid) {
    $this
      ->invalidateMultiple([
      $cid,
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function invalidateAll() {
    $this->backend
      ->invalidateAll();
  }

  /**
   * {@inheritdoc}
   */
  public function garbageCollection() {
    $this->backend
      ->garbageCollection();
  }

  /**
   * {@inheritdoc}
   */
  public function removeBin() {
    $this->backend
      ->removeBin();
  }

  /**
   * {@inheritdoc}
   */
  public function invalidateTags(array $tags) {
    if (!Uuid::isValid(reset($tags))) {

      // If the first item is not a UUID then none of them are.
      return;
    }
    if ($this->backend instanceof DatabaseBackend) {

      // On module install, this will get called, so let's check that the table
      // exists before doing anything.
      if (!$this->connection
        ->schema()
        ->tableExists($this->bin)) {
        return;
      }
      foreach ($tags as $tag) {
        $result = $this->connection
          ->select($this->bin, 'bin')
          ->fields('bin', [
          'cid',
        ])
          ->condition('tags', "%{$this->connection->escapeLike($tag)}%", 'LIKE')
          ->execute();
        $cids = $result
          ->fetchCol();
        if (empty($cids)) {
          continue;
        }

        // Allow for invalidated cache to be invalidated too.
        $this
          ->invalidateMultiple($cids, TRUE);
      }
    }
    elseif ($this->backend instanceof CacheTagsInvalidatorInterface) {
      $this->backend
        ->invalidateTags($tags);
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CacheBackendInterface::CACHE_PERMANENT constant Indicates that the item should never be removed unless explicitly deleted.
DepcalcCacheBackend::$backend protected property The cache backend to decorate.
DepcalcCacheBackend::$bin protected property The bin name.
DepcalcCacheBackend::$connection protected property The database connection.
DepcalcCacheBackend::$dispatcher protected property The event dispatcher.
DepcalcCacheBackend::delete public function Deletes an item from the cache. Overrides CacheBackendInterface::delete
DepcalcCacheBackend::deleteAll public function Deletes all cache items in a bin. Overrides CacheBackendInterface::deleteAll
DepcalcCacheBackend::deleteMultiple public function Deletes multiple items from the cache. Overrides CacheBackendInterface::deleteMultiple
DepcalcCacheBackend::garbageCollection public function Performs garbage collection on a cache bin. Overrides CacheBackendInterface::garbageCollection
DepcalcCacheBackend::get public function Returns data from the persistent cache. Overrides CacheBackendInterface::get
DepcalcCacheBackend::getMultiple public function Returns data from the persistent cache when given an array of cache IDs. Overrides CacheBackendInterface::getMultiple
DepcalcCacheBackend::getProperties private function Get the DatabaseBackend instance's database connection.
DepcalcCacheBackend::invalidate public function Marks a cache item as invalid. Overrides CacheBackendInterface::invalidate
DepcalcCacheBackend::invalidateAll public function Marks all cache items as invalid. Overrides CacheBackendInterface::invalidateAll
DepcalcCacheBackend::invalidateMultiple public function Marks cache items as invalid. Overrides CacheBackendInterface::invalidateMultiple
DepcalcCacheBackend::invalidateTags public function Marks cache items with any of the specified tags as invalid. Overrides CacheTagsInvalidatorInterface::invalidateTags
DepcalcCacheBackend::removeBin public function Remove a cache bin. Overrides CacheBackendInterface::removeBin
DepcalcCacheBackend::set public function Stores data in the persistent cache. Overrides CacheBackendInterface::set
DepcalcCacheBackend::setMultiple public function Store multiple items in the persistent cache. Overrides CacheBackendInterface::setMultiple
DepcalcCacheBackend::__construct public function DepcalcCacheBackend constructor.