diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 214ce28..b683347 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -2010,6 +2010,28 @@ function install_check_requirements($install_state) { ); } } + + // Check that the services.yml file is read and writable. + $yml_file = $conf_path . '/services.yml'; + $readable = drupal_verify_install_file($yml_file, FILE_READABLE); + $writable = drupal_verify_install_file($yml_file, FILE_WRITABLE); + + if (!$readable) { + $requirements['services file readable'] = array( + 'title' => t('Services file'), + 'value' => t('The services.yml file is not readable.'), + 'severity' => REQUIREMENT_ERROR, + 'description' => t('@drupal requires read permissions to %file at all times. If you are unsure how to grant file permissions, consult the online handbook.', array('@drupal' => drupal_install_profile_distribution_name(), '%file' => $yml_file, '@handbook_url' => 'http://drupal.org/server-permissions')), + ); + } + if (!$writable) { + $requirements['service file writable'] = array( + 'title' => t('Services file'), + 'value' => t('The service.yml file is not writable.'), + 'severity' => REQUIREMENT_ERROR, + 'description' => t('The @drupal installer requires write permissions to %file during the installation process. If you are unsure how to grant file permissions, consult the online handbook.', array('@drupal' => drupal_install_profile_distribution_name(), '%file' => $yml_file, '@handbook_url' => 'http://drupal.org/server-permissions')), + ); + } } return $requirements; } diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index a7f5ef4..42c7dea 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\CacheContextsPass; use Drupal\Core\Cache\ListCacheBinsPass; +use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass; @@ -49,6 +50,8 @@ public function register(ContainerBuilder $container) { // list-building passes are operating on the post-alter services list. $container->addCompilerPass(new ModifyServiceDefinitionsPass()); + $container->addCompilerPass(new BackendCompilerPass()); + // Collect tagged handler services as method calls on consumer services. $container->addCompilerPass(new TaggedHandlersPass()); diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php new file mode 100644 index 0000000..e4aedcb --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/BackendCompilerPass.php @@ -0,0 +1,63 @@ +hasParameter('default_backend') ? $container->getParameter('default_backend') : NULL; + // No default backend was configured, so continue as normal. + if (!isset($default_backend)) { + return; + } + + foreach ($container->findTaggedServiceIds('backend_overridable') as $id => $attributes) { + // If the service is already an alias it is not the original backend, so + // we don't want to fallback to other storages any longer. + if ($container->hasAlias($id)) { + continue; + } + if ($container->hasDefinition("$default_backend.$id") || $container->hasAlias("$default_backend.$id")) { + $container->setAlias($id, new Alias("$default_backend.$id")); + } + } + } + +} diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php index 23f0d03..c233392 100644 --- a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php +++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Installer\Form; +use Drupal\Component\Serialization\Yaml; use Drupal\Component\Utility\Crypt; use Drupal\Core\Database\Database; use Drupal\Core\Form\FormBase; @@ -156,6 +157,12 @@ public function submitForm(array &$form, array &$form_state) { drupal_rewrite_settings($settings); + $conf_path = './' . conf_path(FALSE); + $services_file = $conf_path . '/services.yml'; + // @TODO Should we put some logic in here to ensure that the file is read + // and writable? + file_put_contents($services_file, Yaml::encode(array('parameters' => array('default_backend' => $database['driver'])))); + // Add the config directories to settings.php. drupal_install_config_directories(); diff --git a/core/modules/system/src/Tests/Installer/InstallerTest.php b/core/modules/system/src/Tests/Installer/InstallerTest.php index 760a942..ab5b358 100644 --- a/core/modules/system/src/Tests/Installer/InstallerTest.php +++ b/core/modules/system/src/Tests/Installer/InstallerTest.php @@ -30,6 +30,9 @@ public function testInstaller() { $this->assertRaw(t('Congratulations, you installed @drupal!', array( '@drupal' => drupal_install_profile_distribution_name(), ))); + + // Ensures that the services YML file got written and read. + $this->assertEqual(\Drupal::getContainer()->getParameter('default_backend'), \Drupal::database()->driver()); } } diff --git a/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php b/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php new file mode 100644 index 0000000..6f726c1 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/BackendCompilerPassTest.php @@ -0,0 +1,93 @@ +backendPass = new BackendCompilerPass(); + } + + /** + * Tests the process method. + * + * @param string $expected_class + * The expected used class. + * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container + * The container. + * + * @dataProvider providerTestProcess + * + * @covers ::process + */ + public function testProcess($expected_class, ContainerBuilder $container) { + $this->backendPass->process($container); + + $this->assertInstanceOf($expected_class, $container->get('service')); + } + + /** + * Provides test data for testProcess(). + * + * @return array + */ + public function providerTestProcess() { + $data = array(); + // Add a container with no set default_backend. + $container = new ContainerBuilder(); + $prefix = '\\' . __NAMESPACE__ . '\\'; + $container->setDefinition('service', (new Definition($prefix . 'ServiceClassDefault'))->addTag('backend_overridable')); + $container->setDefinition('mysql.service', new Definition($prefix . 'ServiceClassMysql')); + + $data[] = array($prefix . 'ServiceClassDefault', $container); + + // Set the default_backend so the mysql service should be used. + $container = clone $container; + $container->setParameter('default_backend', 'mysql'); + $data[] = array($prefix . 'ServiceClassMysql', $container); + + // Configure a manual alias for the service, so ensure that it is not + // overridden by the default backend. + $container = clone $container; + $container->setDefinition('mariadb.service', new Definition($prefix . 'ServiceClassMariaDb')); + $container->setAlias('service', new Alias('mariadb.service')); + $data[] = array($prefix . 'ServiceClassMariaDb', $container); + + return $data; + } + +} + +class ServiceClassDefault { +} + +class ServiceClassMysql extends ServiceClassDefault { +} + +class ServiceClassMariaDb extends ServiceClassMysql { +}