Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/**
4
 * PDO Cache Handler
5
 * Allows you to store Smarty Cache files into your db.
6
 * Example table :
7
 * CREATE TABLE `smarty_cache` (
8
 * `id` char(40) NOT NULL COMMENT 'sha1 hash',
9
 * `name` varchar(250) NOT NULL,
10
 * `cache_id` varchar(250) DEFAULT NULL,
11
 * `compile_id` varchar(250) DEFAULT NULL,
12
 * `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
13
 * `expire` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
14
 * `content` mediumblob NOT NULL,
15
 * PRIMARY KEY (`id`),
16
 * KEY `name` (`name`),
17
 * KEY `cache_id` (`cache_id`),
18
 * KEY `compile_id` (`compile_id`),
19
 * KEY `modified` (`modified`),
20
 * KEY `expire` (`expire`)
21
 * ) ENGINE=InnoDB
22
 * Example usage :
23
 *      $cnx    =   new PDO("mysql:host=localhost;dbname=mydb", "username", "password");
24
 *      $smarty->setCachingType('pdo');
25
 *      $smarty->loadPlugin('Smarty_CacheResource_Pdo');
26
 *      $smarty->registerCacheResource('pdo', new Smarty_CacheResource_Pdo($cnx, 'smarty_cache'));
27
 *
28
 * @author Beno!t POLASZEK - 2014
29
 */
30
class Smarty_CacheResource_Pdo extends Smarty_CacheResource_Custom
31
{
32
    /**
33
     * @var string[]
34
     */
35
    protected $fetchStatements = array('default' => 'SELECT %2$s
36
                                                                                    FROM %1$s
37
                                                                                    WHERE 1
38
                                                                                    AND id          = :id
39
                                                                                    AND cache_id    IS NULL
40
                                                                                    AND compile_id  IS NULL',
41
                                       'withCacheId' => 'SELECT %2$s
42
                                                                                FROM %1$s
43
                                                                                WHERE 1
44
                                                                                AND id          = :id
45
                                                                                AND cache_id    = :cache_id
46
                                                                                AND compile_id  IS NULL',
47
                                       'withCompileId' => 'SELECT %2$s
48
                                                                                FROM %1$s
49
                                                                                WHERE 1
50
                                                                                AND id          = :id
51
                                                                                AND compile_id  = :compile_id
52
                                                                                AND cache_id    IS NULL',
53
                                       'withCacheIdAndCompileId' => 'SELECT %2$s
54
                                                                                FROM %1$s
55
                                                                                WHERE 1
56
                                                                                AND id          = :id
57
                                                                                AND cache_id    = :cache_id
58
                                                                                AND compile_id  = :compile_id');
59
 
60
    /**
61
     * @var string
62
     */
63
    protected $insertStatement = 'INSERT INTO %s
64
 
65
                                                SET id          =   :id,
66
                                                    name        =   :name,
67
                                                    cache_id    =   :cache_id,
68
                                                    compile_id  =   :compile_id,
69
                                                    modified    =   CURRENT_TIMESTAMP,
70
                                                    expire      =   DATE_ADD(CURRENT_TIMESTAMP, INTERVAL :expire SECOND),
71
                                                    content     =   :content
72
 
73
                                                ON DUPLICATE KEY UPDATE
74
                                                    name        =   :name,
75
                                                    cache_id    =   :cache_id,
76
                                                    compile_id  =   :compile_id,
77
                                                    modified    =   CURRENT_TIMESTAMP,
78
                                                    expire      =   DATE_ADD(CURRENT_TIMESTAMP, INTERVAL :expire SECOND),
79
                                                    content     =   :content';
80
 
81
    /**
82
     * @var string
83
     */
84
    protected $deleteStatement = 'DELETE FROM %1$s WHERE %2$s';
85
 
86
    /**
87
     * @var string
88
     */
89
    protected $truncateStatement = 'TRUNCATE TABLE %s';
90
 
91
    /**
92
     * @var string
93
     */
94
    protected $fetchColumns = 'modified, content';
95
 
96
    /**
97
     * @var string
98
     */
99
    protected $fetchTimestampColumns = 'modified';
100
 
101
    /**
102
     * @var \PDO
103
     */
104
    protected $pdo;
105
 
106
    /**
107
     * @var
108
     */
109
    protected $table;
110
 
111
    /**
112
     * @var null
113
     */
114
    protected $database;
115
 
116
    /**
117
     * Constructor
118
     *
119
     * @param PDO    $pdo      PDO : active connection
120
     * @param string $table    : table (or view) name
121
     * @param string $database : optional - if table is located in another db
122
     *
123
     * @throws \SmartyException
124
     */
125
    public function __construct(PDO $pdo, $table, $database = null)
126
    {
127
        if (is_null($table)) {
128
            throw new SmartyException("Table name for caching can't be null");
129
        }
130
        $this->pdo = $pdo;
131
        $this->table = $table;
132
        $this->database = $database;
133
        $this->fillStatementsWithTableName();
134
    }
135
 
136
    /**
137
     * Fills the table name into the statements.
138
     *
139
     * @return $this Current Instance
140
     * @access protected
141
     */
142
    protected function fillStatementsWithTableName()
143
    {
144
        foreach ($this->fetchStatements as &$statement) {
145
            $statement = sprintf($statement, $this->getTableName(), '%s');
146
        }
147
        $this->insertStatement = sprintf($this->insertStatement, $this->getTableName());
148
        $this->deleteStatement = sprintf($this->deleteStatement, $this->getTableName(), '%s');
149
        $this->truncateStatement = sprintf($this->truncateStatement, $this->getTableName());
150
        return $this;
151
    }
152
 
153
    /**
154
     * Gets the fetch statement, depending on what you specify
155
     *
156
     * @param string      $columns    : the column(s) name(s) you want to retrieve from the database
157
     * @param string      $id         unique cache content identifier
158
     * @param string|null $cache_id   cache id
159
     * @param string|null $compile_id compile id
160
     *
161
     * @access protected
162
     * @return \PDOStatement
163
     */
164
    protected function getFetchStatement($columns, $id, $cache_id = null, $compile_id = null)
165
    {
166
        $args = array();
167
        if (!is_null($cache_id) && !is_null($compile_id)) {
168
            $query = $this->fetchStatements[ 'withCacheIdAndCompileId' ] and
169
            $args = array('id' => $id, 'cache_id' => $cache_id, 'compile_id' => $compile_id);
170
        } elseif (is_null($cache_id) && !is_null($compile_id)) {
171
            $query = $this->fetchStatements[ 'withCompileId' ] and
172
            $args = array('id' => $id, 'compile_id' => $compile_id);
173
        } elseif (!is_null($cache_id) && is_null($compile_id)) {
174
            $query = $this->fetchStatements[ 'withCacheId' ] and $args = array('id' => $id, 'cache_id' => $cache_id);
175
        } else {
176
            $query = $this->fetchStatements[ 'default' ] and $args = array('id' => $id);
177
        }
178
        $query = sprintf($query, $columns);
179
        $stmt = $this->pdo->prepare($query);
180
        foreach ($args as $key => $value) {
181
            $stmt->bindValue($key, $value);
182
        }
183
        return $stmt;
184
    }
185
 
186
    /**
187
     * fetch cached content and its modification time from data source
188
     *
189
     * @param string      $id         unique cache content identifier
190
     * @param string      $name       template name
191
     * @param string|null $cache_id   cache id
192
     * @param string|null $compile_id compile id
193
     * @param string      $content    cached content
194
     * @param integer     $mtime      cache modification timestamp (epoch)
195
     *
196
     * @return void
197
     * @access protected
198
     */
199
    protected function fetch($id, $name, $cache_id, $compile_id, &$content, &$mtime)
200
    {
201
        $stmt = $this->getFetchStatement($this->fetchColumns, $id, $cache_id, $compile_id);
202
        $stmt->execute();
203
        $row = $stmt->fetch();
204
        $stmt->closeCursor();
205
        if ($row) {
206
            $content = $this->outputContent($row[ 'content' ]);
207
            $mtime = strtotime($row[ 'modified' ]);
208
        } else {
209
            $content = null;
210
            $mtime = null;
211
        }
212
    }
213
 
214
    /**
215
     * Fetch cached content's modification timestamp from data source
216
     * {@internal implementing this method is optional.
217
     *  Only implement it if modification times can be accessed faster than loading the complete cached content.}}
218
     *
219
     * @param string      $id         unique cache content identifier
220
     * @param string      $name       template name
221
     * @param string|null $cache_id   cache id
222
     * @param string|null $compile_id compile id
223
     *
224
     * @return integer|boolean timestamp (epoch) the template was modified, or false if not found
225
     * @access protected
226
     */
227
    //    protected function fetchTimestamp($id, $name, $cache_id = null, $compile_id = null) {
228
    //        $stmt       =   $this->getFetchStatement($this->fetchTimestampColumns, $id, $cache_id, $compile_id);
229
    //        $stmt       ->  execute();
230
    //        $mtime      =   strtotime($stmt->fetchColumn());
231
    //        $stmt       ->  closeCursor();
232
    //        return $mtime;
233
    //    }
234
    /**
235
     * Save content to cache
236
     *
237
     * @param string       $id         unique cache content identifier
238
     * @param string       $name       template name
239
     * @param string|null  $cache_id   cache id
240
     * @param string|null  $compile_id compile id
241
     * @param integer|null $exp_time   seconds till expiration time in seconds or null
242
     * @param string       $content    content to cache
243
     *
244
     * @return boolean success
245
     * @access protected
246
     */
247
    protected function save($id, $name, $cache_id, $compile_id, $exp_time, $content)
248
    {
249
        $stmt = $this->pdo->prepare($this->insertStatement);
250
        $stmt->bindValue('id', $id);
251
        $stmt->bindValue('name', $name);
252
        $stmt->bindValue('cache_id', $cache_id, (is_null($cache_id)) ? PDO::PARAM_NULL : PDO::PARAM_STR);
253
        $stmt->bindValue('compile_id', $compile_id, (is_null($compile_id)) ? PDO::PARAM_NULL : PDO::PARAM_STR);
254
        $stmt->bindValue('expire', (int)$exp_time, PDO::PARAM_INT);
255
        $stmt->bindValue('content', $this->inputContent($content));
256
        $stmt->execute();
257
        return !!$stmt->rowCount();
258
    }
259
 
260
    /**
261
     * Encodes the content before saving to database
262
     *
263
     * @param string $content
264
     *
265
     * @return string $content
266
     * @access protected
267
     */
268
    protected function inputContent($content)
269
    {
270
        return $content;
271
    }
272
 
273
    /**
274
     * Decodes the content before saving to database
275
     *
276
     * @param string $content
277
     *
278
     * @return string $content
279
     * @access protected
280
     */
281
    protected function outputContent($content)
282
    {
283
        return $content;
284
    }
285
 
286
    /**
287
     * Delete content from cache
288
     *
289
     * @param string|null $name       template name
290
     * @param string|null $cache_id   cache id
291
     * @param string|null $compile_id compile id
292
     * @param              integer|null|-1 $exp_time   seconds till expiration or null
293
     *
294
     * @return integer number of deleted caches
295
     * @access             protected
296
     */
297
    protected function delete($name = null, $cache_id = null, $compile_id = null, $exp_time = null)
298
    {
299
        // delete the whole cache
300
        if ($name === null && $cache_id === null && $compile_id === null && $exp_time === null) {
301
            // returning the number of deleted caches would require a second query to count them
302
            $this->pdo->query($this->truncateStatement);
303
            return -1;
304
        }
305
        // build the filter
306
        $where = array();
307
        // equal test name
308
        if ($name !== null) {
309
            $where[] = 'name = ' . $this->pdo->quote($name);
310
        }
311
        // equal test cache_id and match sub-groups
312
        if ($cache_id !== null) {
313
            $where[] =
314
                '(cache_id = ' .
315
                $this->pdo->quote($cache_id) .
316
                ' OR cache_id LIKE ' .
317
                $this->pdo->quote($cache_id . '|%') .
318
                ')';
319
        }
320
        // equal test compile_id
321
        if ($compile_id !== null) {
322
            $where[] = 'compile_id = ' . $this->pdo->quote($compile_id);
323
        }
324
        // for clearing expired caches
325
        if ($exp_time === Smarty::CLEAR_EXPIRED) {
326
            $where[] = 'expire < CURRENT_TIMESTAMP';
327
        } // range test expiration time
328
        elseif ($exp_time !== null) {
329
            $where[] = 'modified < DATE_SUB(NOW(), INTERVAL ' . intval($exp_time) . ' SECOND)';
330
        }
331
        // run delete query
332
        $query = $this->pdo->query(sprintf($this->deleteStatement, join(' AND ', $where)));
333
        return $query->rowCount();
334
    }
335
 
336
    /**
337
     * Gets the formatted table name
338
     *
339
     * @return string
340
     * @access protected
341
     */
342
    protected function getTableName()
343
    {
344
        return (is_null($this->database)) ? "`{$this->table}`" : "`{$this->database}`.`{$this->table}`";
345
    }
346
}