1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Twig\Cache; 13 14/** 15 * Chains several caches together. 16 * 17 * Cached items are fetched from the first cache having them in its data store. 18 * They are saved and deleted in all adapters at once. 19 * 20 * @author Quentin Devos <quentin@devos.pm> 21 */ 22final class ChainCache implements CacheInterface, RemovableCacheInterface 23{ 24 /** 25 * @param iterable<CacheInterface> $caches The ordered list of caches used to store and fetch cached items 26 */ 27 public function __construct( 28 private iterable $caches, 29 ) { 30 } 31 32 public function generateKey(string $name, string $className): string 33 { 34 return $className.'#'.$name; 35 } 36 37 public function write(string $key, string $content): void 38 { 39 $splitKey = $this->splitKey($key); 40 41 foreach ($this->caches as $cache) { 42 $cache->write($cache->generateKey(...$splitKey), $content); 43 } 44 } 45 46 public function load(string $key): void 47 { 48 [$name, $className] = $this->splitKey($key); 49 50 foreach ($this->caches as $cache) { 51 $cache->load($cache->generateKey($name, $className)); 52 53 if (class_exists($className, false)) { 54 break; 55 } 56 } 57 } 58 59 public function getTimestamp(string $key): int 60 { 61 $splitKey = $this->splitKey($key); 62 63 foreach ($this->caches as $cache) { 64 if (0 < $timestamp = $cache->getTimestamp($cache->generateKey(...$splitKey))) { 65 return $timestamp; 66 } 67 } 68 69 return 0; 70 } 71 72 public function remove(string $name, string $cls): void 73 { 74 foreach ($this->caches as $cache) { 75 if ($cache instanceof RemovableCacheInterface) { 76 $cache->remove($name, $cls); 77 } 78 } 79 } 80 81 /** 82 * @return string[] 83 */ 84 private function splitKey(string $key): array 85 { 86 return array_reverse(explode('#', $key, 2)); 87 } 88} 89