diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index a73eea8a7..9402bdc21 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -786,10 +786,57 @@ class DboSource extends DataSource { if ($value === null) { return (isset(static::$methodCache[$method][$key])) ? static::$methodCache[$method][$key] : null; } + if (!$this->cacheMethodFilter($method, $key, $value)) { + return $value; + } $this->_methodCacheChange = true; return static::$methodCache[$method][$key] = $value; } +/** + * Filters to apply to the results of `name` and `fields`. When the filter for a given method does not return `true` + * then the result is not added to the memory cache. + * + * Some examples: + * + * ``` + * // For method fields, do not cache values that contain floats + * if ($method === 'fields') { + * $hasFloat = preg_grep('/(\d+)?\.\d+/', $value); + * + * return count($hasFloat) === 0; + * } + * + * return true; + * ``` + * + * ``` + * // For method name, do not cache values that have the name created + * if ($method === 'name') { + * return preg_match('/^`created`$/', $value) !== 1; + * } + * + * return true; + * ``` + * + * ``` + * // For method name, do not cache values that have the key 472551d38e1f8bbc78d7dfd28106166f + * if ($key === '472551d38e1f8bbc78d7dfd28106166f') { + * return false; + * } + * + * return true; + * ``` + * + * @param string $method Name of the method being cached. + * @param string $key The key name for the cache operation. + * @param mixed $value The value to cache into memory. + * @return bool Whether or not to cache + */ + public function cacheMethodFilter($method, $key, $value) { + return true; + } + /** * Returns a quoted name of $data for use in an SQL statement. * Strips fields out of SQL functions before quoting. diff --git a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php index 911faec5c..1ae79694e 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DboSourceTest.php @@ -109,6 +109,35 @@ class DboSecondTestSource extends DboSource { } +/** + * DboFourthTestSource + * + * @package Cake.Test.Case.Model.Datasource + */ +class DboFourthTestSource extends DboSource { + + public function connect($config = array()) { + $this->connected = true; + } + + public function cacheMethodFilter($method, $key, $value) { + if ($method === 'name') { + if ($value === '`menus`') { + return false; + } elseif ($key === '1fca740733997f1ebbedacfc7678592a') { + return false; + } + } elseif ($method === 'fields') { + $endsWithName = preg_grep('/`name`$/', $value); + + return count($endsWithName) === 0; + } + + return true; + } + +} + /** * DboSourceTest class * @@ -737,6 +766,78 @@ class DboSourceTest extends CakeTestCase { $this->assertNull($result); } +/** + * Test that cacheMethodFilter does not filter by default. + * + * @return void + */ + public function testCacheMethodFilter() { + $method = 'name'; + $key = '49d9207adfce6df1dd3ee8c30c434414'; + $value = '`menus`'; + $actual = $this->testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + + $method = 'fields'; + $key = '2b57253ab1fffb3e95fa4f95299220b1'; + $value = array("`Menu`.`id`", "`Menu`.`name`"); + $actual = $this->testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + + $method = 'non-existing'; + $key = ''; + $value = '``'; + $actual = $this->testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + } + +/** + * Test that cacheMethodFilter can be overridden to do actual filtering. + * + * @return void + */ + public function testCacheMethodFilterOverridden() { + $testDb = new DboFourthTestSource(); + + $method = 'name'; + $key = '49d9207adfce6df1dd3ee8c30c434414'; + $value = '`menus`'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertFalse($actual); + + $method = 'name'; + $key = '1fca740733997f1ebbedacfc7678592a'; + $value = '`Menu`.`id`'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertFalse($actual); + + $method = 'fields'; + $key = '2b57253ab1fffb3e95fa4f95299220b1'; + $value = array("`Menu`.`id`", "`Menu`.`name`"); + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertFalse($actual); + + $method = 'name'; + $key = 'd2bc458620afb092c61ab4383b7475e0'; + $value = '`Menu`'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + + $method = 'non-existing'; + $key = ''; + $value = '``'; + $actual = $testDb->cacheMethodFilter($method, $key, $value); + + $this->assertTrue($actual); + } + /** * Test that rare collisions do not happen with method caching *