source: spip-zone/_plugins_/scssphp/trunk/lib/scssphp/src/Cache.php @ 115258

Last change on this file since 115258 was 115258, checked in by cedric@…, 2 years ago

Mise a jour de scssphp, qui inclue une petite optimisation du cache: sur var_mode=css on ne refresh un cache qu'une seule fois et on peut ensuite l'utiliser, ce qui permet de ne parser les fichiers modifies qu'une seule fois
Accelere sensiblement la mise a jour si on a plusieurs scss independante mais qui inclue des morceaux en commun (variables, mixins…)

A noter que le var_mode=css reste utile dans un seul scenario : si on duplique une feuille existante pour la surcharger dans le path, il faudra passer par là pour que le compilateur voit le nouveau fichier et le prenne en compte.
Autrement toute modification d'un fichier utilise dans la compilation provoquera la mise a jour de la css compilee avec un simple var_mode=calcul

File size: 6.2 KB
Line 
1<?php
2/**
3 * SCSSPHP
4 *
5 * @copyright 2012-2018 Leaf Corcoran
6 *
7 * @license http://opensource.org/licenses/MIT MIT
8 *
9 * @link http://leafo.github.io/scssphp
10 */
11
12namespace Leafo\ScssPhp;
13
14use Exception;
15
16/**
17 * The scss cache manager.
18 *
19 * In short:
20 *
21 * allow to put in cache/get from fache a generic result from a known operation on a generic dataset,
22 * taking in account options that affects the result
23 *
24 * The cache manager is agnostic about data format and only the operation is expected to be descripted by string
25 *
26 */
27
28/**
29 * SCSS cache
30 *
31 * @author Cedric Morin
32 */
33class Cache
34{
35
36    const CACHE_VERSION = 0;
37
38
39    // directory used for storing data
40    public static $cache_dir = false;
41
42    // prefix for the storing data
43    public static $prefix = 'scssphp_';
44
45    // force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit
46    public static $force_refresh = false;
47
48    // specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up
49    public static $gc_lifetime = 604800;
50
51
52    // array of already refreshed cache if $force_refresh==='once'
53    protected static $refreshed = [];
54
55
56    /**
57     * Constructor
58     */
59    public function __construct($options)
60    {
61        //check $cache_dir
62        if (isset($options['cache_dir'])) {
63            self::$cache_dir = $options['cache_dir'];
64        }
65
66        if (empty(self::$cache_dir)) {
67            throw new Exception('cache_dir not set');
68        }
69
70        if (isset($options['prefix'])) {
71            self::$prefix = $options['prefix'];
72        }
73
74        if (empty(self::$prefix)) {
75            throw new Exception('prefix not set');
76        }
77
78        if (isset($options['force_refresh'])) {
79            self::$force_refresh = $options['force_refresh'];
80        }
81
82        self::checkCacheDir();
83    }
84
85
86    /**
87     * Get the cached result of $operation on $what, which is known as dependant from the content of $options
88     *
89     * @param string $operation
90     *   parse, compile...
91     * @param $what
92     *  content key (filename to be treated for instance)
93     * @param array $options
94     *  any option that affect the operation result on the content
95     * @param int $last_modified
96     * @return mixed
97     * @throws Exception
98     */
99    public function getCache($operation, $what, $options = array(), $last_modified = null)
100    {
101
102        $fileCache = self::$cache_dir . self::cacheName($operation, $what, $options);
103
104        if ((! self::$force_refresh || (self::$force_refresh === 'once' && isset(self::$refreshed[$fileCache])))
105          and file_exists($fileCache)) {
106            $cache_time = filemtime($fileCache);
107            if ((is_null($last_modified) or $cache_time > $last_modified)
108              and $cache_time + self::$gc_lifetime > time()) {
109                $c = file_get_contents($fileCache);
110                $c = unserialize($c);
111                if (is_array($c) and isset($c['value'])) {
112                    return $c['value'];
113                }
114            }
115        }
116
117        return null;
118    }
119
120    /**
121     * Put in cache the result of $operation on $what, which is known as dependant from the content of $options
122     *
123     * @param string $operation
124     * @param $what
125     * @param $value
126     * @param array $options
127     */
128    public function setCache($operation, $what, $value, $options = array())
129    {
130        $fileCache = self::$cache_dir . self::cacheName($operation, $what, $options);
131
132        $c = array('value' => $value);
133        $c = serialize($c);
134        file_put_contents($fileCache, $c);
135
136        if (self::$force_refresh === 'once') {
137            self::$refreshed[$fileCache] = true;
138        }
139    }
140
141
142    /**
143     * get the cachename for the caching of $opetation on $what, which is known as dependant from the content of $options
144     * @param string $operation
145     * @param $what
146     * @param array $options
147     * @return string
148     */
149    private static function cacheName($operation, $what, $options = array())
150    {
151
152        $t = array(
153          'version' => self::CACHE_VERSION,
154          'operation' => $operation,
155          'what' => $what,
156          'options' => $options
157        );
158
159        $t = self::$prefix
160          . sha1(json_encode($t))
161          . ".$operation"
162          . ".scsscache";
163
164        return $t;
165    }
166
167
168    /**
169     * Check that the cache dir is existing and writeable
170     * @throws Exception
171     */
172    public static function checkCacheDir()
173    {
174
175        self::$cache_dir = str_replace('\\', '/', self::$cache_dir);
176        self::$cache_dir = rtrim(self::$cache_dir, '/') . '/';
177
178        if (! file_exists(self::$cache_dir)) {
179            if (! mkdir(self::$cache_dir)) {
180                throw new Exception('Cache directory couldn\'t be created: ' . self::$cache_dir);
181            }
182        } elseif (! is_dir(self::$cache_dir)) {
183            throw new Exception('Cache directory doesn\'t exist: ' . self::$cache_dir);
184        } elseif (! is_writable(self::$cache_dir)) {
185            throw new Exception('Cache directory isn\'t writable: ' . self::$cache_dir);
186        }
187    }
188
189    /**
190     * Delete unused cached files
191     *
192     */
193    public static function cleanCache()
194    {
195        static $clean = false;
196
197
198        if ($clean || empty(self::$cache_dir)) {
199            return;
200        }
201
202        $clean = true;
203
204        // only remove files with extensions created by SCSSPHP Cache
205        // css files removed based on the list files
206        $remove_types = array('scsscache' => 1);
207
208        $files = scandir(self::$cache_dir);
209        if (! $files) {
210            return;
211        }
212
213        $check_time = time() - self::$gc_lifetime;
214        foreach ($files as $file) {
215            // don't delete if the file wasn't created with SCSSPHP Cache
216            if (strpos($file, self::$prefix) !== 0) {
217                continue;
218            }
219
220            $parts = explode('.', $file);
221            $type = array_pop($parts);
222
223
224            if (! isset($remove_types[$type])) {
225                continue;
226            }
227
228            $full_path = self::$cache_dir . $file;
229            $mtime = filemtime($full_path);
230
231            // don't delete if it's a relatively new file
232            if ($mtime > $check_time) {
233                continue;
234            }
235
236            unlink($full_path);
237        }
238    }
239}
Note: See TracBrowser for help on using the repository browser.