Skip to content

Commit

Permalink
Added custom caching functions
Browse files Browse the repository at this point in the history
This is a combination of 20 commits:
added cache callback #212

added test

Added text for custom cache

formating and tests

added caching_auto_clear option

moved custom cache test for php 5.3+

fixed ConfigTest.php

tabs to spaces

formating

formating

added `create_cache_key` callback option

added $table_name to clear cache function

added $table_name to _create_cache_key

added missing params

added $table_name to cache_query_result

formating

tabs

added $table_name to check_query_cache

unify cache parameters order

`table_name` is more important than `connection_name`

formating
  • Loading branch information
peter-mw authored and treffynnon committed Jun 22, 2014
1 parent 00c6f6c commit e7b77ad
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 10 deletions.
43 changes: 43 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,21 @@ Idiorm can cache the queries it executes during a request. To enable
query caching, set the ``caching`` option to ``true`` (it is ``false``
by default).

.. code-block:: php
<?php
ORM::configure('caching', true);
Setting: ``caching_auto_clear``

Idiorm's cache is never cleared by default. If you wish to automatically clear it on save, set ``caching_auto_clear`` to ``true``

.. code-block:: php
<?php
ORM::configure('caching_auto_clear', true);
When query caching is enabled, Idiorm will cache the results of every
``SELECT`` query it executes. If Idiorm encounters a query that has
already been run, it will fetch the results directly from its cache and
Expand All @@ -313,6 +328,34 @@ Warnings and gotchas
application, as all database rows that are fetched during each
request are held in memory. If you are working with large quantities
of data, you may wish to disable the cache.

If you wish to use custom caching functions, you can set them from the configure options.

.. code-block:: php
<?php
$my_cache = array();
ORM::configure('cache_query_result', function ($cache_key, $value, $table_name, $connection_name) use (&$my_cache) {
$my_cache[$cache_key] = $value;
});
ORM::configure('check_query_cache', function ($cache_key, $table_name, $connection_name) use (&$my_cache) {
if(isset($my_cache[$cache_key])){
return $my_cache[$cache_key];
} else {
return false;
}
});
ORM::configure('clear_cache', function ($table_name, $connection_name) use (&$my_cache) {
$my_cache = array();
});
ORM::configure('create_cache_key', function ($query, $parameters, $table_name, $connection_name) {
$parameter_string = join(',', $parameters);
$key = $query . ':' . $parameter_string;
$my_key = 'my-prefix'.crc32($key);
return $my_key;
});
.. _PDO documentation: http://php.net/manual/en/pdo.construct.php
.. _the PDO documentation: http://www.php.net/manual/en/pdo.construct.php
Expand Down
34 changes: 24 additions & 10 deletions idiorm.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class ORM implements ArrayAccess {
'logging' => false,
'logger' => null,
'caching' => false,
'caching_auto_clear' => false,
'return_result_sets' => false,
);

Expand Down Expand Up @@ -1758,7 +1759,10 @@ protected function _quote_identifier_part($part) {
/**
* Create a cache key for the given query and parameters.
*/
protected static function _create_cache_key($query, $parameters) {
protected static function _create_cache_key($query, $parameters, $table_name = null, $connection_name = self::DEFAULT_CONNECTION) {
if(isset(self::$_config[$connection_name]['create_cache_key']) and is_callable(self::$_config[$connection_name]['create_cache_key'])){
return call_user_func_array(self::$_config[$connection_name]['create_cache_key'], array($query, $parameters, $table_name, $connection_name));
}
$parameter_string = join(',', $parameters);
$key = $query . ':' . $parameter_string;
return sha1($key);
Expand All @@ -1768,8 +1772,10 @@ protected static function _create_cache_key($query, $parameters) {
* Check the query cache for the given cache key. If a value
* is cached for the key, return the value. Otherwise, return false.
*/
protected static function _check_query_cache($cache_key, $connection_name = self::DEFAULT_CONNECTION) {
if (isset(self::$_query_cache[$connection_name][$cache_key])) {
protected static function _check_query_cache($cache_key, $table_name = null, $connection_name = self::DEFAULT_CONNECTION) {
if(isset(self::$_config[$connection_name]['check_query_cache']) and is_callable(self::$_config[$connection_name]['check_query_cache'])){
return call_user_func_array(self::$_config[$connection_name]['check_query_cache'], array($cache_key, $table_name, $connection_name));
} elseif (isset(self::$_query_cache[$connection_name][$cache_key])) {
return self::$_query_cache[$connection_name][$cache_key];
}
return false;
Expand All @@ -1778,15 +1784,20 @@ protected static function _check_query_cache($cache_key, $connection_name = self
/**
* Clear the query cache
*/
public static function clear_cache() {
public static function clear_cache($table_name = null, $connection_name = self::DEFAULT_CONNECTION) {
self::$_query_cache = array();
if(isset(self::$_config[$connection_name]['clear_cache']) and is_callable(self::$_config[$connection_name]['clear_cache'])){
return call_user_func_array(self::$_config[$connection_name]['clear_cache'], array($table_name, $connection_name));
}
}

/**
* Add the given value to the query cache.
*/
protected static function _cache_query_result($cache_key, $value, $connection_name = self::DEFAULT_CONNECTION) {
if (!isset(self::$_query_cache[$connection_name])) {
protected static function _cache_query_result($cache_key, $value, $table_name = null, $connection_name = self::DEFAULT_CONNECTION) {
if(isset(self::$_config[$connection_name]['cache_query_result']) and is_callable(self::$_config[$connection_name]['cache_query_result'])){
return call_user_func_array(self::$_config[$connection_name]['cache_query_result'], array($cache_key, $value, $table_name, $connection_name));
} elseif (!isset(self::$_query_cache[$connection_name])) {
self::$_query_cache[$connection_name] = array();
}
self::$_query_cache[$connection_name][$cache_key] = $value;
Expand All @@ -1801,8 +1812,8 @@ protected function _run() {
$caching_enabled = self::$_config[$this->_connection_name]['caching'];

if ($caching_enabled) {
$cache_key = self::_create_cache_key($query, $this->_values);
$cached_result = self::_check_query_cache($cache_key, $this->_connection_name);
$cache_key = self::_create_cache_key($query, $this->_values, $this->_table_name, $this->_connection_name);
$cached_result = self::_check_query_cache($cache_key, $this->_table_name, $this->_connection_name);

if ($cached_result !== false) {
return $cached_result;
Expand All @@ -1818,7 +1829,7 @@ protected function _run() {
}

if ($caching_enabled) {
self::_cache_query_result($cache_key, $rows, $this->_connection_name);
self::_cache_query_result($cache_key, $rows, $this->_table_name, $this->_connection_name);
}

// reset Idiorm after executing the query
Expand Down Expand Up @@ -1986,7 +1997,10 @@ public function save() {
}

$success = self::_execute($query, $values, $this->_connection_name);

$caching_auto_clear_enabled = self::$_config[$this->_connection_name]['caching_auto_clear'];
if($caching_auto_clear_enabled){
self::clear_cache($this->_table_name, $this->_connection_name);
}
// If we've just inserted a new record, set the ID of this object
if ($this->_is_new) {
$this->_is_new = false;
Expand Down
1 change: 1 addition & 0 deletions test/CacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ public function testQueryGenerationOnlyOccursOnceWithMultipleConnections() {
ORM::for_table('widget', self::ALTERNATE)->where('name', 'Steve')->where('age', 80)->find_one(); // this shouldn't run a query!
$this->assertEquals($expected, ORM::get_last_query(self::ALTERNATE));
}

}
82 changes: 82 additions & 0 deletions test/CacheTest53.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

class CacheTest53 extends PHPUnit_Framework_TestCase {

const ALTERNATE = 'alternate'; // Used as name of alternate connection

public function setUp() {
// Set up the dummy database connections
ORM::set_db(new MockPDO('sqlite::memory:'));
ORM::set_db(new MockDifferentPDO('sqlite::memory:'), self::ALTERNATE);

// Enable logging
ORM::configure('logging', true);
ORM::configure('logging', true, self::ALTERNATE);
ORM::configure('caching', true);
ORM::configure('caching', true, self::ALTERNATE);
}

public function tearDown() {
ORM::reset_config();
ORM::reset_db();
}


public function testCustomCacheCallback() {
$phpunit = $this;
$my_cache = array();
ORM::configure('caching_auto_clear', true);

ORM::configure('create_cache_key', function ($query, $parameters, $table_name, $connection) use ($phpunit, &$my_cache) {
$phpunit->assertEquals(true, is_string($query));
$phpunit->assertEquals(true, is_array($parameters));
$phpunit->assertEquals(true, is_string($connection));
$phpunit->assertEquals('widget', $table_name);
$parameter_string = join(',', $parameters);
$key = $query . ':' . $parameter_string;
$my_key = 'some-prefix'.crc32($key);
return $my_key;
});
ORM::configure('cache_query_result', function ($cache_key, $value, $table_name, $connection_name) use ($phpunit, &$my_cache) {
$phpunit->assertEquals(true, is_string($cache_key));
$phpunit->assertEquals('widget', $table_name);
$my_cache[$cache_key] = $value;
});
ORM::configure('check_query_cache', function ($cache_key, $table_name, $connection_name) use ($phpunit, &$my_cache) {
$phpunit->assertEquals(true, is_string($cache_key));
$phpunit->assertEquals(true, is_string($connection_name));
$phpunit->assertEquals('widget', $table_name);

if(isset($my_cache) and isset($my_cache[$cache_key])){
$phpunit->assertEquals(true, is_array($my_cache[$cache_key]));
return $my_cache[$cache_key];
} else {
return false;
}
});
ORM::configure('clear_cache', function ($table_name, $connection_name) use ($phpunit, &$my_cache) {
$phpunit->assertEquals(true, is_string($table_name));
$phpunit->assertEquals(true, is_string($connection_name));
$my_cache = array();
});
ORM::for_table('widget')->where('name', 'Fred')->where('age', 21)->find_one();
ORM::for_table('widget')->where('name', 'Fred')->where('age', 21)->find_one();
ORM::for_table('widget')->where('name', 'Bob')->where('age', 42)->find_one();

//our custom cache should be full now
$this->assertEquals(true, !empty($my_cache));

//checking custom cache key
foreach($my_cache as $k=>$v){
$this->assertEquals('some-prefix', substr($k,0,11));
}

$new = ORM::for_table('widget')->create();
$new->name = "Joe";
$new->age = 25;
$saved = $new->save();

//our custom cache should be empty now
$this->assertEquals(true, empty($my_cache));
}
}
1 change: 1 addition & 0 deletions test/ConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public function testGetConfigArray() {
'logging' => true,
'logger' => null,
'caching' => false,
'caching_auto_clear' => false,
'return_result_sets' => false,
'limit_clause_style' => 'limit',
);
Expand Down

0 comments on commit e7b77ad

Please # to comment.