Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core\local\guzzle;
18
 
19
/**
20
 * Class to handle and generates CacheItemPoolInterface objects.
21
 *
22
 * This class will handle save, delete, cleanup etc. for the cache item.
23
 * For individual cache objects, this class will rely on {@cache_item} class.
24
 *
25
 * @package    core
26
 * @copyright  2022 Safat Shahin <safat.shahin@moodle.com>
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 */
29
class cache_handler {
30
 
31
    /**
32
     * This array will have the kay and value for that key.
33
     * Mainly individual data will be handled by {@cache_item} class for each array element.
34
     *
35
     * @var array $items cached items or the items currently in use by the cache pool.
36
     */
37
    private array $items;
38
 
39
    /**
40
     * This array will have the cache items which might need to persisted later.
41
     * It will not save the items in the cache pool using cache_item class until the commit is done for these elements.
42
     *
43
     * @var array $deferreditems cache items to be persisted later.
44
     */
45
    private array $deferreditems;
46
 
47
    /** @var string module name. */
48
    private string $module;
49
 
50
    /** @var string the directory for cache. */
51
    private string $dir;
52
 
53
    /**
54
     * Constructor for class cache_handler.
55
     * This class will accept the module which will determine the location of cached files.
56
     *
57
     * @param string $module module string for cache directory.
58
     */
59
    public function __construct(string $module = 'repository') {
60
        global $CFG;
61
        $this->module = $module;
62
 
63
        // Set the directory for cache.
64
        $this->dir = $CFG->cachedir . '/' . $module . '/';
65
        if (!file_exists($this->dir) && !mkdir($concurrentdirectory = $this->dir, $CFG->directorypermissions, true) &&
66
            !is_dir($concurrentdirectory)) {
67
            throw new \moodle_exception(sprintf('Directory "%s" was not created', $concurrentdirectory));
68
        }
69
 
70
    }
71
 
72
    /**
73
     * Returns a Cache Item representing the specified key.
74
     *
75
     * This method must always return a CacheItemInterface object, even in case of
76
     * a cache miss. It MUST NOT return null.
77
     *
78
     * @param string $key The key for which to return the corresponding Cache Item..
79
     * @param int|null $ttl Number of seconds for the cache item to live.
80
     * @return cache_item The corresponding Cache Item.
81
     */
82
    public function get_item(string$key, ?int $ttl = null): cache_item {
83
        return new cache_item($key, $this->module, $ttl);
84
    }
85
 
86
    /**
87
     * Returns a traversable set of cache items.
88
     *
89
     * @param string[] $keys An indexed array of keys of items to retrieve.
90
     * @return iterable
91
     *   An iterable collection of Cache Items keyed by the cache keys of
92
     *   each item. A Cache item will be returned for each key, even if that
93
     *   key is not found. However, if no keys are specified then an empty
94
     *   traversable MUST be returned instead.
95
     */
96
    public function get_items(array $keys = []): iterable {
97
        $items = [];
98
 
99
        foreach ($keys as $key) {
100
            $items[$key] = $this->has_item($key) ? clone $this->items[$key] : $this->get_item($key);
101
        }
102
 
103
        return $items;
104
    }
105
 
106
    /**
107
     * Confirms if the cache contains specified cache item.
108
     *
109
     * Note: This method MAY avoid retrieving the cached value for performance reasons.
110
     * This could result in a race condition with CacheItemInterface::get(). To avoid
111
     * such situation use CacheItemInterface::isHit() instead.
112
     *
113
     * @param string $key The key for which to check existence.
114
     * @return bool True if item exists in the cache, false otherwise.
115
     */
116
    public function has_item($key): bool {
117
        $this->assert_key_is_valid($key);
118
 
119
        return isset($this->items[$key]) && $this->items[$key]->isHit();
120
    }
121
 
122
    /**
123
     * Deletes all items in the pool.
124
     *
125
     * @return bool True if the pool was successfully cleared. False if there was an error.
126
     */
127
    public function clear(): bool {
128
        global $USER;
129
 
130
        if (isset($this->items)) {
131
            foreach ($this->items as $key => $item) {
132
                // Delete cache file.
133
                if ($dir = opendir($this->dir)) {
134
                    $filename = 'u' . $USER->id . '_' . md5(serialize($key));
135
                    $filename = $dir . $filename;
136
                    if (file_exists($filename) && $this->items[$key]->isHit()) {
137
                        @unlink($filename);
138
                    }
139
                    closedir($dir);
140
                }
141
            }
142
        }
143
 
144
        $this->items = [];
145
        $this->deferreditems = [];
146
 
147
        return true;
148
    }
149
 
150
    /**
151
     * Refreshes all items in the pool.
152
     *
153
     * @param int $ttl Seconds to live.
154
     * @return void
155
     */
156
    public function refresh(int $ttl): void {
157
        if ($dir = opendir($this->dir)) {
158
            while (false !== ($file = readdir($dir))) {
159
                if (!is_dir($file) && $file !== '.' && $file !== '..') {
160
                    $lasttime = @filemtime($this->dir . $file);
161
                    if (time() - $lasttime > $ttl) {
162
                        mtrace($this->dir . $file);
163
                        @unlink($this->dir . $file);
164
                    }
165
                }
166
            }
167
            closedir($dir);
168
        }
169
    }
170
 
171
    /**
172
     * Removes the item from the pool.
173
     *
174
     * @param string $key The key to delete.
175
     * @return bool True if the item was successfully removed. False if there was an error.
176
     */
177
    public function delete_item(string $key): bool {
178
        return $this->delete_items([$key]);
179
    }
180
 
181
    /**
182
     * Removes multiple items from the pool.
183
     *
184
     * @param string[] $keys An array of keys that should be removed from the pool.
185
     * @return bool  True if the items were successfully removed. False if there was an error.
186
     */
187
    public function delete_items(array $keys): bool {
188
        global $USER;
189
        array_walk($keys, [$this, 'assert_key_is_valid']);
190
 
191
        foreach ($keys as $key) {
192
            // Delete cache file.
193
            if ($dir = opendir($this->dir)) {
194
                $filename = 'u' . $USER->id . '_' . md5(serialize($key));
195
                $filename = $dir . $filename;
196
                if (file_exists($filename)) {
197
                    @unlink($filename);
198
                }
199
            }
200
 
201
            unset($this->items[$key]);
202
        }
203
 
204
        return true;
205
    }
206
 
207
    /**
208
     * Persists a cache item immediately.
209
     *
210
     * @param cache_item $item The cache item to save.
211
     * @return bool True if the item was successfully persisted. False if there was an error.
212
     */
213
    public function save(cache_item $item): bool {
214
        global $CFG, $USER;
215
        $key = $item->get_key();
216
 
217
        // File and directory setup.
218
        $filename = 'u' . $USER->id . '_' . md5(serialize($key));
219
        $fp = fopen($this->dir . $filename, 'wb');
220
 
221
        // Store the item.
222
        fwrite($fp, serialize($item->get()));
223
        fclose($fp);
224
        @chmod($this->dir . $filename, $CFG->filepermissions);
225
 
226
        $this->items[$key] = $item;
227
 
228
        return true;
229
    }
230
 
231
    /**
232
     * Sets a cache item to be persisted later.
233
     *
234
     * @param cache_item $item The cache item to save.
235
     * @return bool False if the item could not be queued or if a commit was attempted and failed. True otherwise.
236
     */
237
    public function save_deferred(cache_item $item): bool {
238
        $this->deferreditems[$item->get_key()] = $item;
239
 
240
        return true;
241
    }
242
 
243
    /**
244
     * Persists any deferred cache items.
245
     *
246
     * @return bool True if all not-yet-saved items were successfully saved or there were none. False otherwise.
247
     */
248
    public function commit(): bool {
249
        foreach ($this->deferreditems as $item) {
250
            $this->save($item);
251
        }
252
 
253
        $this->deferreditems = [];
254
 
255
        return true;
256
    }
257
 
258
    /**
259
     * Asserts that the given key is valid.
260
     * Some simple validation to make sure the passed key is a valid one.
261
     *
262
     * @param string $key The key to validate.
263
     */
264
    private function assert_key_is_valid(string $key): void {
265
        $invalidcharacters = '{}()/\\\\@:';
266
 
267
        if (!is_string($key) || preg_match("#[$invalidcharacters]#", $key)) {
268
            throw new \moodle_exception('Invalid cache key');
269
        }
270
    }
271
 
272
}