Completed
Push — 2.0 ( aed067...b26523 )
by Marco
04:31
created

Database::addCacheObject()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2.0054

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
ccs 8
cts 9
cp 0.8889
rs 9.4285
cc 2
eloc 9
nc 2
nop 7
crap 2.0054
1
<?php namespace Comodojo\Cache\Providers;
2
3
use \Comodojo\Cache\Providers\AbstractProvider;
4
use \Comodojo\Cache\Components\InstanceTrait;
5
use \Comodojo\Database\EnhancedDatabase;
6
use \Psr\Log\LoggerInterface;
7
use \Comodojo\Exception\DatabaseException;
8
use \Comodojo\Exception\CacheException;
9
use \Exception;
10
11
/**
12
 * Database cache class
13
 *
14
 * @package     Comodojo Spare Parts
15
 * @author      Marco Giovinazzi <[email protected]>
16
 * @license     MIT
17
 *
18
 * LICENSE:
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
 * THE SOFTWARE.
27
 */
28
29
class Database extends AbstractProvider {
30
31
    use InstanceTrait;
32
33
    /**
34
     * Database table
35
     *
36
     * @var string
37
     */
38
    private $table;
39
40
    /**
41
     * Prefix for table
42
     *
43
     * @var string
44
     */
45
    private $table_prefix;
46
47
    /**
48
     * Class constructor
49
     *
50
     * @param   EnhancedDatabase $dbh
51
     * @param   string           $table          Name of table
52
     * @param   string           $table_prefix   Prefix for table
53
     * @param   LoggerInterface  $logger         Logger instance
54
     *
55
     * @throws \Comodojo\Exception\CacheException
56
     */
57 16
    public function __construct(EnhancedDatabase $dbh, $table, $table_prefix = null, LoggerInterface $logger = null) {
58
59 16
        if ( empty($table) ) throw new CacheException("Database table cannot be undefined");
60
61 16
        $this->table = $table;
62
63 16
        $this->table_prefix = empty($table_prefix) ? null : $table_prefix;
64
65 16
        parent::__construct($logger);
66
67 16
        $this->setInstance($dbh);
68
69 16
        $this->table = $table;
70
71 16
        $this->instance->autoClean();
72
73 16
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78 4
    public function set($name, $data, $ttl = null) {
79
80 4
        if ( empty($name) ) throw new CacheException("Name of object cannot be empty");
81
82 4
        if ( is_null($data) ) throw new CacheException("Object content cannot be null");
83
84 4
        if ( !$this->isEnabled() ) return false;
85
86 4
        $this->resetErrorState();
87
88
        try {
89
90 4
            $namespace = $this->getNamespace();
91
92 4
            $this->setTtl($ttl);
93
94 4
            $expire = $this->getTime() + $this->ttl;
95
96 4
            $is_in_cache = self::getCacheObject($this->instance, $this->table, $this->table_prefix, $name, $namespace);
97
98 4
            if ( $is_in_cache->getLength() != 0 ) {
99
100
                self::updateCacheObject($this->instance, $this->table, $this->table_prefix, $name, serialize($data), $namespace, $expire);
101
102
            } else {
103
104 4
                self::addCacheObject($this->instance, $this->table, $this->table_prefix, $name, serialize($data), $namespace, $expire);
105
106
            }
107
108 4
        } catch (CacheException $ce) {
109
110
            throw $ce;
111
112
        } catch (DatabaseException $de) {
113
114
            $this->logger->error("Error writing cache object (Database), exiting gracefully", array(
115
                "ERRORNO"   =>  $de->getCode(),
116
                "ERROR"     =>  $de->getMessage()
117
            ));
118
119
            $this->setErrorState();
120
121
            return false;
122
123
        }
124
125 4
        return true;
126
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 5
    public function get($name) {
133
134 5
        if ( empty($name) ) throw new CacheException("Name of object cannot be empty");
135
136 5
        if ( !$this->isEnabled() ) return null;
137
138 5
        $this->resetErrorState();
139
140
        try {
141
142 5
            $namespace = $this->getNamespace();
143
144 5
            $is_in_cache = self::getCacheObject($this->instance, $this->table, $this->table_prefix, $name, $namespace, $this->getTime());
145
146 5
            if ( $is_in_cache->getLength() != 0 ) {
147
148 3
                $value = $is_in_cache->getData();
149
150 3
                $return = unserialize($value[0]['data']);
151
152 3
            } else {
153
154 3
                $return = null;
155
156
            }
157
158 5
        } catch (CacheException $ce) {
159
160
            throw $ce;
161
162
        } catch (DatabaseException $de) {
163
164
            $this->logger->error("Error reading cache object (Database), exiting gracefully", array(
165
                "ERRORNO"   =>  $de->getCode(),
166
                "ERROR"     =>  $de->getMessage()
167
            ));
168
169
            $this->setErrorState();
170
171
            $return = null;
172
173
        }
174
175 5
        return $return;
176
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182 1
    public function delete($name = null) {
183
184 1
        if ( !$this->isEnabled() ) return false;
185
186 1
        $this->resetErrorState();
187
188
        try {
189
190 1
            $this->instance->tablePrefix($this->table_prefix)
191 1
                ->table($this->table)
192 1
                ->where("namespace", "=", $this->getNamespace());
193
194 1
            if ( !empty($name) ) $this->instance->andWhere("name", "=", $name);
195
196 1
            $this->instance->delete();
197
198 1
        } catch (DatabaseException $de) {
199
200
            $this->logger->error("Failed to delete cache (Database), exiting gracefully", array(
201
                "ERRORNO"   =>  $de->getCode(),
202
                "ERROR"     =>  $de->getMessage()
203
            ));
204
205
            $this->setErrorState();
206
207
            return false;
208
209
        }
210
211 1
        return true;
212
213
    }
214
215
    /**
216
     * {@inheritdoc}
217
     */
218 1
    public function flush() {
219
220 1
        if ( !$this->isEnabled() ) return false;
221
222 1
        $this->resetErrorState();
223
224
        try {
225
226 1
            $this->instance->tablePrefix($this->table_prefix)->table($this->table)->truncate();
227
228 1
        } catch (DatabaseException $de) {
229
230
            $this->logger->error("Failed to flush cache (Database), exiting gracefully", array(
231
                "ERRORNO"   =>  $de->getCode(),
232
                "ERROR"     =>  $de->getMessage()
233
            ));
234
235
            $this->setErrorState();
236
237
            return false;
238
239
        }
240
241 1
        return true;
242
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248 1
    public function status() {
249
250 1
        $this->resetErrorState();
251
252
        try {
253
254 1
            $this->instance->tablePrefix($this->table_prefix)
255 1
                ->table($this->table)
256 1
                ->keys('COUNT::name=>count');
257
258 1
            $count = $this->instance->get();
259
260 1
            $objects = $count->getData();
261
262 1
        } catch (DatabaseException $de) {
263
264
            $this->logger->error("Failed to get cache status (Database), exiting gracefully", array(
265
                "ERRORNO"   =>  $de->getCode(),
266
                "ERROR"     =>  $de->getMessage()
267
            ));
268
269
            $this->setErrorState();
270
271
            return array(
272
                "provider"  => "database",
273
                "enabled"   => false,
274
                "objects"   => 0,
275
                "options"   => array()
276
            );
277
278
        }
279
280
        return array(
281 1
            "provider"  => "database",
282 1
            "enabled"   => $this->isEnabled(),
283 1
            "objects"   => intval($objects[0]['count']),
284
            "options"   => array(
285 1
                'host'  =>  $this->instance->getHost(),
286 1
                'port'  =>  $this->instance->getPort(),
287 1
                'name'  =>  $this->instance->getName(),
288 1
                'user'  =>  $this->instance->getUser(),
289 1
                'model' =>  $this->instance->getModel()
290 1
            )
291 1
        );
292
293
    }
294
295
    /**
296
     * Get object from database
297
     *
298
     * @return  \Comodojo\Database\QueryResult
299
     * @throws  \Comodojo\Exception\DatabaseException
300
     */
301 6
    private static function getCacheObject($dbh, $table, $table_prefix, $name, $namespace, $expire = null) {
302
303
        try {
304
305 6
            $dbh->tablePrefix($table_prefix)
306 6
                ->table($table)
307 6
                ->keys('data')
308 6
                ->where("name", "=", $name)
309 6
                ->andWhere("namespace", "=", $namespace); ;
310
311 6
            if ( is_int($expire) ) {
312
313 5
                $dbh->andWhere("expire", ">", $expire);
314
315 5
            }
316
317 6
            $match = $dbh->get();
318
319
320 6
        } catch (DatabaseException $de) {
321
322
            throw $de;
323
324
        }
325
326 6
        return $match;
327
328
    }
329
330
    /**
331
     * Update a cache element
332
     *
333
     * @throws  \Comodojo\Exception\DatabaseException
334
     */
335
    private static function updateCacheObject($dbh, $table, $table_prefix, $name, $data, $scope, $expire) {
336
337
        try {
338
339
            $dbh->tablePrefix($table_prefix)
340
                ->table($table)
341
                ->keys(array('data', 'expire'))
342
                ->values(array($data, $expire))
343
                ->where("name", "=", $name)
344
                ->andWhere("namespace", "=", $scope)
345
                ->update();
346
347
        } catch (DatabaseException $de) {
348
349
            throw $de;
350
351
        }
352
353
    }
354
355
    /**
356
     * Add a cache element
357
     *
358
     * @throws  \Comodojo\Exception\DatabaseException
359
     */
360 4
    private static function addCacheObject($dbh, $table, $table_prefix, $name, $data, $scope, $expire) {
361
362
        try {
363
364 4
            $dbh->tablePrefix($table_prefix)
365 4
                ->table($table)
366 4
                ->keys(array('name', 'data', 'namespace', 'expire'))
367 4
                ->values(array($name, $data, $scope, $expire))
368 4
                ->store();
369
370 4
        } catch (DatabaseException $de) {
371
372
            throw $de;
373
374
        }
375
376 4
    }
377
378
    /**
379
     * Generate an EnhancedDatabase object
380
     *
381
     * @return \Comodojo\Database\EnhancedDatabase
382
     * @throws \Comodojo\Exception\CacheException
383
     */
384 16
    public static function getDatabase($model, $host, $port, $database, $user, $password = null) {
385
386
        try {
387
388 16
            $dbh = new \Comodojo\Database\EnhancedDatabase(
389 16
                $model,
390 16
                $host,
391 16
                $port,
392 16
                $database,
393 16
                $user,
394
                $password
395 16
            );
396
397 16
        } catch (Exception $e) {
398
399
            throw new CacheException("Cannot init database: (".$e->getCode().") ".$e->getMessage());
400
401
        }
402
403 16
        return $dbh;
404
405
    }
406
407
}
408