Completed
Push — master ( 22a331...8f6a24 )
by Marco
62:34 queued 60:06
created

SQLite3Cache::isExpired()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 0
cts 6
cp 0
rs 9.4285
cc 3
eloc 4
nc 3
nop 1
crap 12
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\Common\Cache;
21
22
use SQLite3;
23
use SQLite3Result;
24
25
/**
26
 * SQLite3 cache provider.
27
 *
28
 * @since  1.4
29
 * @author Jake Bell <[email protected]>
30
 */
31
class SQLite3Cache extends CacheProvider
32
{
33
    /**
34
     * The ID field will store the cache key.
35
     */
36
    const ID_FIELD = 'k';
37
38
    /**
39
     * The data field will store the serialized PHP value.
40
     */
41
    const DATA_FIELD = 'd';
42
43
    /**
44
     * The expiration field will store a date value indicating when the
45
     * cache entry should expire.
46
     */
47
    const EXPIRATION_FIELD = 'e';
48
49
    /**
50
     * @var SQLite3
51
     */
52
    private $sqlite;
53
54
    /**
55
     * @var string
56
     */
57
    private $table;
58
59
    /**
60
     * Constructor.
61
     *
62
     * Calling the constructor will ensure that the database file and table 
63
     * exist and will create both if they don't.
64
     *
65
     * @param SQLite3 $sqlite
66
     * @param string $table
67
     */
68
    public function __construct(SQLite3 $sqlite, $table)
69
    {
70
        $this->sqlite = $sqlite;
71
        $this->table  = (string) $table;
72
73
        list($id, $data, $exp) = $this->getFields();
74
75
        return $this->sqlite->exec(sprintf(
76
            'CREATE TABLE IF NOT EXISTS %s(%s TEXT PRIMARY KEY NOT NULL, %s BLOB, %s INTEGER)',
77
            $table,
78
            $id,
79
            $data,
80
            $exp
81
        ));
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    protected function doFetch($id)
88
    {
89
        $item = $this->findById($id)
90
91
        if (!$item) {
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_IF
Loading history...
92
            return false;
93
        }
94
95
        return unserialize($item[self::DATA_FIELD]);
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    protected function doContains($id)
102
    {
103
        return null !== $this->findById($id, false);
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    protected function doSave($id, $data, $lifeTime = 0)
110
    {
111
        $statement = $this->sqlite->prepare(sprintf(
112
            'INSERT OR REPLACE INTO %s (%s) VALUES (:id, :data, :expire)',
113
            $this->table,
114
            implode(',', $this->getFields())
115
        ));
116
117
        $statement->bindValue(':id', $id);
118
        $statement->bindValue(':data', serialize($data), SQLITE3_BLOB);
119
        $statement->bindValue(':expire', $lifeTime > 0 ? time() + $lifeTime : null);
120
121
        return $statement->execute() instanceof SQLite3Result;
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    protected function doDelete($id)
128
    {
129
        list($idField) = $this->getFields();
130
131
        $statement = $this->sqlite->prepare(sprintf(
132
            'DELETE FROM %s WHERE %s = :id',
133
            $this->table,
134
            $idField
135
        ));
136
137
        $statement->bindValue(':id', $id);
138
139
        return $statement->execute() instanceof SQLite3Result;
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    protected function doFlush()
146
    {
147
        return $this->sqlite->exec(sprintf('DELETE FROM %s', $this->table));
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    protected function doGetStats()
154
    {
155
        // no-op.
156
    }
157
158
    /**
159
     * Find a single row by ID.
160
     *
161
     * @param mixed $id
162
     * @param bool $includeData
163
     *
164
     * @return array|null
165
     */
166
    private function findById($id, $includeData = true)
167
    {
168
        list($idField) = $fields = $this->getFields();
169
170
        if (!$includeData) {
171
            $key = array_search(static::DATA_FIELD, $fields);
172
            unset($fields[$key]);
173
        }
174
175
        $statement = $this->sqlite->prepare(sprintf(
176
            'SELECT %s FROM %s WHERE %s = :id LIMIT 1',
177
            implode(',', $fields),
178
            $this->table,
179
            $idField
180
        ));
181
182
        $statement->bindValue(':id', $id, SQLITE3_TEXT);
183
184
        $item = $statement->execute()->fetchArray(SQLITE3_ASSOC);
185
186
        if ($item === false) {
187
            return null;
188
        }
189
190
        if ($this->isExpired($item)) {
191
            $this->doDelete($id);
192
193
            return null;
194
        }
195
196
        return $item;
197
    }
198
199
    /**
200
     * Gets an array of the fields in our table.
201
     *
202
     * @return array
203
     */
204
    private function getFields()
205
    {
206
        return [static::ID_FIELD, static::DATA_FIELD, static::EXPIRATION_FIELD];
207
    }
208
209
    /**
210
     * Check if the item is expired.
211
     *
212
     * @param array $item
213
     *
214
     * @return bool
215
     */
216
    private function isExpired(array $item)
217
    {
218
        return isset($item[static::EXPIRATION_FIELD]) &&
219
            $item[self::EXPIRATION_FIELD] !== null &&
220
            $item[self::EXPIRATION_FIELD] < time();
221
    }
222
}
223