Version 1
[yaffs-website] / web / core / lib / Drupal / Component / FileCache / FileCache.php
diff --git a/web/core/lib/Drupal/Component/FileCache/FileCache.php b/web/core/lib/Drupal/Component/FileCache/FileCache.php
new file mode 100644 (file)
index 0000000..eea92ac
--- /dev/null
@@ -0,0 +1,160 @@
+<?php
+
+namespace Drupal\Component\FileCache;
+
+/**
+ * Allows to cache data based on file modification dates.
+ */
+class FileCache implements FileCacheInterface {
+
+  /**
+   * Prefix that is used for cache entries.
+   *
+   * @var string
+   */
+  protected $prefix;
+
+  /**
+   * Static cache that contains already loaded cache entries.
+   *
+   * @var array
+   */
+  protected static $cached = [];
+
+  /**
+   * The collection identifier of this cache.
+   *
+   * @var string
+   */
+  protected $collection;
+
+  /**
+   * The cache backend backing this FileCache object.
+   *
+   * @var \Drupal\Component\FileCache\FileCacheBackendInterface
+   */
+  protected $cache;
+
+  /**
+   * Constructs a FileCache object.
+   *
+   * @param string $prefix
+   *   The cache prefix.
+   * @param string $collection
+   *   A collection identifier to ensure that the same files could be cached for
+   *   different purposes without clashing.
+   * @param string|null $cache_backend_class
+   *   (optional) The class that should be used as cache backend.
+   * @param array $cache_backend_configuration
+   *   (optional) The configuration for the backend class.
+   */
+  public function __construct($prefix, $collection, $cache_backend_class = NULL, array $cache_backend_configuration = []) {
+
+    if (empty($prefix)) {
+      throw new \InvalidArgumentException('Required prefix configuration is missing');
+    }
+
+    $this->prefix = $prefix;
+    $this->collection = $collection;
+
+    if (isset($cache_backend_class)) {
+      $this->cache = new $cache_backend_class($cache_backend_configuration);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($filepath) {
+    $filepaths = [$filepath];
+    $cached = $this->getMultiple($filepaths);
+    return isset($cached[$filepath]) ? $cached[$filepath] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMultiple(array $filepaths) {
+    $file_data = [];
+    $remaining_cids = [];
+
+    // First load from the static cache what we can.
+    foreach ($filepaths as $filepath) {
+      if (!file_exists($filepath)) {
+        continue;
+      }
+
+      $realpath = realpath($filepath);
+      // If the file exists but realpath returns nothing, it is using a stream
+      // wrapper, those are not supported.
+      if (empty($realpath)) {
+        continue;
+      }
+
+      $cid = $this->prefix . ':' . $this->collection . ':' . $realpath;
+      if (isset(static::$cached[$cid]) && static::$cached[$cid]['mtime'] == filemtime($filepath)) {
+        $file_data[$filepath] = static::$cached[$cid]['data'];
+      }
+      else {
+        // Collect a list of cache IDs that we still need to fetch from cache
+        // backend.
+        $remaining_cids[$cid] = $filepath;
+      }
+    }
+
+    // If there are any cache IDs left to fetch from the cache backend.
+    if ($remaining_cids && $this->cache) {
+      $cache_results = $this->cache->fetch(array_keys($remaining_cids)) ?: [];
+      foreach ($cache_results as $cid => $cached) {
+        $filepath = $remaining_cids[$cid];
+        if ($cached['mtime'] == filemtime($filepath)) {
+          $file_data[$cached['filepath']] = $cached['data'];
+          static::$cached[$cid] = $cached;
+        }
+      }
+    }
+
+    return $file_data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($filepath, $data) {
+    $realpath = realpath($filepath);
+    $cached = [
+      'mtime' => filemtime($filepath),
+      'filepath' => $filepath,
+      'data' => $data,
+    ];
+
+    $cid = $this->prefix . ':' . $this->collection . ':' . $realpath;
+    static::$cached[$cid] = $cached;
+    if ($this->cache) {
+      $this->cache->store($cid, $cached);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete($filepath) {
+    $realpath = realpath($filepath);
+    $cid = $this->prefix . ':' . $this->collection . ':' . $realpath;
+
+    unset(static::$cached[$cid]);
+    if ($this->cache) {
+      $this->cache->delete($cid);
+    }
+  }
+
+  /**
+   * Resets the static cache.
+   *
+   * @todo Replace this once https://www.drupal.org/node/2260187 is in.
+   */
+  public static function reset() {
+    static::$cached = [];
+  }
+
+}