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