<?php

namespace Drupal\autoslave;

use Drupal\Core\Cache\CacheBackendInterface;

/**
 * Abstract cache backend that delays cache clearing until after transactions.
 */
abstract class AutoslaveCache implements CacheBackendInterface {
  private $backend = NULL;
  protected $bin;
  private static $buffer = [];

  /**
   * Destructor. Clears the cache buffer on object destruction.
   */
  public function __destruct() {
    self::clearBuffer();
  }

  /**
   * Clears all buffered cache operations.
   */
  public static function clearBuffer() {
    foreach (self::$buffer as $bin => $data) {
      [$cid, $wildcard] = $data;
      _cache_get_object($bin)->clear($cid, $wildcard);
    }
    self::$buffer = [];
  }

  /**
   * Clears cache entries, buffering the operation if inside a transaction.
   */
  public function clear($cid = NULL, $wildcard = FALSE) {
    $connection = \Database::getConnection();
    $depth = $connection->transactionDepth();
    if ($depth == 0) {
      return $this->clear($cid, $wildcard);
    }
    else {
      return self::$buffer[$this->bin] = [$cid, $wildcard];
    }
  }

  /**
   * Checks if the cache is empty.
   */
  public function isEmpty() {
    return $this->isEmpty();
  }

  /**
   * Stores data in the cache.
   */
  public function set($cid, $data, $expire = CACHE_PERMANENT, array $tags = []) {
    return $this->set($cid, $data, $expire);
  }

  /**
   * Returns data from the cache.
   */
  public function get($cid, $allow_invalid = FALSE) {
    $cids = [$cid];
    $cache = $this->getMultiple($cids);
    return reset($cache);
  }

  /**
   * Constructor.
   * Initialize bin and prefetch data
   */
  public function __construct($bin) {
    $this->bin = $bin;

    // Let our parent do his work.
    $class = variable_get('autoslave_cache_class_' . $bin);
    if (!isset($class)) {
      $class = variable_get('autoslave_cache_default_class', 'DrupalDatabaseCache');
    }
    $this->backend = new $class($bin);
  }

  /**
   * Aggregate cache data from prefetch and requested.
   */
  public function getMultiple(&$cids, $allow_invalid = FALSE) {
    return $this->getMultiple($cids);
  }

}
