Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
Cache
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
6 / 6
14
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
 getDir
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 key
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 path
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
 put
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <nick@popphp.org>
8 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\View\Template\Stream;
16
17/**
18 * View stream template compiled-cache class
19 *
20 * @category   Pop
21 * @package    Pop\View
22 * @author     Nick Sagona, III <nick@popphp.org>
23 * @copyright  Copyright (c) 2009-2026 Nick Sagona, III
24 * @license    https://www.popphp.org/license     New BSD License
25 * @version    5.0.0
26 */
27class Cache
28{
29
30    /**
31     * Cache directory
32     * @var string
33     */
34    protected string $dir;
35
36    /**
37     * Constructor
38     *
39     * @param  string $dir
40     */
41    public function __construct(string $dir)
42    {
43        $this->dir = rtrim($dir, '/\\');
44    }
45
46    /**
47     * Get the cache directory
48     *
49     * @return string
50     */
51    public function getDir(): string
52    {
53        return $this->dir;
54    }
55
56    /**
57     * Derive a stable cache key from resolved template content
58     *
59     * @param  string $resolvedTemplate
60     * @return string
61     */
62    public static function key(string $resolvedTemplate): string
63    {
64        return hash('sha256', $resolvedTemplate);
65    }
66
67    /**
68     * Get the absolute path to the cache file for a given key
69     *
70     * @param  string $key
71     * @return string
72     */
73    public function path(string $key): string
74    {
75        return $this->dir . DIRECTORY_SEPARATOR . $key . '.php';
76    }
77
78    /**
79     * Get cached compiled source for a key, or null on miss/stale
80     *
81     * @param  string $key
82     * @param  int    $newestSourceMtime
83     * @return ?string
84     */
85    public function get(string $key, int $newestSourceMtime): ?string
86    {
87        $file = $this->path($key);
88
89        if (!file_exists($file)) {
90            return null;
91        }
92
93        if (($newestSourceMtime > 0) && (filemtime($file) < $newestSourceMtime)) {
94            return null;
95        }
96
97        $content = file_get_contents($file);
98
99        return ($content === false) ? null : $content;
100    }
101
102    /**
103     * Write compiled source to the cache, atomically
104     *
105     * @param  string $key
106     * @param  string $source
107     * @throws Exception
108     * @return void
109     */
110    public function put(string $key, string $source): void
111    {
112        if (!is_dir($this->dir) || !is_writable($this->dir)) {
113            throw new Exception("Error: The cache directory '" . $this->dir . "' does not exist or is not writable.");
114        }
115
116        $file = $this->path($key);
117        $tmp  = $file . '.' . uniqid('', true) . '.tmp';
118
119        if (@file_put_contents($tmp, $source) === false) {
120            throw new Exception("Error: Failed to write compiled template to '" . $tmp . "'.");
121        }
122
123        if (!@rename($tmp, $file)) {
124            throw new Exception("Error: Failed to move compiled template into place at '" . $file . "'.");
125        }
126    }
127
128}