diff --git a/core/lib/Drupal/Core/Cache/CacheFactory.php b/core/lib/Drupal/Core/Cache/CacheFactory.php index d029cc1..49ebdef 100644 --- a/core/lib/Drupal/Core/Cache/CacheFactory.php +++ b/core/lib/Drupal/Core/Cache/CacheFactory.php @@ -65,7 +65,7 @@ public function __construct(Settings $settings, array $default_bin_backends = [] public function get($bin) { $cache_settings = $this->settings->get('cache'); // First, look for a cache bin specific setting. - if (isset($cache_settings['bins'][$bin])) { + if (isset($cache_settings['bins'][$bin]) && $this->container->has($cache_settings['bins'][$bin])) { $service_name = $cache_settings['bins'][$bin]; } // Second, use the default backend specified by the cache bin. @@ -73,7 +73,7 @@ public function get($bin) { $service_name = $this->defaultBinBackends[$bin]; } // Third, use configured default backend. - elseif (isset($cache_settings['default'])) { + elseif (isset($cache_settings['default']) && $this->container->has($cache_settings['default'])) { $service_name = $cache_settings['default']; } else { diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php index 1016e5a..08195f0 100644 --- a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php @@ -66,6 +66,17 @@ public function __construct(Settings $settings = NULL, $consistent_service_name } /** + * Getter for the consistent service name. + * + * @return string + * The service name of the consistent backend factory. + */ + public function getConsistentServiceName() { + return ($this->consistentServiceName && $this->container->has($this->consistentServiceName)) ? + $this->consistentServiceName : 'cache.backend.database'; + } + + /** * Instantiates a chained, fast cache backend class for a given cache bin. * * @param string $bin @@ -79,13 +90,13 @@ public function get($bin) { // otherwise, just return the consistent backend directly. if (isset($this->fastServiceName)) { return new ChainedFastBackend( - $this->container->get($this->consistentServiceName)->get($bin), + $this->container->get($this->getConsistentServiceName())->get($bin), $this->container->get($this->fastServiceName)->get($bin), $bin ); } else { - return $this->container->get($this->consistentServiceName)->get($bin); + return $this->container->get($this->getConsistentServiceName())->get($bin); } } diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 1838326..100dec0 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -22,6 +22,7 @@ use Drupal\Core\Site\Settings; use Drupal\Core\StreamWrapper\PrivateStream; use Drupal\Core\StreamWrapper\PublicStream; +use Drupal\Core\StringTranslation\PluralTranslatableMarkup; use Drupal\system\SystemRequirements; use Symfony\Component\HttpFoundation\Request; @@ -283,6 +284,33 @@ function system_requirements($phase) { $requirements['php_opcache']['title'] = t('PHP OPcode caching'); } + if ($phase == 'install' || $phase == 'runtime') { + // Check that the required cache backends exist. + $cache_settings = Settings::get('cache'); + $missing_cache_backends = []; + if (isset($cache_settings['bins'])) { + foreach ($cache_settings['bins'] as $bin => $backend) { + if (!Drupal::getContainer()->has($cache_settings['bins'][$bin])) { + $missing_cache_backends[] = $cache_settings['bins'][$bin]; + } + } + } + if (isset($cache_settings['default']) && !Drupal::getContainer()->has($cache_settings['default'])) { + $missing_cache_backends[] = $cache_settings['default']; + } + if ($missing_cache_backends) { + $requirements['cache_backend'] = [ + 'title' => t('Cache Backend'), + 'value' => t('Missing'), + 'severity' => REQUIREMENT_WARNING, + 'description' => new PluralTranslatableMarkup(count($missing_cache_backends), + 'The configured Cache Backend %backend is not available.', + 'The configured Cache Backends %backend are not available.', + ['%backend' => implode(', ', $missing_cache_backends)]), + ]; + } + } + if ($phase != 'update') { // Test whether we have a good source of random bytes. $requirements['php_random_bytes'] = [ diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheFactoryTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheFactoryTest.php index 0c43bb2..c969dd6 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheFactoryTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheFactoryTest.php @@ -145,4 +145,66 @@ public function testCacheFactoryWithSpecifiedPerBinBackend() { $this->assertSame($render_bin, $actual_bin); } + /** + * Test that the cache factory falls back to the built-in default service if specified bin service does not exist. + * + * @covers ::__construct + * @covers ::get + */ + public function testCacheFactoryBinBackendServiceExist() { + $settings = new Settings(array( + 'cache' => array( + 'bins' => array( + 'render' => 'cache.backend.custom', + ), + ), + )); + $cache_factory = new CacheFactory($settings); + + $container = new ContainerBuilder(); + $cache_factory->setContainer($container); + + $builtin_default_backend_factory = $this->getMock('\Drupal\Core\Cache\CacheFactoryInterface'); + $container->set('cache.backend.database', $builtin_default_backend_factory); + + $render_bin = $this->getMock('\Drupal\Core\Cache\CacheBackendInterface'); + $builtin_default_backend_factory->expects($this->once()) + ->method('get') + ->with('render') + ->will($this->returnValue($render_bin)); + + $actual_bin = $cache_factory->get('render'); + $this->assertSame($render_bin, $actual_bin); + } + + /** + * Test that the cache factory falls back to the built-in default service if specified default bin service does not exist. + * + * @covers ::__construct + * @covers ::get + */ + public function testCacheFactoryBinBackendDefaultServiceExist() { + $settings = new Settings(array( + 'cache' => array( + 'default' => 'cache.backend.custom', + ), + )); + $cache_factory = new CacheFactory($settings); + + $container = new ContainerBuilder(); + $cache_factory->setContainer($container); + + $builtin_default_backend_factory = $this->getMock('\Drupal\Core\Cache\CacheFactoryInterface'); + $container->set('cache.backend.database', $builtin_default_backend_factory); + + $render_bin = $this->getMock('\Drupal\Core\Cache\CacheBackendInterface'); + $builtin_default_backend_factory->expects($this->once()) + ->method('get') + ->with('render') + ->will($this->returnValue($render_bin)); + + $actual_bin = $cache_factory->get('render'); + $this->assertSame($render_bin, $actual_bin); + } + }