Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
CachedConfig
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
4 / 4
7
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __invoke
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 set
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 remove
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of php-fast-forward/config.
7 *
8 * This source file is subject to the license bundled
9 * with this source code in the file LICENSE.
10 *
11 * @link      https://github.com/php-fast-forward/config
12 * @copyright Copyright (c) 2025 Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
13 * @license   https://opensource.org/licenses/MIT MIT License
14 */
15
16namespace FastForward\Config;
17
18use Psr\SimpleCache\CacheInterface;
19use Psr\SimpleCache\InvalidArgumentException;
20
21/**
22 * Class CachedConfig.
23 *
24 * Provides a cached implementation of a configuration source.
25 * This class MUST cache the configuration output of the decorated ConfigInterface instance.
26 * It SHALL lazily initialize and retrieve cached configuration data upon invocation.
27 */
28final class CachedConfig implements ConfigInterface
29{
30    use LazyLoadConfigTrait;
31
32    /**
33     * Constructs a CachedConfig wrapper.
34     *
35     * This constructor SHALL accept a PSR-16 cache implementation and a configuration instance
36     * to be cached. It MUST defer reading and writing the configuration until invoked.
37     *
38     * @param CacheInterface  $cache         the cache implementation used for storing configuration data
39     * @param ConfigInterface $defaultConfig the configuration source to be cached
40     * @param bool            $persistent    whether the cache should be persistent or not
41     * @param null|string     $cacheKey      the cache key to use for storing the configuration data
42     */
43    public function __construct(
44        private readonly CacheInterface $cache,
45        private readonly ConfigInterface $defaultConfig,
46        private readonly bool $persistent = false,
47        private ?string $cacheKey = null,
48    ) {
49        $this->cacheKey ??= $this->defaultConfig::class;
50    }
51
52    /**
53     * Invokes the configuration and returns the cached configuration data.
54     *
55     * If the configuration has not yet been cached, it MUST be stored in the cache upon first invocation.
56     * This method MUST return a ConfigInterface implementation containing the cached configuration data.
57     *
58     * @return ConfigInterface a ConfigInterface implementation containing the cached configuration data
59     *
60     * @throws InvalidArgumentException if the cache key is invalid
61     */
62    public function __invoke(): ConfigInterface
63    {
64        if (!$this->cache->has($this->cacheKey)) {
65            $this->cache->set($this->cacheKey, $this->defaultConfig->toArray());
66        }
67
68        return new ArrayConfig($this->cache->get($this->cacheKey));
69    }
70
71    /**
72     * Sets configuration data.
73     *
74     * This method MUST update the cached configuration data in the cache if the persistent flag is set to true.
75     *
76     * @param array|ConfigInterface|string $key   the configuration key or an array of key-value pairs to set
77     * @param mixed                        $value the value to set for the specified key
78     *
79     * @throws InvalidArgumentException if the key is invalid
80     */
81    public function set(array|ConfigInterface|string $key, mixed $value = null): void
82    {
83        $config = $this->getConfig();
84        $config->set($key, $value);
85
86        if ($this->persistent) {
87            $this->cache->set($this->cacheKey, $config->toArray());
88        }
89    }
90
91    /**
92     * Retrieves a configuration value by key.
93     *
94     * This method MUST return the cached value if it exists, or the default value if not found.
95     *
96     * @param string $key the configuration key to retrieve
97     *
98     * @return mixed the configuration value or the default value
99     */
100    public function remove(mixed $key): void
101    {
102        $config = $this->getConfig();
103        $config->remove($key);
104
105        if ($this->persistent) {
106            $this->cache->set($this->cacheKey, $config->toArray());
107        }
108    }
109}