Write a CacheBackend implementation for PDO.
authorRobert Sesek <rsesek@bluestatic.org>
Tue, 4 Jun 2013 01:54:00 +0000 (21:54 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Tue, 4 Jun 2013 01:56:41 +0000 (21:56 -0400)
testing/tests/views/pdo_cache_backend_test.php [new file with mode: 0644]
views/pdo_cache_backend.php [new file with mode: 0644]

diff --git a/testing/tests/views/pdo_cache_backend_test.php b/testing/tests/views/pdo_cache_backend_test.php
new file mode 100644 (file)
index 0000000..699a4d4
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+// Hoplite
+// Copyright (c) 2013 Blue Static
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace hoplite\test;
+use hoplite\views as views;
+
+require_once HOPLITE_ROOT . '/views/pdo_cache_backend.php';
+
+class PDOCacheBackendTest extends \PHPUnit_Framework_TestCase
+{
+  private $db;
+  private $cache;
+
+  public function setUp()
+  {
+    $this->db = new \PDO('sqlite::memory:');
+    $this->db->Exec("
+        CREATE TABLE test_template_cache (
+            filename string PRIMARY KEY,
+            data string,
+            mtime int
+        );
+    ");
+
+    $this->cache = new views\PDOCacheBackend(
+        $this->db, 'test_template_cache', 'filename', 'data', 'mtime');
+  }
+
+  private function _GetCount()
+  {
+    $stmt = $this->db->Query("SELECT COUNT(*) AS count FROM test_template_cache");
+    return $stmt->FetchObject()->count;
+  }
+
+  public function testCacheMiss()
+  {
+    $this->assertNull($this->cache->GetTemplateDataForName('test', 100));
+    $this->db->Exec("INSERT INTO test_template_cache (filename, data, mtime) VALUES ('test', 'hello world', 100)");
+    $this->assertEquals('hello world', $this->cache->GetTemplateDataForName('test', 100));
+    $this->assertEquals(1, $this->_GetCount());
+
+    $this->assertNull($this->cache->GetTemplateDataForName('test', 200));
+    $this->assertEquals(0, $this->_GetCount());
+  }
+
+  public function testCacheStore()
+  {
+    $this->cache->StoreCompiledTemplate('name', 400, 'abcdefgh');
+    $this->assertEquals(1, $this->_GetCount());
+
+    $this->assertEquals('abcdefgh', $this->cache->GetTemplateDataForName('name', 400));
+    $this->assertEquals(1, $this->_GetCount());
+
+    $this->assertNull($this->cache->GetTemplateDataForName('name', 500));
+  }
+}
diff --git a/views/pdo_cache_backend.php b/views/pdo_cache_backend.php
new file mode 100644 (file)
index 0000000..da3f093
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+// Hoplite
+// Copyright (c) 2013 Blue Static
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program.  If not, see <http://www.gnu.org/licenses/>.
+
+namespace hoplite\views;
+
+require_once HOPLITE_ROOT . '/views/cache_backend.php';
+
+/*!
+  An instance of CacheBackend that stores compiled templates in a database
+  table accessed through a PDO object.
+*/
+class PDOCacheBackend implements CacheBackend
+{
+  /*! @var \PDOStatement Used to query for cached templates. */
+  protected $fetch_statement = NULL;
+
+  /*! @var \PDOStatement Used to insert new templates. */
+  protected $insert_statement = NULL;
+
+  /*! @var \PDOStatement Used to expire out-of-date templates. */
+  protected $delete_statement = NULL;
+
+  /*!
+    Constructor that prepares the database statements.
+
+    @param \PDO The connected database object.
+    @param string Name of the database table to store templates in.
+    @param string Column in which the template name is stored.
+    @param string Column in which the template data is stored.
+    @param string Column in which the template last modified time is stored.
+  */
+  public function __construct(\PDO $db,
+                              $table_name,
+                              $name_column_name = 'name',
+                              $data_column_name = 'template',
+                              $timestamp_column_name = 'timestamp')
+  {
+    $this->fetch_statement = $db->Prepare("
+        SELECT `$data_column_name` AS template,
+            `$timestamp_column_name` AS timestamp
+        FROM $table_name
+        WHERE `$name_column_name` IN (:name)
+    ");
+
+    $this->insert_statement = $db->Prepare("
+        INSERT INTO `$table_name`
+            (`$name_column_name`, `$data_column_name`, `$timestamp_column_name`)
+        VALUES
+            (:name, :template, :timestamp)
+    ");
+
+    $this->delete_statement = $db->Prepare("
+        DELETE FROM `$table_name`
+        WHERE `$name_column_name` = :name
+    ");
+  }
+
+  public function GetTemplateDataForName($name, $modification_time)
+  {
+    if (!$this->fetch_statement->Execute(array('name' => $name)))
+      return NULL;
+
+    $tpl = $this->fetch_statement->FetchObject();
+    if (!$tpl)
+      return NULL;
+
+    if ($tpl->timestamp < $modification_time) {
+      $this->delete_statement->Execute(array('name' => $name));
+      return NULL;
+    }
+
+    return $tpl->template;
+  }
+
+  public function StoreCompiledTemplate($name, $modification_time, $data)
+  {
+    $this->insert_statement->Execute(array(
+        'name'      => $name,
+        'timestamp' => $modification_time,
+        'template'  => $data,
+    ));
+  }
+}