From 4fb0f9d8fd5269e96d04fe7650ee6e6ff1d6b585 Mon Sep 17 00:00:00 2001 From: webchick <drupal@webchick.net> Date: Sat, 23 Aug 2014 13:19:53 -0700 Subject: [PATCH] Issue #2251113 by alexpott, damiankloip, Crell, Wim Leers, dawehner, sun: Use container parameters instead of settings. --- core/INSTALL.txt | 17 +- core/core.services.yml | 32 ++- core/includes/install.core.inc | 188 +++++++++++------- core/lib/Drupal/Core/CoreServiceProvider.php | 45 +---- .../DependencyInjection/YamlFileLoader.php | 8 + core/lib/Drupal/Core/DrupalKernel.php | 3 +- .../Installer/InstallerServiceProvider.php | 5 + .../Core/KeyValueStore/KeyValueFactory.php | 28 +-- .../Drupal/Core/Template/TwigEnvironment.php | 12 +- .../modules/simpletest/src/KernelTestBase.php | 7 +- core/modules/simpletest/src/WebTestBase.php | 23 +++ .../DatabaseStorageExpirableTest.php | 5 +- .../KeyValueStore/DatabaseStorageTest.php | 5 +- .../Tests/KeyValueStore/MemoryStorageTest.php | 5 +- .../Tests/KeyValueStore/StorageTestBase.php | 4 +- .../src/Tests/Theme/TwigDebugMarkupTest.php | 8 +- .../src/Tests/Theme/TwigSettingsTest.php | 24 ++- core/modules/system/system.install | 8 +- sites/default/default.services.yml | 53 +++++ sites/example.settings.local.php | 53 ----- 20 files changed, 317 insertions(+), 216 deletions(-) create mode 100644 sites/default/default.services.yml diff --git a/core/INSTALL.txt b/core/INSTALL.txt index 18804738344c..f985620ab1fa 100644 --- a/core/INSTALL.txt +++ b/core/INSTALL.txt @@ -147,26 +147,30 @@ INSTALLATION b. Missing settings file. - Drupal will try to automatically create a settings.php configuration file, - which is normally in the directory sites/default (to avoid problems when - upgrading, Drupal is not packaged with this file). If auto-creation fails, - you will need to create this file yourself, using the file - sites/default/default.settings.php as a template. + Drupal will try to automatically create settings.php and services.yml + files, which are normally in the directory sites/default (to avoid + problems when upgrading, Drupal is not packaged with this file). If + auto-creation of either file fails, you will need to create the file + yourself. Use the template sites/default/default.settings.php or + sites/default/default.services.yml respectively. For example, on a Unix/Linux command line, you can make a copy of the - default.settings.php file with the command: + default.settings.php and default.services.yml files with the commands: cp sites/default/default.settings.php sites/default/settings.php + cp sites/default/default.services.yml sites/default/services.yml Next, grant write privileges to the file to everyone (including the web server) with the command: chmod a+w sites/default/settings.php + chmod a+w sites/default/services.yml Be sure to set the permissions back after the installation is finished! Sample command: chmod go-w sites/default/settings.php + chmod go-w sites/default/services.yml c. Write permissions after install. @@ -176,6 +180,7 @@ INSTALLATION from a Unix/Linux command line: chmod go-w sites/default/settings.php + chmod go-w sites/default/services.yml chmod go-w sites/default 4. Verify that the site is working. diff --git a/core/core.services.yml b/core/core.services.yml index dec001f6ee96..c26834cc2315 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1,3 +1,9 @@ +parameters: + twig.config: {} + factory.keyvalue: + default: keyvalue.database + factory.keyvalue.expirable: + default: keyvalue.expirable.database services: cache_factory: class: Drupal\Core\Cache\CacheFactory @@ -156,13 +162,13 @@ services: arguments: ['@request_stack', '@url_generator'] keyvalue: class: Drupal\Core\KeyValueStore\KeyValueFactory - arguments: ['@service_container', '@settings'] + arguments: ['@service_container', '%factory.keyvalue%'] keyvalue.database: class: Drupal\Core\KeyValueStore\KeyValueDatabaseFactory arguments: ['@serialization.phpserialize', '@database'] keyvalue.expirable: class: Drupal\Core\KeyValueStore\KeyValueExpirableFactory - arguments: ['@service_container', '@settings'] + arguments: ['@service_container', '%factory.keyvalue.expirable%'] keyvalue.expirable.database: class: Drupal\Core\KeyValueStore\KeyValueDatabaseExpirableFactory arguments: ['@serialization.phpserialize', '@database'] @@ -922,6 +928,28 @@ services: arguments: ['@module_handler'] info_parser: class: Drupal\Core\Extension\InfoParser + twig: + class: Drupal\Core\Template\TwigEnvironment + arguments: ['@twig.loader', '@module_handler', '@theme_handler', '%twig.config%'] + tags: + - { name: service_collector, tag: 'twig.extension', call: addExtension } + twig.extension: + class: Drupal\Core\Template\TwigExtension + tags: + - { name: twig.extension, priority: 100 } + calls: + - [setGenerators, ['@url_generator']] + # @todo Figure out what to do about debugging functions. + # @see http://drupal.org/node/1804998 + twig.extension.debug: + class: Twig_Extension_Debug + tags: + - { name: twig.extension } + twig.loader: + alias: twig.loader.filesystem + twig.loader.filesystem: + class: Twig_Loader_Filesystem + arguments: ['%app.root%'] element_info: alias: plugin.manager.element_info file.mime_type.guesser: diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 4cdc52945ee0..3a877a87c2b0 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -1886,67 +1886,88 @@ function install_check_requirements($install_state) { // Check the profile requirements. $requirements = drupal_check_profile($profile, $install_state); - // If Drupal is not set up already, we need to create a settings file. - if (!$install_state['settings_verified']) { + if ($install_state['settings_verified']) { + return $requirements; + } + + // If Drupal is not set up already, we need to try to create the default + // settings and services files. + $default_files = array(); + $default_files['settings.php'] = array( + 'file' => 'settings.php', + 'file_default' => 'default.settings.php', + 'title_default' => t('Default settings file'), + 'description_default' => t('The default settings file does not exist.'), + 'title' => t('Settings file'), + ); + $default_files['services.yml'] = array( + 'file' => 'services.yml', + 'file_default' => 'default.services.yml', + 'title_default' => t('Default services file'), + 'description_default' => t('The default services file does not exist.'), + 'title' => t('Services file'), + ); + + foreach ($default_files as $default_file_info) { $readable = FALSE; $writable = FALSE; $conf_path = './' . conf_path(FALSE); - $settings_file = $conf_path . '/settings.php'; - $default_settings_file = './sites/default/default.settings.php'; - $file = $conf_path; + $file = $conf_path . "/{$default_file_info['file']}"; + $default_file = "./sites/default/{$default_file_info['file_default']}"; $exists = FALSE; // Verify that the directory exists. if (drupal_verify_install_file($conf_path, FILE_EXIST, 'dir')) { - // Check if a settings.php file already exists. - $file = $settings_file; - if (drupal_verify_install_file($settings_file, FILE_EXIST)) { + if (drupal_verify_install_file($file, FILE_EXIST)) { // If it does, make sure it is writable. - $readable = drupal_verify_install_file($settings_file, FILE_READABLE); - $writable = drupal_verify_install_file($settings_file, FILE_WRITABLE); + $readable = drupal_verify_install_file($file, FILE_READABLE); + $writable = drupal_verify_install_file($file, FILE_WRITABLE); $exists = TRUE; } } - // If default.settings.php does not exist, or is not readable, throw an - // error. - if (!drupal_verify_install_file($default_settings_file, FILE_EXIST|FILE_READABLE)) { - $requirements['default settings file exists'] = array( - 'title' => t('Default settings file'), - 'value' => t('The default settings file does not exist.'), - 'severity' => REQUIREMENT_ERROR, - 'description' => t('The @drupal installer requires that the %default-file file not be modified in any way from the original download.', array('@drupal' => drupal_install_profile_distribution_name(), '%default-file' => $default_settings_file)), + // If the default $default_file does not exist, or is not readable, + // report an error. + if (!drupal_verify_install_file($default_file, FILE_EXIST | FILE_READABLE)) { + $requirements["default $file file exists"] = array( + 'title' => $default_file_info['title_default'], + 'value' => $default_file_info['description_default'], + 'severity' => REQUIREMENT_ERROR, + 'description' => t('The @drupal installer requires that the %default-file file not be modified in any way from the original download.', array( + '@drupal' => drupal_install_profile_distribution_name(), + '%default-file' => $default_file + )), ); } - // Otherwise, if settings.php does not exist yet, we can try to copy - // default.settings.php to create it. + // Otherwise, if $file does not exist yet, we can try to copy + // $default_file to create it. elseif (!$exists) { - $copied = drupal_verify_install_file($conf_path, FILE_EXIST|FILE_WRITABLE, 'dir') && @copy($default_settings_file, $settings_file); + $copied = drupal_verify_install_file($conf_path, FILE_EXIST | FILE_WRITABLE, 'dir') && @copy($default_file, $file); if ($copied) { - // If the new settings file has the same owner as default.settings.php, - // this means default.settings.php is owned by the webserver user. - // This is an inherent security weakness because it allows a malicious - // webserver process to append arbitrary PHP code and then execute it. - // However, it is also a common configuration on shared hosting, and - // there is nothing Drupal can do to prevent it. In this situation, - // having settings.php also owned by the webserver does not introduce - // any additional security risk, so we keep the file in place. - if (fileowner($default_settings_file) === fileowner($settings_file)) { - $readable = drupal_verify_install_file($settings_file, FILE_READABLE); - $writable = drupal_verify_install_file($settings_file, FILE_WRITABLE); + // If the new $file file has the same owner as $default_file this means + // $default_file is owned by the webserver user. This is an inherent + // security weakness because it allows a malicious webserver process to + // append arbitrary PHP code and then execute it. However, it is also a + // common configuration on shared hosting, and there is nothing Drupal + // can do to prevent it. In this situation, having $file also owned by + // the webserver does not introduce any additional security risk, so we + // keep the file in place. + if (fileowner($default_file) === fileowner($file)) { + $readable = drupal_verify_install_file($file, FILE_READABLE); + $writable = drupal_verify_install_file($file, FILE_WRITABLE); $exists = TRUE; } - // If settings.php and default.settings.php have different owners, this - // probably means the server is set up "securely" (with the webserver - // running as its own user, distinct from the user who owns all the - // Drupal PHP files), although with either a group or world writable - // sites directory. Keeping settings.php owned by the webserver would - // therefore introduce a security risk. It would also cause a usability - // problem, since site owners who do not have root access to the file - // system would be unable to edit their settings file later on. We - // therefore must delete the file we just created and force the - // administrator to log on to the server and create it manually. + // If $file and $default_file have different owners, this probably means + // the server is set up "securely" (with the webserver running as its + // own user, distinct from the user who owns all the Drupal PHP files), + // although with either a group or world writable sites directory. + // Keeping $file owned by the webserver would therefore introduce a + // security risk. It would also cause a usability problem, since site + // owners who do not have root access to the file system would be unable + // to edit their settings file later on. We therefore must delete the + // file we just created and force the administrator to log on to the + // server and create it manually. else { - $deleted = @drupal_unlink($settings_file); + $deleted = @drupal_unlink($file); // We expect deleting the file to be successful (since we just // created it ourselves above), but if it fails somehow, we set a // variable so we can display a one-time error message to the @@ -1956,57 +1977,76 @@ function install_check_requirements($install_state) { $exists = !$deleted; if ($exists) { $settings_file_ownership_error = TRUE; - $readable = drupal_verify_install_file($settings_file, FILE_READABLE); - $writable = drupal_verify_install_file($settings_file, FILE_WRITABLE); + $readable = drupal_verify_install_file($file, FILE_READABLE); + $writable = drupal_verify_install_file($file, FILE_WRITABLE); } } } } - // If settings.php does not exist, throw an error. + // If the $file does not exist, throw an error. if (!$exists) { - $requirements['settings file exists'] = array( - 'title' => t('Settings file'), - 'value' => t('The settings file does not exist.'), - 'severity' => REQUIREMENT_ERROR, - 'description' => t('The @drupal installer requires that you create a settings file as part of the installation process. Copy the %default_file file to %file. More details about installing Drupal are available in <a href="@install_txt">INSTALL.txt</a>.', array('@drupal' => drupal_install_profile_distribution_name(), '%file' => $file, '%default_file' => $default_settings_file, '@install_txt' => base_path() . 'core/INSTALL.txt')), + $requirements["$file file exists"] = array( + 'title' => $default_file_info['title'], + 'value' => t('The %file does not exist.', array('%file' => $default_file_info['title'])), + 'severity' => REQUIREMENT_ERROR, + 'description' => t('The @drupal installer requires that you create a %file as part of the installation process. Copy the %default_file file to %file. More details about installing Drupal are available in <a href="@install_txt">INSTALL.txt</a>.', array( + '@drupal' => drupal_install_profile_distribution_name(), + '%file' => $file, + '%default_file' => $default_file, + '@install_txt' => base_path() . 'core/INSTALL.txt' + )), ); } else { - $requirements['settings file exists'] = array( - 'title' => t('Settings file'), - 'value' => t('The %file file exists.', array('%file' => $file)), + $requirements["$file file exists"] = array( + 'title' => $default_file_info['title'], + 'value' => t('The %file exists.', array('%file' => $file)), ); - // If settings.php is not readable, throw an error. + // If the $file is not readable, throw an error. if (!$readable) { - $requirements['settings file readable'] = array( - 'title' => t('Settings file'), - 'value' => t('The settings 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 <a href="@handbook_url">online handbook</a>.', array('@drupal' => drupal_install_profile_distribution_name(), '%file' => $file, '@handbook_url' => 'http://drupal.org/server-permissions')), + $requirements["$file file readable"] = array( + 'title' => $default_file_info['title'], + 'value' => t('The %file is not readable.', array('%file' => $default_file_info['title'])), + '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 <a href="@handbook_url">online handbook</a>.', array( + '@drupal' => drupal_install_profile_distribution_name(), + '%file' => $file, + '@handbook_url' => 'http://drupal.org/server-permissions' + )), ); } - // If settings.php is not writable, throw an error. + // If the $file is not writable, throw an error. if (!$writable) { - $requirements['settings file writable'] = array( - 'title' => t('Settings file'), - 'value' => t('The settings 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 <a href="@handbook_url">online handbook</a>.', array('@drupal' => drupal_install_profile_distribution_name(), '%file' => $file, '@handbook_url' => 'http://drupal.org/server-permissions')), + $requirements["$file file writeable"] = array( + 'title' => $default_file_info['title'], + 'value' => t('The %file is not writable.', array('%file' => $default_file_info['title'])), + '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 <a href="@handbook_url">online handbook</a>.', array( + '@drupal' => drupal_install_profile_distribution_name(), + '%file' => $file, + '@handbook_url' => 'http://drupal.org/server-permissions' + )), ); } else { - $requirements['settings file'] = array( - 'title' => t('Settings file'), - 'value' => t('The settings file is writable.'), + $requirements["$file file"] = array( + 'title' => $default_file_info['title'], + 'value' => t('The @file is writable.', array('@file' => $default_file_info['title'])), ); } if (!empty($settings_file_ownership_error)) { - $requirements['settings file ownership'] = array( - 'title' => t('Settings file'), - 'value' => t('The settings file is owned by the web server.'), - 'severity' => REQUIREMENT_ERROR, - 'description' => t('The @drupal installer failed to create a settings file with proper file ownership. Log on to your web server, remove the existing %file file, and create a new one by copying the %default_file file to %file. More details about installing Drupal are available in <a href="@install_txt">INSTALL.txt</a>. If you have problems with the file permissions on your server, consult the <a href="@handbook_url">online handbook</a>.', array('@drupal' => drupal_install_profile_distribution_name(), '%file' => $file, '%default_file' => $default_settings_file, '@install_txt' => base_path() . 'core/INSTALL.txt', '@handbook_url' => 'http://drupal.org/server-permissions')), + $requirements["$file file ownership"] = array( + 'title' => $default_file_info['title'], + 'value' => t('The @file is owned by the web server.', array('@file' => $default_file_info['title'])), + 'severity' => REQUIREMENT_ERROR, + 'description' => t('The @drupal installer failed to create a %file file with proper file ownership. Log on to your web server, remove the existing %file file, and create a new one by copying the %default_file file to %file. More details about installing Drupal are available in <a href="@install_txt">INSTALL.txt</a>. If you have problems with the file permissions on your server, consult the <a href="@handbook_url">online handbook</a>.', array( + '@drupal' => drupal_install_profile_distribution_name(), + '%file' => $file, + '%default_file' => $default_file, + '@install_txt' => base_path() . 'core/INSTALL.txt', + '@handbook_url' => 'http://drupal.org/server-permissions' + )), ); } } diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php index a006a9866b0c..8662d640e403 100644 --- a/core/lib/Drupal/Core/CoreServiceProvider.php +++ b/core/lib/Drupal/Core/CoreServiceProvider.php @@ -18,10 +18,6 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterAccessChecksPass; use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; use Drupal\Core\Plugin\PluginManagerPass; -use Drupal\Core\Site\Settings; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Compiler\PassConfig; /** @@ -42,7 +38,8 @@ class CoreServiceProvider implements ServiceProviderInterface { * {@inheritdoc} */ public function register(ContainerBuilder $container) { - $this->registerTwig($container); + $container->setParameter('app.root', DRUPAL_ROOT); + $this->registerUuid($container); $this->registerTest($container); @@ -72,44 +69,6 @@ public function register(ContainerBuilder $container) { $container->addCompilerPass(new PluginManagerPass()); } - /** - * Registers Twig services. - * - * This method is public and static so that it can be reused in the installer. - */ - public static function registerTwig(ContainerBuilder $container) { - $container->register('twig.loader.filesystem', 'Twig_Loader_Filesystem') - ->addArgument(DRUPAL_ROOT); - $container->setAlias('twig.loader', 'twig.loader.filesystem'); - - $twig_extension = new Definition('Drupal\Core\Template\TwigExtension'); - $twig_extension->addMethodCall('setGenerators', array(new Reference('url_generator'))); - - $container->register('twig', 'Drupal\Core\Template\TwigEnvironment') - ->addArgument(new Reference('twig.loader')) - ->addArgument(array( - // This is saved / loaded via drupal_php_storage(). - // All files can be refreshed by clearing caches. - // @todo ensure garbage collection of expired files. - // When in the installer, twig_cache must be FALSE until we know the - // files folder is writable. - 'cache' => drupal_installation_attempted() ? FALSE : Settings::get('twig_cache', TRUE), - 'autoescape' => TRUE, - 'debug' => Settings::get('twig_debug', FALSE), - 'auto_reload' => Settings::get('twig_auto_reload', NULL), - )) - ->addArgument(new Reference('module_handler')) - ->addArgument(new Reference('theme_handler')) - ->addMethodCall('addExtension', array($twig_extension)) - // @todo Figure out what to do about debugging functions. - // @see http://drupal.org/node/1804998 - ->addMethodCall('addExtension', array(new Definition('Twig_Extension_Debug'))) - ->addTag('service_collector', array( - 'tag' => 'twig.extension', - 'call' => 'addExtension', - )); - } - /** * Determines and registers the UUID service. * diff --git a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php index 75282d289d3a..d4ae53e2d0bf 100644 --- a/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php +++ b/core/lib/Drupal/Core/DependencyInjection/YamlFileLoader.php @@ -52,6 +52,14 @@ public function __construct(ContainerBuilder $container) $this->container = $container; } + /** + * Resets the internal cache. This method is mostly useful for tests. + */ + public static function reset() + { + static::$yaml = array(); + } + /** * Loads a Yaml file. * diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index 7b69341e63d2..da657c5f708d 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -529,7 +529,8 @@ public function discoverServiceProviders() { if ($container_yamls = Settings::get('container_yamls')) { $this->serviceYamls['site'] = $container_yamls; } - if (file_exists($site_services_yml = $this->getSitePath() . '/services.yml')) { + $site_services_yml = $this->getSitePath() . '/services.yml'; + if (file_exists($site_services_yml) && is_readable($site_services_yml)) { $this->serviceYamls['site'][] = $site_services_yml; } } diff --git a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php index 6c393b16c99b..d64bcbbb59f0 100644 --- a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php +++ b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php @@ -60,6 +60,11 @@ public function register(ContainerBuilder $container) { * {@inheritdoc} */ public function alter(ContainerBuilder $container) { + // Disable Twig cache (php storage does not exist yet). + $twig_config = $container->getParameter('twig.config'); + $twig_config['cache'] = FALSE; + $container->setParameter('twig.config', $twig_config); + // Disable configuration overrides. // ConfigFactory would to try to load language overrides and InstallStorage // throws an exception upon trying to load a non-existing file. diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php index 717ee04b5416..40851923440d 100644 --- a/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php +++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueFactory.php @@ -7,7 +7,6 @@ namespace Drupal\Core\KeyValueStore; -use Drupal\Core\Site\Settings; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -29,7 +28,7 @@ class KeyValueFactory implements KeyValueFactoryInterface { * This is a setting name that will be used if the specific setting does not * exist. The setting value will be the id of a service. */ - const DEFAULT_SETTING = 'keyvalue_default'; + const DEFAULT_SETTING = 'default'; /** * The default service id. @@ -50,22 +49,15 @@ class KeyValueFactory implements KeyValueFactoryInterface { */ protected $container; - /** - * The read-only settings container. - * - * @var \Drupal\Core\Site\Settings - */ - protected $settings; - /** * @param \Symfony\Component\DependencyInjection\ContainerInterface $container * The service container. - * @param \Drupal\Core\Site\Settings $settings - * The read-only settings container. + * @param array $options + * (optional) Collection-specific storage override options. */ - function __construct(ContainerInterface $container, Settings $settings) { + function __construct(ContainerInterface $container, array $options = array()) { $this->container = $container; - $this->settings = $settings; + $this->options = $options; } /** @@ -73,14 +65,16 @@ function __construct(ContainerInterface $container, Settings $settings) { */ public function get($collection) { if (!isset($this->stores[$collection])) { - if ($service_name = $this->settings->get(static::SPECIFIC_PREFIX . $collection)) { + if (isset($this->options[$collection])) { + $service_id = $this->options[$collection]; } - elseif ($service_name = $this->settings->get(static::DEFAULT_SETTING)) { + elseif (isset($this->options[static::DEFAULT_SETTING])) { + $service_id = $this->options[static::DEFAULT_SETTING]; } else { - $service_name = static::DEFAULT_SERVICE; + $service_id = static::DEFAULT_SERVICE; } - $this->stores[$collection] = $this->container->get($service_name)->get($collection); + $this->stores[$collection] = $this->container->get($service_id)->get($collection); } return $this->stores[$collection]; } diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php index d8da1ca33bde..fba0173613b0 100644 --- a/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -41,7 +41,7 @@ class TwigEnvironment extends \Twig_Environment { * Constructs a TwigEnvironment object and stores cache and storage * internally. */ - public function __construct(\Twig_LoaderInterface $loader = NULL, $options = array(), ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler) { + public function __construct(\Twig_LoaderInterface $loader = NULL, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, $options = array()) { // @todo Pass as arguments from the DIC. $this->cache_object = \Drupal::cache(); @@ -68,6 +68,16 @@ public function __construct(\Twig_LoaderInterface $loader = NULL, $options = arr $this->templateClasses = array(); $this->stringLoader = new \Twig_Loader_String(); + $options += array( + // @todo Ensure garbage collection of expired files. + 'cache' => TRUE, + // @todo Remove this. + // @see http://drupal.org/node/1712444 + 'autoescape' => FALSE, + 'debug' => FALSE, + 'auto_reload' => NULL, + ); + parent::__construct($loader, $options); } diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php index afea5908e5f6..949bd0459aea 100644 --- a/core/modules/simpletest/src/KernelTestBase.php +++ b/core/modules/simpletest/src/KernelTestBase.php @@ -15,6 +15,7 @@ use Drupal\Core\Language\Language; use Drupal\Core\Site\Settings; use Drupal\Core\Entity\Schema\EntitySchemaProviderInterface; +use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Request; @@ -260,7 +261,9 @@ public function containerBuild(ContainerBuilder $container) { ->addArgument(Database::getConnection()) ->addArgument('config'); - $this->settingsSet('keyvalue_default', 'keyvalue.memory'); + $keyvalue_options = $container->getParameter('factory.keyvalue') ?: array(); + $keyvalue_options['default'] = 'keyvalue.memory'; + $container->setParameter('factory.keyvalue', $keyvalue_options); $container->set('keyvalue.memory', $this->keyValueFactory); if (!$container->has('keyvalue')) { // TestBase::setUp puts a completely empty container in @@ -280,7 +283,7 @@ public function containerBuild(ContainerBuilder $container) { $container ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory') ->addArgument(new Reference('service_container')) - ->addArgument(new Reference('settings')); + ->addArgument(new Parameter('factory.keyvalue')); $container->register('state', 'Drupal\Core\State\State') ->addArgument(new Reference('keyvalue')); diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index a12c31020ecf..05467d2a19c6 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -8,9 +8,11 @@ namespace Drupal\simpletest; use Drupal\Component\Serialization\Json; +use Drupal\Component\Serialization\Yaml; use Drupal\Component\Utility\Crypt; use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\String; +use Drupal\Core\DependencyInjection\YamlFileLoader; use Drupal\Core\DrupalKernel; use Drupal\Core\Database\Database; use Drupal\Core\Database\ConnectionNotDefinedException; @@ -812,6 +814,7 @@ protected function setUp() { // Not using File API; a potential error must trigger a PHP warning. $directory = DRUPAL_ROOT . '/' . $this->siteDirectory; copy(DRUPAL_ROOT . '/sites/default/default.settings.php', $directory . '/settings.php'); + copy(DRUPAL_ROOT . '/sites/default/default.services.yml', $directory . '/services.yml'); // All file system paths are created by System module during installation. // @see system_requirements() @@ -1018,6 +1021,26 @@ protected function writeSettings(array $settings) { drupal_rewrite_settings($settings, $filename); } + /** + * Changes parameters in the services.yml file. + * + * @param $name + * The name of the parameter. + * @param $value + * The value of the parameter. + */ + protected function setContainerParameter($name, $value) { + $filename = $this->siteDirectory . '/services.yml'; + chmod($filename, 0666); + + $services = Yaml::decode(file_get_contents($filename)); + $services['parameters'][$name] = $value; + file_put_contents($filename, Yaml::encode($services)); + + // Clear the YML file cache. + YamlFileLoader::reset(); + } + /** * Queues custom translations to be written to settings.php. * diff --git a/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageExpirableTest.php b/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageExpirableTest.php index b18befa45ba4..f83584d6871a 100644 --- a/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageExpirableTest.php +++ b/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageExpirableTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\KeyValueStore; +use Drupal\Core\KeyValueStore\KeyValueFactory; use Symfony\Component\DependencyInjection\Reference; /** @@ -33,7 +34,9 @@ protected function setUp() { ->addArgument(new Reference('database')); $this->container ->register('serialization.phpserialize', 'Drupal\Component\Serialization\PhpSerialize'); - $this->settingsSet('keyvalue_expirable_default', 'keyvalue.expirable.database'); + $parameter = array(); + $parameter[KeyValueFactory::DEFAULT_SETTING] = 'keyvalue.expirable.database'; + $this->container->setParameter('factory.keyvalue.expirable', $parameter); } protected function tearDown() { diff --git a/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageTest.php b/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageTest.php index f3f61be804d7..3180ac838602 100644 --- a/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageTest.php +++ b/core/modules/system/src/Tests/KeyValueStore/DatabaseStorageTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\KeyValueStore; +use Drupal\Core\KeyValueStore\KeyValueFactory; use Symfony\Component\DependencyInjection\Reference; /** @@ -32,7 +33,9 @@ protected function setUp() { ->addArgument(new Reference('database')); $this->container ->register('serialization.phpserialize', 'Drupal\Component\Serialization\PhpSerialize'); - $this->settingsSet('keyvalue_default', 'keyvalue.database'); + $parameter = array(); + $parameter[KeyValueFactory::DEFAULT_SETTING] = 'keyvalue.database'; + $this->container->setParameter('factory.keyvalue', $parameter); } protected function tearDown() { diff --git a/core/modules/system/src/Tests/KeyValueStore/MemoryStorageTest.php b/core/modules/system/src/Tests/KeyValueStore/MemoryStorageTest.php index 10b2a15601d2..770d758130a3 100644 --- a/core/modules/system/src/Tests/KeyValueStore/MemoryStorageTest.php +++ b/core/modules/system/src/Tests/KeyValueStore/MemoryStorageTest.php @@ -6,6 +6,7 @@ */ namespace Drupal\system\Tests\KeyValueStore; +use Drupal\Core\KeyValueStore\KeyValueFactory; /** * Tests the key-value memory storage. @@ -25,7 +26,9 @@ protected function setUp() { parent::setUp(); $this->container ->register('keyvalue.memory', 'Drupal\Core\KeyValueStore\KeyValueMemoryFactory'); - $this->settingsSet('keyvalue_default', 'keyvalue.memory'); + $parameter = array(); + $parameter[KeyValueFactory::DEFAULT_SETTING] = 'keyvalue.memory'; + $this->container->setParameter('factory.keyvalue', $parameter); } } diff --git a/core/modules/system/src/Tests/KeyValueStore/StorageTestBase.php b/core/modules/system/src/Tests/KeyValueStore/StorageTestBase.php index 0190e6b494c2..2f70e0096643 100644 --- a/core/modules/system/src/Tests/KeyValueStore/StorageTestBase.php +++ b/core/modules/system/src/Tests/KeyValueStore/StorageTestBase.php @@ -58,11 +58,11 @@ protected function setUp() { $this->container ->register('keyvalue', 'Drupal\Core\KeyValueStore\KeyValueFactory') ->addArgument(new Reference('service_container')) - ->addArgument(new Reference('settings')); + ->addArgument('%factory.keyvalue%'); $this->container ->register('keyvalue.expirable', 'Drupal\Core\KeyValueStore\KeyValueExpirableFactory') ->addArgument(new Reference('service_container')) - ->addArgument(new Reference('settings')); + ->addArgument('%factory.keyvalue.expirable%'); // Define two data collections, $this->collections = array(0 => 'zero', 1 => 'one'); diff --git a/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php b/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php index 2836c2ca266a..efb081803c78 100644 --- a/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php +++ b/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php @@ -31,7 +31,9 @@ function testTwigDebugMarkup() { theme_enable(array('test_theme')); \Drupal::config('system.theme')->set('default', 'test_theme')->save(); // Enable debug, rebuild the service container, and clear all caches. - $this->settingsSet('twig_debug', TRUE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['debug'] = TRUE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); $this->resetAll(); @@ -67,7 +69,9 @@ function testTwigDebugMarkup() { $this->assertTrue(strpos($output, '* node--foo--bar' . $extension . PHP_EOL . ' * node--foo' . $extension . PHP_EOL . ' * node--3--full' . $extension . PHP_EOL . ' * node--3' . $extension . PHP_EOL . ' * node--page--full' . $extension . PHP_EOL . ' * node--page' . $extension . PHP_EOL . ' * node--full' . $extension . PHP_EOL . ' x node' . $extension) !== FALSE, 'Suggested template files found in order and base template shown as current template.'); // Disable debug, rebuild the service container, and clear all caches. - $this->settingsSet('twig_debug', FALSE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['debug'] = FALSE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); $this->resetAll(); diff --git a/core/modules/system/src/Tests/Theme/TwigSettingsTest.php b/core/modules/system/src/Tests/Theme/TwigSettingsTest.php index 277eef51a575..e57043234605 100644 --- a/core/modules/system/src/Tests/Theme/TwigSettingsTest.php +++ b/core/modules/system/src/Tests/Theme/TwigSettingsTest.php @@ -29,14 +29,18 @@ class TwigSettingsTest extends WebTestBase { */ function testTwigAutoReloadOverride() { // Enable auto reload and rebuild the service container. - $this->settingsSet('twig_auto_reload', TRUE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['auto_reload'] = TRUE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); // Check isAutoReload() via the Twig service container. $this->assertTrue($this->container->get('twig')->isAutoReload(), 'Automatic reloading of Twig templates enabled.'); // Disable auto reload and check the service container again. - $this->settingsSet('twig_auto_reload', FALSE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['auto_reload'] = FALSE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); $this->assertFalse($this->container->get('twig')->isAutoReload(), 'Automatic reloading of Twig templates disabled.'); @@ -47,7 +51,9 @@ function testTwigAutoReloadOverride() { */ function testTwigDebugOverride() { // Enable debug and rebuild the service container. - $this->settingsSet('twig_debug', TRUE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['debug'] = TRUE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); // Check isDebug() via the Twig service container. @@ -55,12 +61,16 @@ function testTwigDebugOverride() { $this->assertTrue($this->container->get('twig')->isAutoReload(), 'Twig automatic reloading is enabled when debug is enabled.'); // Override auto reload when debug is enabled. - $this->settingsSet('twig_auto_reload', FALSE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['auto_reload'] = FALSE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); $this->assertFalse($this->container->get('twig')->isAutoReload(), 'Twig automatic reloading can be disabled when debug is enabled.'); // Disable debug and check the service container again. - $this->settingsSet('twig_debug', FALSE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['debug'] = FALSE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); $this->assertFalse($this->container->get('twig')->isDebug(), 'Twig debug disabled.'); @@ -98,7 +108,9 @@ function testTwigCacheOverride() { $this->assertTrue(PhpStorageFactory::get('twig')->exists($cache_filename), 'Cached Twig template found.'); // Disable the Twig cache and rebuild the service container. - $this->settingsSet('twig_cache', FALSE); + $parameters = $this->container->getParameter('twig.config'); + $parameters['cache'] = FALSE; + $this->setContainerParameter('twig.config', $parameters); $this->rebuildContainer(); // This should return false after rebuilding the service container. diff --git a/core/modules/system/system.install b/core/modules/system/system.install index 4c945167538e..8e7b534c95cb 100644 --- a/core/modules/system/system.install +++ b/core/modules/system/system.install @@ -219,7 +219,7 @@ function system_requirements($phase) { if (!drupal_verify_install_file($conf_path, FILE_NOT_WRITABLE, 'dir')) { $conf_errors[] = t("The directory %file is not protected from modifications and poses a security risk. You must change the directory's permissions to be non-writable.", array('%file' => $conf_path)); } - foreach (array('settings.php', 'settings.local.php') as $conf_file) { + foreach (array('settings.php', 'settings.local.php', 'services.yml') as $conf_file) { $full_path = $conf_path . '/' . $conf_file; if (file_exists($full_path) && !drupal_verify_install_file($full_path, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) { $conf_errors[] = t("The file %file is not protected from modifications and poses a security risk. You must change the file's permissions to be non-writable.", array('%file' => $full_path)); @@ -236,18 +236,18 @@ function system_requirements($phase) { ); $description = drupal_render($item_list); } - $requirements['settings.php'] = array( + $requirements['configuration_files'] = array( 'value' => t('Not protected'), 'severity' => REQUIREMENT_ERROR, 'description' => $description, ); } else { - $requirements['settings.php'] = array( + $requirements['configuration_files'] = array( 'value' => t('Protected'), ); } - $requirements['settings.php']['title'] = t('Configuration files'); + $requirements['configuration_files']['title'] = t('Configuration files'); } // Test the contents of the .htaccess files. diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml new file mode 100644 index 000000000000..280eb43d9bca --- /dev/null +++ b/sites/default/default.services.yml @@ -0,0 +1,53 @@ +parameters: + twig.config: + # Twig debugging: + # + # When debugging is enabled: + # - The markup of each Twig template is surrounded by HTML comments that + # contain theming information, such as template file name suggestions. + # - Note that this debugging markup will cause automated tests that directly + # check rendered HTML to fail. When running automated tests, 'twig_debug' + # should be set to FALSE. + # - The dump() function can be used in Twig templates to output information + # about template variables. + # - Twig templates are automatically recompiled whenever the source code + # changes (see twig_auto_reload below). + # + # For more information about debugging Twig templates, see + # http://drupal.org/node/1906392. + # + # Not recommended in production environments + # @default false + debug: false + # Twig auto-reload: + # + # Automatically recompile Twig templates whenever the source code changes. + # If you don't provide a value for twig_auto_reload, it will be determined + # based on the value of twig_debug. + # + # Not recommended in production environments + # @default null + auto_reload: null + # Twig cache: + # + # By default, Twig templates will be compiled and stored in the filesystem + # to increase performance. Disabling the Twig cache will recompile the + # templates from source each time they are used. In most cases the + # twig_auto_reload setting above should be enabled rather than disabling the + # Twig cache. + # + # Not recommended in production environments + # @default true + cache: true + factory.keyvalue: + {} + # Default key/value storage service to use. + # @default keyvalue.database + #default: keyvalue.database + # Collection-specific overrides. + #state: keyvalue.database + factory.keyvalue.expirable: + {} + # Default key/value expirable storage service to use. + # @default keyvalue.database.expirable + #default: keyvalue.database.expirable diff --git a/sites/example.settings.local.php b/sites/example.settings.local.php index 3fac75760922..6bf2fd705e44 100644 --- a/sites/example.settings.local.php +++ b/sites/example.settings.local.php @@ -46,56 +46,3 @@ * using these parameters in a request to rebuild.php. */ $settings['rebuild_access'] = TRUE; - -/** - * Twig debugging: - * - * When debugging is enabled: - * - The markup of each Twig template is surrounded by HTML comments that - * contain theming information, such as template file name suggestions. - * - Note that this debugging markup will cause automated tests that directly - * check rendered HTML to fail. When running automated tests, 'twig_debug' - * should be set to FALSE. - * - The dump() function can be used in Twig templates to output information - * about template variables. - * - Twig templates are automatically recompiled whenever the source code - * changes (see twig_auto_reload below). - * - * Note: changes to this setting will only take effect once the cache is - * cleared. - * - * For more information about debugging Twig templates, see - * http://drupal.org/node/1906392. - * - * Not recommended in production environments (Default: FALSE). - */ -# $settings['twig_debug'] = TRUE; - -/** - * Twig auto-reload: - * - * Automatically recompile Twig templates whenever the source code changes. If - * you don't provide a value for twig_auto_reload, it will be determined based - * on the value of twig_debug. - * - * Note: changes to this setting will only take effect once the cache is - * cleared. - * - * Not recommended in production environments (Default: NULL). - */ -# $settings['twig_auto_reload'] = TRUE; - -/** - * Twig cache: - * - * By default, Twig templates will be compiled and stored in the filesystem to - * increase performance. Disabling the Twig cache will recompile the templates - * from source each time they are used. In most cases the twig_auto_reload - * setting above should be enabled rather than disabling the Twig cache. - * - * Note: changes to this setting will only take effect once the cache is - * cleared. - * - * Not recommended in production environments (Default: TRUE). - */ -# $settings['twig_cache'] = FALSE; -- GitLab