Template::isUsingCache()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Esi\SimpleTpl.
7
 *
8
 * (c) 2006 - 2025 Eric Sizemore <[email protected]>
9
 *
10
 * This file is licensed under The MIT License. For the full copyright and
11
 * license information, please view the LICENSE.md file that was distributed
12
 * with this source code.
13
 */
14
15
namespace Esi\SimpleTpl;
16
17
use Esi\SimpleTpl\Exception\TemplateHasNoContentException;
18
use Esi\SimpleTpl\Exception\TemplateNotFoundException;
19
use Esi\SimpleTpl\Exception\TemplateVariablesException;
20
use Esi\SimpleTpl\Storage\StorageInterface;
21
use Psr\Cache\CacheItemPoolInterface;
22
use Psr\Cache\InvalidArgumentException as PsrInvalidArgumentException;
23
24
use function array_keys;
25
use function array_map;
26
use function array_merge;
27
use function array_values;
28
use function crc32;
29
use function dechex;
30
use function str_replace;
31
32
final class Template
33
{
34
    private string $leftDelimiter = '{';
35
36
    private string $rightDelimiter = '}';
37
38
    /**
39
     * @var array<string>
40
     */
41
    private array $tplVars = [];
42
43
    /**
44
     * Constructor.
45
     */
46 16
    public function __construct(
47
        private readonly StorageInterface $storage,
48
        private readonly ?CacheItemPoolInterface $cacheItemPool = null
49 16
    ) {}
50
51
    /**
52
     * Clears the cache.
53
     *
54
     * @return bool True if the cache was cleared successfully, false otherwise.
55
     */
56 3
    public function clearCache(): bool
57
    {
58 3
        if (!$this->isUsingCache()) {
59 2
            return true;
60
        }
61
62 1
        return $this->cacheItemPool->clear();
63
    }
64
65
    /**
66
     * Displays the parsed template.
67
     *
68
     * @param string $templateName The path to the template file.
69
     *
70
     * @throws PsrInvalidArgumentException
71
     */
72 1
    public function display(string $templateName): void
73
    {
74 1
        echo $this->parse($templateName);
75
    }
76
77
    /**
78
     * Gets the left delimiter.
79
     *
80
     * @return string The left delimiter.
81
     */
82 1
    public function getLeftDelimiter(): string
83
    {
84 1
        return $this->leftDelimiter;
85
    }
86
87
    /**
88
     * Gets the right delimiter.
89
     *
90
     * @return string The right delimiter.
91
     */
92 1
    public function getRightDelimiter(): string
93
    {
94 1
        return $this->rightDelimiter;
95
    }
96
97
    /**
98
     * Gets the template variables.
99
     *
100
     * @return array<string> The template variables.
101
     */
102 2
    public function getTplVars(): array
103
    {
104 2
        return $this->tplVars;
105
    }
106
107
    /**
108
     * Checks if caching is enabled.
109
     *
110
     * @psalm-assert-if-true !null $this->cacheItemPool
111
     *
112
     * @return bool True if caching is enabled, false otherwise.
113
     */
114 12
    public function isUsingCache(): bool
115
    {
116 12
        return $this->cacheItemPool instanceof CacheItemPoolInterface;
117
    }
118
119
    /**
120
     * Parses the template and replaces variables.
121
     *
122
     * @param string $templateName The name of the template.
123
     *
124
     * @throws TemplateNotFoundException     If the template cannot be found or read.
125
     * @throws TemplateHasNoContentException If the template has no content.
126
     * @throws TemplateVariablesException    If there are no template variables set.
127
     * @throws PsrInvalidArgumentException
128
     *
129
     * @return string The parsed template content.
130
     */
131 12
    public function parse(string $templateName): string
132
    {
133 12
        $cacheKey = $this->generateCacheKey($templateName);
134
135 12
        if ($this->isUsingCache() && $this->cacheItemPool->hasItem($cacheKey)) {
136
            /**
137
             * @var string $templateCache
138
             */
139 1
            $templateCache = $this->cacheItemPool->getItem($cacheKey)->get();
140
141 1
            return $templateCache;
142
        }
143
144
        // Load template content
145 11
        $contents = $this->storage->loadTemplate($templateName);
146
147 7
        if ($this->tplVars === []) {
148 1
            throw TemplateVariablesException::create();
149
        }
150
151
        // Perform replacements
152 6
        $contents = $this->doReplacements($contents);
153
154 6
        if ($this->isUsingCache()) {
155 3
            $this->cacheItemPool->save($this->cacheItemPool->getItem($cacheKey)->set($contents));
156
        }
157
158 6
        return $contents;
159
    }
160
161
    /**
162
     * Refreshes the cache for a specific template file.
163
     *
164
     * @param string $templateName The path to the template file.
165
     *
166
     * @throws PsrInvalidArgumentException
167
     *
168
     * @return bool True if the cache was refreshed successfully, false otherwise.
169
     */
170 2
    public function refreshCache(string $templateName): bool
171
    {
172 2
        if (!$this->isUsingCache()) {
173 1
            return true;
174
        }
175
176 1
        return $this->cacheItemPool->deleteItem($this->generateCacheKey($templateName));
177
    }
178
179
    /**
180
     * Sets the left delimiter.
181
     *
182
     * @param string $delimiter The left delimiter.
183
     */
184 1
    public function setLeftDelimiter(string $delimiter): self
185
    {
186 1
        $this->leftDelimiter = $delimiter;
187
188 1
        return $this;
189
    }
190
191
    /**
192
     * Sets the right delimiter.
193
     *
194
     * @param string $delimiter The right delimiter.
195
     */
196 1
    public function setRightDelimiter(string $delimiter): self
197
    {
198 1
        $this->rightDelimiter = $delimiter;
199
200 1
        return $this;
201
    }
202
203
    /**
204
     * Sets the template variables.
205
     *
206
     * An empty array can be passed to clear/reset previously assigned variables.
207
     *
208
     * @param array<string> $tplVars Template variables and replacements.
209
     */
210 11
    public function setTplVars(array $tplVars): self
211
    {
212 11
        $this->tplVars = ($tplVars === []) ? [] : array_merge($this->tplVars, $tplVars);
213
214 11
        return $this;
215
    }
216
217
    /**
218
     * Replaces template variables in the content.
219
     *
220
     * @param string $contents The content of the template file.
221
     *
222
     * @return string The content with template variables replaced.
223
     */
224 6
    private function doReplacements(string $contents): string
225
    {
226 6
        return str_replace(
227 6
            array_map(
228 6
                fn (int|string $find): string => \sprintf('%s%s%s', $this->leftDelimiter, $find, $this->rightDelimiter),
229 6
                array_keys($this->tplVars)
230 6
            ),
231 6
            array_values($this->tplVars),
232 6
            $contents
233 6
        );
234
    }
235
236
    /**
237
     * Generates a cache key for a template.
238
     *
239
     * @param string $templateName The name of the template.
240
     *
241
     * @return string The generated cache key.
242
     */
243 12
    private function generateCacheKey(string $templateName): string
244
    {
245 12
        return \sprintf('template_%s', dechex(crc32($templateName)));
246
    }
247
}
248