LocalStorage::clear()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 15
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
/**
4
 * Platine Cache
5
 *
6
 * Platine Cache is the implementation of PSR 16 simple cache
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine Cache
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file LocalStorage.php
33
 *
34
 *  The Cache Driver using file system to manage the cache data
35
 *
36
 *  @package    Platine\Cache\Storage
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   https://www.platine-php.com
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Cache\Storage;
48
49
use DateInterval;
50
use Platine\Cache\Configuration;
51
use Platine\Cache\Exception\FilesystemStorageException;
52
use Platine\Filesystem\DirectoryInterface;
53
use Platine\Filesystem\FileInterface;
54
use Platine\Filesystem\Filesystem;
55
use Platine\Stdlib\Helper\Path;
56
use Platine\Stdlib\Helper\Str;
57
58
59
/**
60
 * @class LocalStorage
61
 * @package Platine\Cache\Storage
62
 */
63
class LocalStorage extends AbstractStorage
64
{
65
     /**
66
     * The directory to use to save cache files
67
     * @var DirectoryInterface
68
     */
69
    protected DirectoryInterface $directory;
70
71
    /**
72
     * The file system instance
73
     * @var Filesystem
74
     */
75
    protected Filesystem $filesystem;
76
77
    /**
78
     * Create new instance
79
     *
80
     * {@inheritdoc}
81
     */
82
    public function __construct(Filesystem $filesystem, ?Configuration $config = null)
83
    {
84
        parent::__construct($config);
85
        $this->filesystem = $filesystem;
86
87
        $filePath = Path::normalizePathDS($this->config->get('storages.file.path'), true);
88
        $directory = $filesystem->directory($filePath);
89
        if ($directory->exists() === false || $directory->isWritable() === false) {
90
            throw new FilesystemStorageException(sprintf(
91
                'Cannot use file cache handler, because the directory %s does '
92
                    . 'not exist or is not writable',
93
                $filePath
94
            ));
95
        }
96
97
        $this->directory = $directory;
98
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    public function get(string $key, mixed $default = null): mixed
104
    {
105
        $file = $this->getCacheFile($key);
106
107
        if (!$file->exists() || $file->getMtime() <= time()) {
108
            return $default;
109
        }
110
111
        $data = $file->read();
112
113
        /** @var bool|string */
114
        $value = @unserialize($data);
115
116
117
        if ($value === false) {
118
            //unserialize failed
119
120
            return $default;
121
        }
122
123
124
        return $value;
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function set(string $key, mixed $value, int|DateInterval|null $ttl = null): bool
131
    {
132
        if ($ttl === null) {
133
            $ttl = $this->config->get('ttl');
134
        } elseif ($ttl instanceof DateInterval) {
135
            $ttl = $this->convertDateIntervalToSeconds($ttl);
136
        }
137
138
139
        /** @var int */
140
        $expireAt = time() + $ttl;
141
        $file = $this->getCacheFile($key);
142
        $file->write(serialize($value));
143
        $file->touch($expireAt);
144
145
        return true;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function delete(string $key): bool
152
    {
153
        $file = $this->getCacheFile($key);
154
155
        if ($file->exists()) {
156
            $file->delete();
157
        }
158
159
        return true;
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function clear(): bool
166
    {
167
        $files = $this->directory->read(DirectoryInterface::FILE);
168
        foreach ($files as /** @var FileInterface $file */ $file) {
169
            if (
170
                Str::startsWith(
171
                    $this->config->get('storages.file.prefix'),
172
                    $file->getName()
173
                )
174
            ) {
175
                $file->delete();
176
            }
177
        }
178
179
        return true;
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185
    public function has(string $key): bool
186
    {
187
        return $this->get($key, $this) !== $this;
188
    }
189
190
    /**
191
     * Return the file cache
192
     * @param string $key
193
     * @return FileInterface
194
     */
195
    protected function getCacheFile(string $key): FileInterface
196
    {
197
        $filename = $this->getFileName($key);
198
        $file = $this->filesystem->file(
199
            $this->directory->getPath() . DIRECTORY_SEPARATOR . $filename
200
        );
201
202
        return $file;
203
    }
204
205
    /**
206
     * Get cache file name for given key
207
     * @param  string $key
208
     * @return string      the filename
209
     */
210
    private function getFileName(string $key): string
211
    {
212
        $cleanKey = preg_replace('/[^A-Za-z0-9\.]+/', '_', $key);
213
        return sprintf(
214
            '%s%s.cache',
215
            $this->config->get('storages.file.prefix'),
216
            $cleanKey
217
        );
218
    }
219
}
220