Passed
Push — master ( cc3241...e24646 )
by Eric
01:01 queued 13s
created

Template::readFile()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 3
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 15
    public function __construct(
47
        private readonly StorageInterface $storage,
48
        private readonly ?CacheItemPoolInterface $cacheItemPool = null
49 15
    ) {}
50
51
    /**
52
     * Clears the cache.
53
     *
54
     * @return bool True if the cache was cleared successfully, false otherwise.
55
     */
56 2
    public function clearCache(): bool
57
    {
58 2
        if (!$this->isUsingCache()) {
59 1
            return true;
60
        }
61
62 1
        return $this->cacheItemPool->clear();
63
    }
64
65
    /**
66
     * Displays the parsed template.
67
     *
68
     * @param string $tplFile The path to the template file.
69
     *
70
     * @throws PsrInvalidArgumentException
71
     */
72 1
    public function display(string $tplFile): void
73
    {
74 1
        echo $this->parse($tplFile);
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 11
    public function isUsingCache(): bool
115
    {
116 11
        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 11
    public function parse(string $templateName): string
132
    {
133 11
        $cacheKey = $this->generateCacheKey($templateName);
134
135 11
        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 10
        $contents = $this->storage->loadTemplate($templateName);
146
147 6
        if ($this->tplVars === []) {
148 1
            throw TemplateVariablesException::create();
149
        }
150
151
        // Perform replacements
152 5
        $contents = $this->doReplacements($contents);
153
154 5
        if ($this->isUsingCache()) {
155 3
            $this->cacheItemPool->save($this->cacheItemPool->getItem($cacheKey)->set($contents));
156
        }
157
158 5
        return $contents;
159
    }
160
161
    /**
162
     * Refreshes the cache for a specific template file.
163
     *
164
     * @param string $tplFile 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 $tplFile): bool
171
    {
172 2
        if (!$this->isUsingCache()) {
173 1
            return true;
174
        }
175
176 1
        return $this->cacheItemPool->deleteItem($this->generateCacheKey($tplFile));
177
    }
178
179
    /**
180
     * Sets the left delimiter.
181
     *
182
     * @param string $delimiter The left delimiter.
183
     */
184 1
    public function setLeftDelimiter(string $delimiter): void
185
    {
186 1
        $this->leftDelimiter = $delimiter;
187
    }
188
189
    /**
190
     * Sets the right delimiter.
191
     *
192
     * @param string $delimiter The right delimiter.
193
     */
194 1
    public function setRightDelimiter(string $delimiter): void
195
    {
196 1
        $this->rightDelimiter = $delimiter;
197
    }
198
199
    /**
200
     * Sets the template variables.
201
     *
202
     * An empty array can be passed to clear/reset previously assigned variables.
203
     *
204
     * @param array<string> $tplVars Template variables and replacements.
205
     */
206 10
    public function setTplVars(array $tplVars): void
207
    {
208 10
        if ($tplVars === []) {
209 2
            $this->tplVars = [];
210
211 2
            return;
212
        }
213
214 9
        $this->tplVars = array_merge($this->tplVars, $tplVars);
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 5
    private function doReplacements(string $contents): string
225
    {
226 5
        return str_replace(
227 5
            array_map(
228 5
                fn (int|string $find): string => \sprintf('%s%s%s', $this->leftDelimiter, $find, $this->rightDelimiter),
229 5
                array_keys($this->tplVars)
230 5
            ),
231 5
            array_values($this->tplVars),
232 5
            $contents
233 5
        );
234
    }
235
236
    /**
237
     * Generates a cache key for a template file.
238
     *
239
     * @param string $file The path to the template file.
240
     *
241
     * @return string The generated cache key.
242
     */
243 11
    private function generateCacheKey(string $file): string
244
    {
245 11
        return \sprintf('template_%s', dechex(crc32($file)));
246
    }
247
}
248