Skip to content

Commit

Permalink
Merge pull request #4765 from cakephp/3.0-extract-schema-cache
Browse files Browse the repository at this point in the history
3.0 extract schema cache
  • Loading branch information
markstory committed Sep 30, 2014
2 parents 11b0b27 + 313fd56 commit 9ecf121
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 58 deletions.
29 changes: 26 additions & 3 deletions src/Database/Connection.php
Expand Up @@ -21,6 +21,8 @@
use Cake\Database\Log\LoggingStatement;
use Cake\Database\Log\QueryLogger;
use Cake\Database\Query;
use Cake\Database\Schema\CachedCollection;
use Cake\Database\Schema\Collection as SchemaCollection;
use Cake\Database\ValueBinder;

/**
Expand Down Expand Up @@ -81,6 +83,13 @@ class Connection {
*/
protected $_logger = null;

/**
* The schema collection object
*
* @var \Cake\Database\Schema\Collection
*/
protected $_schemaCollection;

/**
* Constructor.
*
Expand Down Expand Up @@ -280,12 +289,25 @@ public function newQuery() {
}

/**
* Get a Schema\Collection object for this connection.
* Gets or sets a Schema\Collection object for this connection.
*
* @param \Cake\Database\Schema\Collection $collection The schema collection object
* @return \Cake\Database\Schema\Collection
*/
public function schemaCollection() {
return new \Cake\Database\Schema\Collection($this);
public function schemaCollection(SchemaCollection $collection = null) {
if ($collection !== null) {
return $this->_schemaCollection = $collection;
}

if ($this->_schemaCollection !== null) {
return $this->_schemaCollection;
}

if (!empty($this->_config['cacheMetadata'])) {
return $this->_schemaCollection = new CachedCollection($this, $this->_config['cacheMetadata']);
}

return $this->_schemaCollection = new SchemaCollection($this);
}

/**
Expand Down Expand Up @@ -584,6 +606,7 @@ public function logQueries($enable = null) {
* @return void
*/
public function cacheMetadata($cache) {
$this->_schemaCollection = null;
$this->_config['cacheMetadata'] = $cache;
}

Expand Down
99 changes: 99 additions & 0 deletions src/Database/Schema/CachedCollection.php
@@ -0,0 +1,99 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Database\Schema;

use Cake\Cache\Cache;
use Cake\Database\Connection;
use Cake\Database\Schema\Collection;

/**
* Extends the schema collection class to provide caching
*
*/
class CachedCollection extends Collection {

/**
* The name of the cache config key to use for caching table metadata,
* of false if disabled.
*
* @var string|bool
*/
protected $_cache = false;

/**
* Constructor.
*
* @param \Cake\Database\Connection $connection The connection instance.
* @param string|bool $cacheKey The cache key or boolean false to disable caching.
*/
public function __construct(Connection $connection, $cacheKey = true) {
parent::__construct($connection);
$this->cacheMetadata($cacheKey);
}

/**
* {@inheritDoc}
*
*/
public function describe($name, array $options = []) {
$options += ['forceRefresh' => false];
$cacheConfig = $this->cacheMetadata();
$cacheKey = $this->cacheKey($name);

if (!empty($cacheConfig) && !$options['forceRefresh']) {
$cached = Cache::read($cacheKey, $cacheConfig);
if ($cached !== false) {
return $cached;
}
}

$table = parent::describe($name, $options);

if (!empty($cacheConfig)) {
Cache::write($cacheKey, $table, $cacheConfig);
}

return $table;
}

/**
* Get the cache key for a given name.
*
* @param string $name The name to get a cache key for.
* @return string The cache key.
*/
public function cacheKey($name) {
return $this->_connection->configName() . '_' . $name;
}

/**
* Sets the cache config name to use for caching table metadata, or
* disabels it if false is passed.
* If called with no arguments it returns the current configuration name.
*
* @param bool $enable whether or not to enable caching
* @return string|bool
*/
public function cacheMetadata($enable = null) {
if ($enable === null) {
return $this->_cache;
}
if ($enable === true) {
$enable = '_cake_model_';
}
return $this->_cache = $enable;
}

}
55 changes: 1 addition & 54 deletions src/Database/Schema/Collection.php
Expand Up @@ -41,14 +41,6 @@ class Collection {
*/
protected $_dialect;

/**
* The name of the cache config key to use for caching table metadata,
* of false if disabled.
*
* @var string|bool
*/
protected $_cache = false;

/**
* Constructor.
*
Expand All @@ -57,11 +49,6 @@ class Collection {
public function __construct(Connection $connection) {
$this->_connection = $connection;
$this->_dialect = $connection->driver()->schemaDialect();
$config = $this->_connection->config();

if (!empty($config['cacheMetadata'])) {
$this->cacheMetadata($config['cacheMetadata']);
}
}

/**
Expand Down Expand Up @@ -97,16 +84,6 @@ public function listTables() {
* @throws \Cake\Database\Exception when table cannot be described.
*/
public function describe($name, array $options = []) {
$options += ['forceRefresh' => false];
$cacheConfig = $this->cacheMetadata();
$cacheKey = $this->cacheKey($name);

if (!empty($cacheConfig) && !$options['forceRefresh']) {
$cached = Cache::read($cacheKey, $cacheConfig);
if ($cached !== false) {
return $cached;
}
}
$config = $this->_connection->config();
if (strpos($name, '.')) {
list($config['schema'], $name) = explode('.', $name);
Expand All @@ -117,13 +94,11 @@ public function describe($name, array $options = []) {
if (count($table->columns()) === 0) {
throw new Exception(sprintf('Cannot describe %s. It has 0 columns.', $name));
}

$this->_reflect('Index', $name, $config, $table);
$this->_reflect('ForeignKey', $name, $config, $table);
$this->_reflect('Options', $name, $config, $table);

if (!empty($cacheConfig)) {
Cache::write($cacheKey, $table, $cacheConfig);
}
return $table;
}

Expand Down Expand Up @@ -156,32 +131,4 @@ protected function _reflect($stage, $name, $config, $table) {
$statement->closeCursor();
}

/**
* Get the cache key for a given name.
*
* @param string $name The name to get a cache key for.
* @return string The cache key.
*/
public function cacheKey($name) {
return $this->_connection->configName() . '_' . $name;
}

/**
* Sets the cache config name to use for caching table metadata, or
* disabels it if false is passed.
* If called with no arguments it returns the current configuration name.
*
* @param bool $enable whether or not to enable caching
* @return string|bool
*/
public function cacheMetadata($enable = null) {
if ($enable === null) {
return $this->_cache;
}
if ($enable === true) {
$enable = '_cake_model_';
}
return $this->_cache = $enable;
}

}
21 changes: 21 additions & 0 deletions tests/TestCase/Database/ConnectionTest.php
Expand Up @@ -812,4 +812,25 @@ public function testTransactionalWithException() {
});
}

/**
* Tests it is possible to set a schema collection object
*
* @return void
*/
public function testSchemaCollection() {
$driver = $this->getMockFormDriver();
$connection = $this->getMock(
'\Cake\Database\Connection',
['connect'],
[['driver' => $driver]]
);

$schema = $connection->schemaCollection();
$this->assertInstanceOf('Cake\Database\Schema\Collection', $schema);

$schema = $this->getMock('Cake\Database\Schema\Collection', [], [$connection]);
$connection->schemaCollection($schema);
$this->assertSame($schema, $connection->schemaCollection());
}

}
4 changes: 3 additions & 1 deletion tests/TestCase/Database/Schema/CollectionTest.php
Expand Up @@ -77,7 +77,9 @@ public function testDescribeCache() {
$table = $this->connection->schemaCollection()->describe('users');

Cache::delete('test_users', '_cake_model_');
$schema->cacheMetadata(true);
$this->connection->cacheMetadata(true);
$schema = $this->connection->schemaCollection();

$result = $schema->describe('users');
$this->assertEquals($table, $result);

Expand Down

0 comments on commit 9ecf121

Please sign in to comment.