Completed
Push — master ( d16df5...ee3a8e )
by Matthias
03:12
created

PostgreSQL::set()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 30
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 14
nc 3
nop 3
1
<?php
2
3
namespace MatthiasMullie\Scrapbook\Adapters;
4
5
/**
6
 * PostgreSQL adapter. Basically just a wrapper over \PDO, but in an
7
 * exchangeable (KeyValueStore) interface.
8
 *
9
 * @author Matthias Mullie <[email protected]>
10
 * @copyright Copyright (c) 2014, Matthias Mullie. All rights reserved
11
 * @license LICENSE MIT
12
 */
13
class PostgreSQL extends SQL
14
{
15
    /**
16
     * @var bool
17
     */
18
    protected $conflictSupport = true;
19
20
    /**
21
     * {@inheritdoc}
22
     */
23
    public function flush()
24
    {
25
        return $this->client->exec("TRUNCATE TABLE $this->table") !== false;
26
    }
27
28
    /**
29
     * {@inheritdoc}
30
     */
31
    public function set($key, $value, $expire = 0)
32
    {
33
        if (!$this->conflictSupport) {
34
            return parent::set($key, $value, $expire);
35
        }
36
37
        $this->clearExpired();
38
39
        $statement = $this->client->prepare(
40
            "INSERT INTO $this->table (k, v, e)
41
            VALUES (:key, :value, :expire) 
42
            ON CONFLICT (k) DO UPDATE SET v=EXCLUDED.v, e=EXCLUDED.e"
43
        );
44
45
        $statement->execute(array(
46
            ':key' => $key,
47
            ':value' => $this->serialize($value),
48
            ':expire' => $this->expire($expire),
49
        ));
50
51
        // ON CONFLICT is not supported in versions < 9.5, in which case we'll
52
        // have to fall back on add/replace
53
        if ($statement->errorCode() === '42601') {
54
            $this->conflictSupport = false;
55
56
            return $this->set($key, $value, $expire);
57
        }
58
59
        return $statement->rowCount() === 1;
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function get($key, &$token = null)
66
    {
67
        $return = parent::get($key, $token);
68
69
        if ($token !== null) {
70
            // BYTEA data return streams - we actually need the data in
71
            // serialized format, not some silly stream
72
            $token = $this->serialize($return);
73
        }
74
75
        return $return;
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81
    public function getMulti(array $keys, array &$tokens = null)
82
    {
83
        $return = parent::getMulti($keys, $tokens);
84
85
        foreach ($return as $key => $value) {
86
            // BYTEA data return streams - we actually need the data in
87
            // serialized format, not some silly stream
88
            $tokens[$key] = $this->serialize($value);
89
        }
90
91
        return $return;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    protected function init()
98
    {
99
        $this->client->exec(
100
            "CREATE TABLE IF NOT EXISTS $this->table (
101
                k VARCHAR NOT NULL PRIMARY KEY,
102
                v TEXT,
103
                e TIMESTAMP NULL DEFAULT NULL
104
            )"
105
        );
106
        $this->client->exec("CREATE INDEX IF NOT EXISTS e_index ON $this->table (e)");
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112
    protected function unserialize($value)
113
    {
114
        // BYTEA data return streams. Even though it's not how init() will
115
        // configure the DB by default, it could be used instead!
116
        if (is_resource($value)) {
117
            $value = stream_get_contents($value);
118
        }
119
120
        return parent::unserialize($value);
121
    }
122
}
123