Passed
Push — master ( 5a87d9...5af04f )
by Mihail
03:04
created

FileClient::set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 5
Bugs 0 Features 1
Metric Value
cc 2
eloc 5
c 5
b 0
f 1
nc 2
nop 3
dl 0
loc 12
ccs 6
cts 6
cp 1
crap 2
rs 10
1
<?php
2
3
/*
4
 * This file is part of the Koded package.
5
 *
6
 * (c) Mihail Binev <[email protected]>
7
 *
8
 * Please view the LICENSE distributed with this source code
9
 * for the full copyright and license information.
10
 *
11
 */
12
13
namespace Koded\Caching\Client;
14
15
use Koded\Caching\{Cache, CacheException};
16
use Psr\Log\LoggerInterface;
17
use function Koded\Caching\verify_key;
18
use function Koded\Stdlib\rmdir;
19
20
/**
21
 * @property FileClient client
22
 *
23
 */
24
final class FileClient implements Cache
25
{
26
    use ClientTrait, MultiplesTrait;
27
28
    /** @var string */
29
    private $dir = '';
30
31
    /** @var LoggerInterface */
32
    private $logger;
33
34
35 201
    public function __construct(LoggerInterface $logger, string $dir, int $ttl = null)
36
    {
37 201
        $this->ttl = $ttl;
38 201
        $this->logger = $logger;
39 201
        $this->setDirectory($dir);
40 200
    }
41
42
43 66
    public function get($key, $default = null)
44
    {
45
        try {
46 66
            if ($this->has($key, $filename, $cache)) {
47 41
                return unserialize($cache['value']);
48
            }
49
50 14
            return $default;
51
52
        } finally {
53 66
            unset($filename, $cache);
54
        }
55
    }
56
57
58 78
    public function set($key, $value, $ttl = null)
59
    {
60 78
        verify_key($key);
61
62 61
        if (1 > $expiration = $this->timestampWithGlobalTtl($ttl, Cache::DATE_FAR_FAR_AWAY)) {
63
            // The item is considered expired and must be deleted
64 2
            return $this->delete($key);
65
        }
66
67 50
        $filename = $this->filename($key, true);
68
69 50
        return (bool)file_put_contents($filename, $this->data($key, $value, $expiration));
70
    }
71
72
73 27
    public function delete($key)
74
    {
75 27
        if (false === $this->has($key, $filename)) {
76 8
            return true;
77
        }
78
79 7
        return unlink($filename);
80
    }
81
82
83 197
    public function clear()
84
    {
85 197
        return rmdir($this->dir);
86
    }
87
88
89 105
    public function has($key, &$filename = '', &$cache = null)
90
    {
91 105
        verify_key($key);
92 54
        $filename = $this->filename($key, false);
93
94 54
        if (false === is_file($filename)) {
95 17
            return false;
96
        }
97
98
        /** @noinspection PhpIncludeInspection */
99 49
        $cache = include $filename;
100
101 49
        if ($cache['timestamp'] <= time()) {
102 3
            unlink($filename);
103
104 3
            return false;
105
        }
106
107 49
        return true;
108
    }
109
110
    /**
111
     * Normalizes the cache filename.
112
     *
113
     * @param string $key    The cache key
114
     * @param bool   $create Flag to create the file or not
115
     *
116
     * @return string
117
     */
118 54
    private function filename(string $key, bool $create): string
119
    {
120 54
        $filename = sha1($key);
121 54
        $dir = $this->dir . $filename[0];
122
123 54
        if ($create && false === is_dir($dir)) {
124 50
            mkdir($dir, 0775, true)
125
            || $this->logger->error('Failed to create cache directory in: {dir}', ['dir' => $dir]);
126
        }
127
128 54
        $filename = $dir . '/' . substr($filename, 1) . '.php';
129
130 54
        if ($create && false === is_file($filename)) {
131 50
            touch($filename);
132 50
            chmod($filename, 0666);
133
        }
134
135 54
        return $filename;
136
    }
137
138
    /**
139
     * Prepares the cache directory.
140
     *
141
     * @param string $directory
142
     *
143
     * @throws CacheException
144
     */
145 201
    private function setDirectory(string $directory): void
146
    {
147
        // Overrule shell misconfiguration or the web server
148 201
        umask(umask() | 0002);
149 201
        $dir = $directory ?: sys_get_temp_dir() . '/_cache';
150 201
        $dir = rtrim($dir, '/') . '/';
151
152 201
        if (false === is_dir($dir) && false === mkdir($dir, 0775, true)) {
153 1
            $e = CacheException::forCreatingDirectory($dir);
154 1
            $this->logger->error($e->getMessage());
155 1
            throw $e;
156
        }
157
158 200
        $this->dir = $dir;
159 200
    }
160
161
    /**
162
     * Creates a cache content.
163
     *
164
     * @param string   $key   The cache key
165
     * @param mixed    $value The value to be cached
166
     * @param int|null $ttl   Time to live
167
     *
168
     * @return string
169
     */
170 50
    private function data(string $key, $value, int $ttl): string
171
    {
172 50
        return '<?php return ' . var_export([
173 50
                'timestamp' => $ttl,
174 50
                'key' => $key,
175 50
                'value' => serialize($value),
176 50
            ], true) . ';';
177
    }
178
}
179