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