Passed
Push — main ( e82f34...7054df )
by Sílvio
05:01 queued 02:07
created

CacheDatabaseRepository::retrieve()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 10
c 2
b 0
f 0
nc 2
nop 2
dl 0
loc 16
rs 9.9332
1
<?php
2
3
namespace Silviooosilva\CacheerPhp\Repositories;
4
5
use PDO;
6
use Silviooosilva\CacheerPhp\Core\Connect;
7
8
/**
9
 * Class CacheDatabaseRepository
10
 * @author Sílvio Silva <https://github.com/silviooosilva>
11
 * @package Silviooosilva\CacheerPhp
12
 */
13
class CacheDatabaseRepository
14
{
15
16
    /** @var PDO */
17
    private $connection = null;
18
19
    public function __construct()
20
    {
21
        $this->connection = Connect::getInstance();
22
    }
23
24
25
    /**
26
     * @param string $cacheKey
27
     * @param mixed  $cacheData
28
     * @param string $namespace
29
     * @param string|int $ttl
30
     * @return bool
31
     */
32
    public function store(string $cacheKey, mixed $cacheData, string $namespace, string|int $ttl = 3600)
33
    {
34
        if (!empty($this->retrieve($cacheKey, $namespace))) {
35
            return $this->update($cacheKey, $cacheData, $namespace);
36
        }
37
38
        $expirationTime = date('Y-m-d H:i:s', time() + $ttl);
39
        $createdAt = date('Y-m-d H:i:s');
40
41
        $stmt = $this->connection->prepare(
42
            "INSERT INTO cacheer_table (cacheKey, cacheData, cacheNamespace, expirationTime, created_at) 
43
            VALUES (:cacheKey, :cacheData, :namespace, :expirationTime, :createdAt)"
44
        );
45
        $stmt->bindValue(':cacheKey', $cacheKey);
46
        $stmt->bindValue(':cacheData', $this->serialize($cacheData));
47
        $stmt->bindValue(':namespace', $namespace);
48
        $stmt->bindValue(':expirationTime', $expirationTime);
49
        $stmt->bindValue(':createdAt', $createdAt);
50
51
        return $stmt->execute() && $stmt->rowCount() > 0;
52
    }
53
54
    /**
55
    * @param string $cacheKey
56
    * @param string $namespace
57
    * @return mixed
58
    */
59
    public function retrieve(string $cacheKey, string $namespace = '')
60
    {
61
        $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
62
        $nowFunction = $this->getCurrentDateTime($driver);
63
64
        $stmt = $this->connection->prepare(
65
            "SELECT cacheData FROM cacheer_table 
66
            WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > $nowFunction
67
            LIMIT 1"
68
        );
69
        $stmt->bindValue(':cacheKey', $cacheKey);
70
        $stmt->bindValue(':namespace', $namespace);
71
        $stmt->execute();
72
73
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
74
        return (!empty($data)) ? $this->serialize($data['cacheData'], false) : null;
75
    }
76
77
    /**
78
     * @return string
79
     */
80
    private function getUpdateQueryWithDriver()
81
    {
82
        $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
83
        if ($driver === 'mysql' || $driver === 'mariadb') {
84
            return "UPDATE cacheer_table SET cacheData = :cacheData, cacheNamespace = :namespace WHERE cacheKey = :cacheKey LIMIT 1";
85
        }
86
        return "UPDATE cacheer_table SET cacheData = :cacheData, cacheNamespace = :namespace WHERE cacheKey = :cacheKey";
87
    }
88
89
    /**
90
     * @return string
91
     */
92
    private function getDeleteQueryWithDriver()
93
    {
94
        $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
95
        if ($driver === 'mysql' || $driver === 'mariadb') {
96
            return "DELETE FROM cacheer_table WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace LIMIT 1";
97
        }
98
        return "DELETE FROM cacheer_table WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace";
99
    }
100
101
    /**
102
     * @param string $cacheKey
103
     * @param mixed  $cacheData
104
     * @param string $namespace
105
     * @return bool
106
     */
107
    public function update(string $cacheKey, mixed $cacheData, string $namespace = '')
108
    {
109
        $query = $this->getUpdateQueryWithDriver();
110
        $stmt = $this->connection->prepare($query);
111
        $stmt->bindValue(':cacheData', $this->serialize($cacheData));
112
        $stmt->bindValue(':namespace', $namespace);
113
        $stmt->bindValue(':cacheKey', $cacheKey);
114
        $stmt->execute();
115
116
        return $stmt->rowCount() > 0;
117
    }
118
119
    /**
120
     * @param string $cacheKey
121
     * @param string $namespace
122
     * @return bool
123
     */
124
    public function clear(string $cacheKey, string $namespace = '')
125
    {
126
        $query = $this->getDeleteQueryWithDriver();
127
        $stmt = $this->connection->prepare($query);
128
        $stmt->bindValue(':cacheKey', $cacheKey);
129
        $stmt->bindValue(':namespace', $namespace);
130
        $stmt->execute();
131
132
        return $stmt->rowCount() > 0;
133
    }
134
135
    /**
136
     * @return string
137
     */
138
    private function getRenewExpirationQueryWithDriver(): string
139
    {
140
        $driver = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
141
        if ($driver === 'sqlite') {
142
            return "UPDATE cacheer_table
143
                    SET expirationTime = DATETIME(expirationTime, '+' || :ttl || ' seconds')
144
                    WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > :currentTime";
145
        }
146
        return "UPDATE cacheer_table
147
                SET expirationTime = DATE_ADD(expirationTime, INTERVAL :ttl SECOND)
148
                WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > :currentTime";
149
    }
150
151
    /**
152
     * @param string $cacheKey
153
     * @param string $namespace
154
     * @param string $currentTime
155
     * @return bool
156
     */
157
    private function hasValidCache(string $cacheKey, string $namespace, string $currentTime): bool
158
    {
159
        $stmt = $this->connection->prepare(
160
            "SELECT 1 FROM cacheer_table 
161
            WHERE cacheKey = :cacheKey AND cacheNamespace = :namespace AND expirationTime > :currentTime
162
            LIMIT 1"
163
        );
164
        $stmt->bindValue(':cacheKey', $cacheKey);
165
        $stmt->bindValue(':namespace', $namespace);
166
        $stmt->bindValue(':currentTime', $currentTime);
167
        $stmt->execute();
168
        return $stmt->fetchColumn() !== false;
169
    }
170
171
    /**
172
    * @param string $cacheKey
173
    * @param string|int $ttl
174
    * @param string $namespace
175
    * @return bool
176
    */
177
    public function renew(string $cacheKey, string|int $ttl, string $namespace = '')
178
    {
179
        $currentTime = date('Y-m-d H:i:s');
180
        if (!$this->hasValidCache($cacheKey, $namespace, $currentTime)) {
181
            return false;
182
        }
183
184
        $query = $this->getRenewExpirationQueryWithDriver();
185
        $stmt = $this->connection->prepare($query);
186
        $stmt->bindValue(':ttl', (int) $ttl, PDO::PARAM_INT);
187
        $stmt->bindValue(':cacheKey', $cacheKey);
188
        $stmt->bindValue(':namespace', $namespace);
189
        $stmt->bindValue(':currentTime', $currentTime);
190
        $stmt->execute();
191
192
        return $stmt->rowCount() > 0;
193
    }
194
195
    /**
196
     * @return bool
197
     */
198
    public function flush()
199
    {
200
        return $this->connection->exec("DELETE FROM cacheer_table") !== false;
201
    }
202
203
    /**
204
     * @param mixed $data
205
     * @return string
206
     */
207
    private function serialize(mixed $data, bool $serialize = true)
208
    {
209
        return $serialize ? serialize($data) : unserialize($data);
210
    }
211
212
    /**
213
    * @param string $driver
214
    * @return string
215
    */
216
    private function getCurrentDateTime(string $driver)
217
    {
218
        return ($driver === 'sqlite') ? "DATETIME('now', 'localtime')" : "NOW()";
219
    }
220
}
221