diff --git a/core/includes/cache.inc b/core/includes/cache.inc index 74afcbf..d207d9e 100644 --- a/core/includes/cache.inc +++ b/core/includes/cache.inc @@ -26,21 +26,7 @@ * @see Drupal\Core\Cache\CacheBackendInterface */ function cache($bin = 'cache') { - // Use the advanced drupal_static() pattern, since this is called very often. - static $drupal_static_fast; - if (!isset($drupal_static_fast)) { - $drupal_static_fast['cache'] = &drupal_static(__FUNCTION__, array()); - } - $cache_objects = &$drupal_static_fast['cache']; - - // Temporary backwards compatibiltiy layer, allow old style prefixed cache - // bin names to be passed as arguments. - $bin = str_replace('cache_', '', $bin); - - if (!isset($cache_objects[$bin])) { - $cache_objects[$bin] = CacheFactory::get($bin); - } - return $cache_objects[$bin]; + return drupal_container()->get('cache')->get($bin); } /** @@ -57,7 +43,7 @@ function cache($bin = 'cache') { * The list of tags to delete cache items for. */ function cache_delete_tags(array $tags) { - foreach (CacheFactory::getBackends() as $bin => $class) { + foreach (drupal_container()->get('cache')->getBackends() as $bin => $class) { cache($bin)->deleteTags($tags); } } @@ -76,7 +62,7 @@ function cache_delete_tags(array $tags) { * The list of tags to invalidate cache items for. */ function cache_invalidate_tags(array $tags) { - foreach (CacheFactory::getBackends() as $bin => $class) { + foreach (drupal_container()->get('cache')->getBackends() as $bin => $class) { cache($bin)->invalidateTags($tags); } } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 8f5dd68..e3ad337 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -330,6 +330,8 @@ function install_begin_request(&$install_state) { $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') ->addArgument(new Reference('config.storage')) ->addArgument(new Reference('event_dispatcher')); + $container->register('cache', 'Drupal\Core\Cache\CacheFactory') + ->addMethodCall('setContainer', array(new Reference('service_container'))); drupal_container($container); } @@ -343,7 +345,8 @@ function install_begin_request(&$install_state) { drupal_load('module', 'system'); require_once DRUPAL_ROOT . '/core/includes/cache.inc'; - $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend'); + drupal_container()->set('cache.memory', new \Drupal\Core\Cache\MemoryBackendFactory()); + $conf['cache_bin'] = 'cache.memory'; // The install process cannot use the database lock backend since the database // is not fully up, so we use a null backend implementation during the diff --git a/core/lib/Drupal/Core/Cache/CacheFactory.php b/core/lib/Drupal/Core/Cache/CacheFactory.php index da42a26..92f1b61 100644 --- a/core/lib/Drupal/Core/Cache/CacheFactory.php +++ b/core/lib/Drupal/Core/Cache/CacheFactory.php @@ -7,32 +7,66 @@ namespace Drupal\Core\Cache; +use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\DependencyInjection\ContainerInterface; + /** * Defines the cache backend factory. */ -class CacheFactory { +class CacheFactory extends ContainerAware { /** - * Instantiates a cache backend class for a given cache bin. + * Instantiated caches, keyed by bin name. + * + * @var array + */ + protected $bins = array(); + + /** + * The dependency injection container. * - * By default, this returns an instance of the - * Drupal\Core\Cache\DatabaseBackend class. + * @var \Symfony\Component\DependencyInjection\ContainerInterface + */ + protected $container; + + /** + * Implements \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer(). + */ + function setContainer(ContainerInterface $container = null) { + $this->container = $container; + } + + /** + * Instantiates a cache backend class for a given cache bin. * - * Classes implementing Drupal\Core\Cache\CacheBackendInterface can register - * themselves both as a default implementation and for specific bins. + * Classes implementing CacheBackendInterface can register themselves both as + * a default implementation and for specific bins. * * @param string $bin * The cache bin for which a cache backend object should be returned. * - * @return Drupal\Core\Cache\CacheBackendInterface + * @return \Drupal\Core\Cache\CacheBackendInterface * The cache backend object associated with the specified bin. */ - public static function get($bin) { - // Check whether there is a custom class defined for the requested bin or - // use the default 'cache' definition otherwise. - $cache_backends = self::getBackends(); - $class = isset($cache_backends[$bin]) ? $cache_backends[$bin] : $cache_backends['cache']; - return new $class($bin); + public function get($bin) { + global $conf; + if (!isset($this->bins[$bin])) { + if (isset($conf['cache_bin_' . $bin])) { + $service_name = $conf['cache_bin_' . $bin]; + } + elseif (isset($conf['cache_bin'])) { + $service_name = $conf['cache_bin']; + } + else { + $service_name = 'cache.database'; + } + // Fall back to database if the service does not exist. + if (!$this->container->has($service_name)) { + $service_name = 'cache.database'; + } + $this->bins[$bin] = $this->container->get($service_name)->get($bin); + } + return $this->bins[$bin]; } /** @@ -42,7 +76,7 @@ public static function get($bin) { * An associative array with cache bins as keys, and backend class names as * value. */ - public static function getBackends() { + public function getBackends() { // @todo Improve how cache backend classes are defined. Cannot be // configuration, since e.g. the CachedStorage config storage controller // requires the definition in its constructor already. @@ -52,5 +86,4 @@ public static function getBackends() { $cache_backends += array('cache' => 'Drupal\Core\Cache\DatabaseBackend'); return $cache_backends; } - } diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php index e4d86c6..09168f1 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php @@ -7,14 +7,14 @@ namespace Drupal\Core\Cache; -use Drupal\Core\Database\Database; -use Drupal\Core\Database\DatabaseException; +use Drupal\Core\Database\Connection; /** * Defines a default cache implementation. * * This is Drupal's default cache implementation. It uses the database to store - * cached data. Each cache bin corresponds to a database table by the same name. + * cached data. Each cache bin corresponds to a database table prefixed by + * cache_. */ class DatabaseBackend implements CacheBackendInterface { @@ -24,12 +24,22 @@ class DatabaseBackend implements CacheBackendInterface { protected $bin; /** - * Constructs a DatabaseBackend object. + * A database connection object. + * + * @var \Drupal\Core\Database\Connection + */ + protected $connection; + + /** + * Constructs a new cache database backend. * * @param string $bin - * The cache bin for which the object is created. + * (optional) The cache bin that should be used. + * @param \Drupal\Core\Database\Connection $connection + * The database connection that should be used. */ - public function __construct($bin) { + function __construct($bin, Connection $connection) { + $this->connection = $connection; // All cache tables should be prefixed with 'cache_', except for the // default 'cache' bin. if ($bin != 'cache') { @@ -58,7 +68,7 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) { // is used here only due to the performance overhead we would incur // otherwise. When serving an uncached page, the overhead of using // ::select() is a much smaller proportion of the request. - $result = Database::getConnection()->query('SELECT cid, data, created, expire, serialized, tags, checksum_invalidations, checksum_deletions FROM {' . Database::getConnection()->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids)); + $result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum_invalidations, checksum_deletions FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => $cids)); $cache = array(); foreach ($result as $item) { $item = $this->prepareItem($item, $allow_invalid); @@ -142,7 +152,7 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN $fields['serialized'] = 0; } - Database::getConnection()->merge($this->bin) + $this->connection->merge($this->bin) ->key(array('cid' => $cid)) ->fields($fields) ->execute(); @@ -152,7 +162,7 @@ public function set($cid, $data, $expire = CacheBackendInterface::CACHE_PERMANEN * Implements Drupal\Core\Cache\CacheBackendInterface::delete(). */ public function delete($cid) { - Database::getConnection()->delete($this->bin) + $this->connection->delete($this->bin) ->condition('cid', $cid) ->execute(); } @@ -163,7 +173,7 @@ public function delete($cid) { public function deleteMultiple(array $cids) { // Delete in chunks when a large array is passed. do { - Database::getConnection()->delete($this->bin) + $this->connection->delete($this->bin) ->condition('cid', array_splice($cids, 0, 1000), 'IN') ->execute(); } @@ -177,7 +187,7 @@ public function deleteTags(array $tags) { $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache'); foreach ($this->flattenTags($tags) as $tag) { unset($tag_cache[$tag]); - Database::getConnection()->merge('cache_tags') + $this->connection->merge('cache_tags') ->insertFields(array('deletions' => 1)) ->expression('deletions', 'deletions + 1') ->key(array('tag' => $tag)) @@ -189,14 +199,14 @@ public function deleteTags(array $tags) { * Implements Drupal\Core\Cache\CacheBackendInterface::deleteAll(). */ public function deleteAll() { - Database::getConnection()->truncate($this->bin)->execute(); + $this->connection->truncate($this->bin)->execute(); } /** * Implements Drupal\Core\Cache\CacheBackendInterface::deleteExpired(). */ public function deleteExpired() { - Database::getConnection()->delete($this->bin) + $this->connection->delete($this->bin) ->condition('expire', CacheBackendInterface::CACHE_PERMANENT, '<>') ->condition('expire', REQUEST_TIME, '<') ->execute(); @@ -215,7 +225,7 @@ public function invalidate($cid) { public function invalidateMultiple(array $cids) { // Update in chunks when a large array is passed. do { - Database::getConnection()->update($this->bin) + $this->connection->update($this->bin) ->fields(array('expire' => REQUEST_TIME - 1)) ->condition('cid', array_splice($cids, 0, 1000), 'IN') ->execute(); @@ -230,7 +240,7 @@ public function invalidateTags(array $tags) { $tag_cache = &drupal_static('Drupal\Core\Cache\CacheBackendInterface::tagCache'); foreach ($this->flattenTags($tags) as $tag) { unset($tag_cache[$tag]); - Database::getConnection()->merge('cache_tags') + $this->connection->merge('cache_tags') ->insertFields(array('invalidations' => 1)) ->expression('invalidations', 'invalidations + 1') ->key(array('tag' => $tag)) @@ -242,7 +252,7 @@ public function invalidateTags(array $tags) { * Implements Drupal\Core\Cache\CacheBackendInterface::invalidateAll(). */ public function invalidateAll() { - Database::getConnection()->update($this->bin) + $this->connection->update($this->bin) ->fields(array('expire' => REQUEST_TIME - 1)) ->execute(); } @@ -303,7 +313,7 @@ protected function checksumTags($flat_tags) { $query_tags = array_diff($flat_tags, array_keys($tag_cache)); if ($query_tags) { - $db_tags = Database::getConnection()->query('SELECT tag, invalidations, deletions FROM {cache_tags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllAssoc('tag', \PDO::FETCH_ASSOC); + $db_tags = $this->connection->query('SELECT tag, invalidations, deletions FROM {cache_tags} WHERE tag IN (:tags)', array(':tags' => $query_tags))->fetchAllAssoc('tag', \PDO::FETCH_ASSOC); $tag_cache += $db_tags; // Fill static cache with empty objects for tags not found in the database. @@ -323,7 +333,7 @@ protected function checksumTags($flat_tags) { */ public function isEmpty() { $this->garbageCollection(); - $query = Database::getConnection()->select($this->bin); + $query = $this->connection->select($this->bin); $query->addExpression('1'); $result = $query->range(0, 1) ->execute() diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php new file mode 100644 index 0000000..fda7d13 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php @@ -0,0 +1,40 @@ +connection = $connection; + } + + /** + * Constructs a new cache database backend for a given bin name. + * + * @param string $bin + * The cache bin for which a cache backend object should be returned. + * + * @return Drupal\Core\Cache\CacheBackendInterface + * The cache backend object associated with the specified bin. + */ + public function get($bin) { + return new DatabaseBackend($bin, $this->connection); + } +} diff --git a/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php new file mode 100644 index 0000000..6a9b132 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/MemoryBackendFactory.php @@ -0,0 +1,27 @@ +register('cache.config', 'Drupal\Core\Cache\CacheBackendInterface') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryService('cache') ->setFactoryMethod('get') ->addArgument('config'); @@ -50,6 +50,17 @@ public function build(ContainerBuilder $container) { ->addArgument(new Reference('config.cachedstorage.storage')) ->addArgument(new Reference('cache.config')); + // Register the cache factory. + $container->register('cache', 'Drupal\Core\Cache\CacheFactory') + ->addMethodCall('setContainer', array(new Reference('service_container'))); + $container + ->register('cache.database', 'Drupal\Core\Cache\DatabaseBackendFactory') + ->addArgument(new Reference('database')); + + // Register configuration object factory. + $container->register('config.subscriber.globalconf', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber'); + $container->register('dispatcher', 'Symfony\Component\EventDispatcher\EventDispatcher') + ->addMethodCall('addSubscriber', array(new Reference('config.subscriber.globalconf'))); $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory') ->addArgument(new Reference('config.storage')) ->addArgument(new Reference('event_dispatcher')) @@ -141,7 +152,7 @@ public function build(ContainerBuilder $container) { $container ->register('cache.path', 'Drupal\Core\Cache\CacheBackendInterface') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryService('cache') ->setFactoryMethod('get') ->addArgument('path'); diff --git a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php index b7186b0..63fc614 100644 --- a/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php +++ b/core/modules/block/lib/Drupal/block/Plugin/Type/BlockManager.php @@ -30,7 +30,7 @@ public function __construct() { $this->discovery = new AnnotatedClassDiscovery('block', 'block'); $this->discovery = new DerivativeDiscoveryDecorator($this->discovery); $this->discovery = new AlterDecorator($this->discovery, 'block'); - $this->discovery = new CacheDecorator($this->discovery, 'block_plugins:' . language(LANGUAGE_TYPE_INTERFACE)->langcode, 'cache_block'); + $this->discovery = new CacheDecorator($this->discovery, 'block_plugins:' . language(LANGUAGE_TYPE_INTERFACE)->langcode, 'block'); $this->factory = new DefaultFactory($this); $this->mapper = new ConfigMapper($this); } diff --git a/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php b/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php index 40affcc..f1ae495 100644 --- a/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php +++ b/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php @@ -22,7 +22,7 @@ class RdfBundle extends Bundle { public function build(ContainerBuilder $container) { // Site schema type cache. $container->register('cache.rdf.site_schema.types', 'Drupal\Core\Cache\CacheBackendInterface') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryService('cache') ->setFactoryMethod('get') ->addArgument('cache'); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php index 96e9017..f35056b 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php @@ -133,7 +133,8 @@ public function containerBuild($container) { // Keep the container object around for tests. $this->container = $container; $conf['lock_backend'] = 'Drupal\Core\Lock\NullLockBackend'; - $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend'); + $this->container->register('cache.memory', 'Drupal\Core\Cache\MemoryBackendFactory'); + $conf['cache_bin'] = 'cache.memory'; $container ->register('config.storage', 'Drupal\Core\Config\FileStorage') ->addArgument($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index 5ac4017..86df520 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -809,7 +809,7 @@ protected function setUp() { $batch = $this->originalBatch; // Revert install_begin_request() cache and lock service overrides. - unset($conf['cache_classes']); + unset($conf['cache_bin']); unset($conf['lock_backend']); // Set path variables. diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php index f301257..c36506d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Cache; use Drupal\Core\Cache\DatabaseBackend; +use Drupal\Core\Database\Database; /** * Tests DatabaseBackend using GenericCacheBackendUnitTestBase. @@ -29,7 +30,7 @@ public static function getInfo() { * A new DatabaseBackend object. */ protected function createCacheBackend($bin) { - return new DatabaseBackend($bin); + return new DatabaseBackend($bin, Database::getConnection()); } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorTest.php index 327e46e..739014d 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/CacheDecoratorTest.php @@ -45,7 +45,8 @@ public function setUp() { // Use a non-db cache backend, so that we can use DiscoveryTestBase (which // extends UnitTestBase). - $conf['cache_classes'][$this->cacheBin] = 'Drupal\Core\Cache\MemoryBackend'; + $this->container->register('cache.memory', 'Drupal\Core\Cache\MemoryBackendFactory'); + $conf['cache_bin_' . $this->cacheBin] = 'cache.memory'; // Create discovery objects to test. $this->emptyDiscovery = new StaticDiscovery(); diff --git a/core/modules/views/lib/Drupal/views/ViewsBundle.php b/core/modules/views/lib/Drupal/views/ViewsBundle.php index 544b8c3..39cb4e2 100644 --- a/core/modules/views/lib/Drupal/views/ViewsBundle.php +++ b/core/modules/views/lib/Drupal/views/ViewsBundle.php @@ -28,7 +28,7 @@ public function build(ContainerBuilder $container) { $container ->register('cache.views_info', 'Drupal\Core\Cache\CacheBackendInterface') - ->setFactoryClass('Drupal\Core\Cache\CacheFactory') + ->setFactoryService('cache') ->setFactoryMethod('get') ->addArgument('views_info');