summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorxjm <xjm@65776.no-reply.drupal.org>2023-01-07 15:32:44 -0600
committerxjm <xjm@65776.no-reply.drupal.org>2023-01-07 15:32:44 -0600
commit4d9b40b01e2c02e5e53b69102c07b3df31353d4e (patch)
treea7719d74cae1c625db00e898dcc30a0b56654cff
parent8b49c009d13194ad6fc00f2a5be50e483b110674 (diff)
downloaddrupal-4d9b40b01e2c02e5e53b69102c07b3df31353d4e.tar.gz
drupal-4d9b40b01e2c02e5e53b69102c07b3df31353d4e.zip
Issue #3244570 by voleger, xjm, alexpott, longwave, andypost: Deprecate drupal_rewrite_settings()
-rw-r--r--core/includes/install.inc199
-rw-r--r--core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php3
-rw-r--r--core/lib/Drupal/Core/Site/SettingsEditor.php305
-rw-r--r--core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php7
-rw-r--r--core/phpstan-baseline.neon20
-rw-r--r--core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php4
-rw-r--r--core/tests/Drupal/KernelTests/Core/Site/LegacySettingsRewriteTest.php131
-rw-r--r--core/tests/Drupal/KernelTests/Core/Site/SettingsRewriteTest.php11
-rw-r--r--core/tests/Drupal/Tests/BrowserTestBase.php4
9 files changed, 516 insertions, 168 deletions
diff --git a/core/includes/install.inc b/core/includes/install.inc
index c8dd224cab5..588855a3dc9 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -5,14 +5,13 @@
* API functions for installing modules and themes.
*/
-use Drupal\Component\Utility\OpCodeCache;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Database\Database;
use Drupal\Core\Extension\Dependency;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Installer\InstallerKernel;
-use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\SettingsEditor;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
@@ -254,154 +253,20 @@ function drupal_get_database_types() {
* @code
* $settings['config_sync_directory'] = 'config_hash/sync'
* @endcode
+ *
+ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use
+ * SettingsEditor::rewrite() instead. Note $settings_file argument becomes
+ * required and the first argument of the method.
+ *
+ * @see https://www.drupal.org/node/3244583
+ * @see \Drupal\Core\Site\SettingsEditor::rewrite()
*/
function drupal_rewrite_settings($settings = [], $settings_file = NULL) {
- if (!isset($settings_file)) {
- $settings_file = \Drupal::getContainer()->getParameter('site.path') . '/settings.php';
- }
- // Build list of setting names and insert the values into the global namespace.
- $variable_names = [];
- $settings_settings = [];
- foreach ($settings as $setting => $data) {
- if ($setting != 'settings') {
- _drupal_rewrite_settings_global($GLOBALS[$setting], $data);
- }
- else {
- _drupal_rewrite_settings_global($settings_settings, $data);
- }
- $variable_names['$' . $setting] = $setting;
- }
- $contents = file_get_contents($settings_file);
- if ($contents !== FALSE) {
- // Initialize the contents for the settings.php file if it is empty.
- if (trim($contents) === '') {
- $contents = "<?php\n";
- }
- // Step through each token in settings.php and replace any variables that
- // are in the passed-in array.
- $buffer = '';
- $state = 'default';
- foreach (token_get_all($contents) as $token) {
- if (is_array($token)) {
- [$type, $value] = $token;
- }
- else {
- $type = -1;
- $value = $token;
- }
- // Do not operate on whitespace.
- if (!in_array($type, [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
- switch ($state) {
- case 'default':
- if ($type === T_VARIABLE && isset($variable_names[$value])) {
- // This will be necessary to unset the dumped variable.
- $parent = &$settings;
- // This is the current index in parent.
- $index = $variable_names[$value];
- // This will be necessary for descending into the array.
- $current = &$parent[$index];
- $state = 'candidate_left';
- }
- break;
-
- case 'candidate_left':
- if ($value == '[') {
- $state = 'array_index';
- }
- if ($value == '=') {
- $state = 'candidate_right';
- }
- break;
-
- case 'array_index':
- if (_drupal_rewrite_settings_is_array_index($type)) {
- $index = trim($value, '\'"');
- $state = 'right_bracket';
- }
- else {
- // $a[foo()] or $a[$bar] or something like that.
- throw new Exception('invalid array index');
- }
- break;
-
- case 'right_bracket':
- if ($value == ']') {
- if (isset($current[$index])) {
- // If the new settings has this index, descend into it.
- $parent = &$current;
- $current = &$parent[$index];
- $state = 'candidate_left';
- }
- else {
- // Otherwise, jump back to the default state.
- $state = 'wait_for_semicolon';
- }
- }
- else {
- // $a[1 + 2].
- throw new Exception('] expected');
- }
- break;
-
- case 'candidate_right':
- if (_drupal_rewrite_settings_is_simple($type, $value)) {
- $value = _drupal_rewrite_settings_dump_one($current);
- // Unsetting $current would not affect $settings at all.
- unset($parent[$index]);
- // Skip the semicolon because _drupal_rewrite_settings_dump_one() added one.
- $state = 'semicolon_skip';
- }
- else {
- $state = 'wait_for_semicolon';
- }
- break;
-
- case 'wait_for_semicolon':
- if ($value == ';') {
- $state = 'default';
- }
- break;
-
- case 'semicolon_skip':
- if ($value == ';') {
- $value = '';
- $state = 'default';
- }
- else {
- // If the expression was $a = 1 + 2; then we replaced 1 and
- // the + is unexpected.
- throw new Exception('Unexpected token after replacing value.');
- }
- break;
- }
- }
- $buffer .= $value;
- }
- foreach ($settings as $name => $setting) {
- $buffer .= _drupal_rewrite_settings_dump($setting, '$' . $name);
- }
-
- // Write the new settings file.
- if (file_put_contents($settings_file, $buffer) === FALSE) {
- throw new Exception("Failed to modify '$settings_file'. Verify the file permissions.");
- }
- else {
- // In case any $settings variables were written, import them into the
- // Settings singleton.
- if (!empty($settings_settings)) {
- $old_settings = Settings::getAll();
- new Settings($settings_settings + $old_settings);
- }
- // The existing settings.php file might have been included already. In
- // case an opcode cache is enabled, the rewritten contents of the file
- // will not be reflected in this process. Ensure to invalidate the file
- // in case an opcode cache is enabled.
- OpCodeCache::invalidate(DRUPAL_ROOT . '/' . $settings_file);
- }
- }
- else {
- throw new Exception("Failed to open '$settings_file'. Verify the file permissions.");
- }
+ @trigger_error(__FUNCTION__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. The order of the arguments has also changed: $settings_file is now required and is the first argument of the method. See https://www.drupal.org/node/3244583', E_USER_DEPRECATED);
+ SettingsEditor::rewrite(
+ $settings_file ?? \Drupal::getContainer()->getParameter('site.path') . '/settings.php',
+ $settings
+ );
}
/**
@@ -417,9 +282,16 @@ function drupal_rewrite_settings($settings = [], $settings_file = NULL) {
* @return bool
* TRUE if this token represents a scalar or NULL.
*
+ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use
+ * SettingsEditor::rewrite() instead. As internal API,
+ * _drupal_rewrite_settings_is_simple() may also be removed in a minor
+ * release.
+ *
+ * @see https://www.drupal.org/node/3244583
* @see token_name()
*/
function _drupal_rewrite_settings_is_simple($type, $value) {
+ @trigger_error(__FUNCTION__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. As internal API, ' . __FUNCTION__ . '() may also be removed in a minor release. See https://www.drupal.org/node/3244583', E_USER_DEPRECATED);
$is_integer = $type == T_LNUMBER;
$is_float = $type == T_DNUMBER;
$is_string = $type == T_CONSTANT_ENCAPSED_STRING;
@@ -439,9 +311,16 @@ function _drupal_rewrite_settings_is_simple($type, $value) {
* @return bool
* TRUE if this token represents a number or a string.
*
+ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use
+ * SettingsEditor::rewrite() instead. As internal API,
+ * _drupal_rewrite_settings_is_array_index() may also be removed in a minor
+ * release.
+ *
+ * @see https://www.drupal.org/node/3244583
* @see token_name()
*/
function _drupal_rewrite_settings_is_array_index($type) {
+ @trigger_error(__FUNCTION__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. As internal API, ' . __FUNCTION__ . '() may also be removed in a minor release. See https://www.drupal.org/node/3244583', E_USER_DEPRECATED);
$is_integer = $type == T_LNUMBER;
$is_float = $type == T_DNUMBER;
$is_string = $type == T_CONSTANT_ENCAPSED_STRING;
@@ -457,8 +336,16 @@ function _drupal_rewrite_settings_is_array_index($type) {
* A reference to a nested index in $GLOBALS.
* @param array|object $variable
* The nested value of the setting being copied.
+ *
+ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use
+ * SettingsEditor::rewrite() instead. As internal API,
+ * _drupal_rewrite_settings_global() may also be removed in a minor
+ * release.
+ *
+ * @see https://www.drupal.org/node/3244583
*/
function _drupal_rewrite_settings_global(&$ref, $variable) {
+ @trigger_error(__FUNCTION__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. As internal API, ' . __FUNCTION__ . '() may also be removed in a minor release. See https://www.drupal.org/node/3244583', E_USER_DEPRECATED);
if (is_object($variable)) {
$ref = $variable->value;
}
@@ -482,8 +369,16 @@ function _drupal_rewrite_settings_global(&$ref, $variable) {
* @return string
* A string containing valid PHP code of the variable suitable for placing
* into settings.php.
+ *
+ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use
+ * SettingsEditor::rewrite() instead. As internal API,
+ * _drupal_rewrite_settings_dump() may also be removed in a minor
+ * release.
+ *
+ * @see https://www.drupal.org/node/3244583
*/
function _drupal_rewrite_settings_dump($variable, $variable_name) {
+ @trigger_error(__FUNCTION__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. As internal API, ' . __FUNCTION__ . '() may also be removed in a minor release. See https://www.drupal.org/node/3244583', E_USER_DEPRECATED);
$return = '';
if (is_object($variable)) {
if (!empty($variable->required)) {
@@ -513,8 +408,16 @@ function _drupal_rewrite_settings_dump($variable, $variable_name) {
* @return string
* A string containing valid PHP code of the variable suitable for placing
* into settings.php.
+ *
+ * @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use
+ * SettingsEditor::rewrite() instead. As internal API,
+ * _drupal_rewrite_settings_dump_one() may also be removed in a minor
+ * release.
+ *
+ * @see https://www.drupal.org/node/3244583
*/
function _drupal_rewrite_settings_dump_one(\stdClass $variable, $prefix = '', $suffix = '') {
+ @trigger_error(__FUNCTION__ . '() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. As internal API, ' . __FUNCTION__ . '() may also be removed in a minor release. See https://www.drupal.org/node/3244583', E_USER_DEPRECATED);
$return = $prefix . var_export($variable->value, TRUE) . ';';
if (!empty($variable->comment)) {
$return .= ' // ' . $variable->comment;
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
index dc265471222..0f1f25bb914 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteSettingsForm.php
@@ -9,6 +9,7 @@ use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\SettingsEditor;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -264,7 +265,7 @@ class SiteSettingsForm extends FormBase {
];
}
- drupal_rewrite_settings($settings);
+ SettingsEditor::rewrite($this->sitePath . '/settings.php', $settings);
// Indicate that the settings file has been verified, and check the database
// for the last completed task, now that we have a valid connection. This
diff --git a/core/lib/Drupal/Core/Site/SettingsEditor.php b/core/lib/Drupal/Core/Site/SettingsEditor.php
new file mode 100644
index 00000000000..e9a8c4c99f0
--- /dev/null
+++ b/core/lib/Drupal/Core/Site/SettingsEditor.php
@@ -0,0 +1,305 @@
+<?php
+
+namespace Drupal\Core\Site;
+
+use Drupal\Component\Utility\OpCodeCache;
+
+/**
+ * Generates settings.php files for Drupal installations.
+ */
+final class SettingsEditor {
+
+ /**
+ * This class should not be instantiated.
+ *
+ * Use a static ::rewrite() method call instead.
+ *
+ * @see \Drupal\Core\Site\SettingsEditor::rewrite()
+ */
+ private function __construct() {}
+
+ /**
+ * Replaces values in settings.php with values in the submitted array.
+ *
+ * This method rewrites values in place if possible, even for
+ * multidimensional arrays. This helps ensure that the documentation remains
+ * attached to the correct settings and that old, overridden values do not
+ * clutter up the file.
+ *
+ * @code
+ * $settings['settings']['config_sync_directory'] = (object) array(
+ * 'value' => 'config_hash/sync',
+ * 'required' => TRUE,
+ * );
+ * @endcode
+ * gets dumped as:
+ * @code
+ * $settings['config_sync_directory'] = 'config_hash/sync'
+ * @endcode
+ *
+ * @param string $settings_file
+ * Path to the settings file relative to the DRUPAL_ROOT directory.
+ * @param array $settings
+ * An array of settings that need to be updated. Multidimensional arrays
+ * are dumped up to a stdClass object. The object can have value, required
+ * and comment properties.
+ *
+ * @throws \Exception
+ */
+ public static function rewrite(string $settings_file, array $settings = []): void {
+ // Build list of setting names and insert the values into the global
+ // namespace.
+ $variable_names = [];
+ $settings_settings = [];
+ foreach ($settings as $setting => $data) {
+ if ($setting !== 'settings') {
+ self::setGlobal($GLOBALS[$setting], $data);
+ }
+ else {
+ self::setGlobal($settings_settings, $data);
+ }
+ $variable_names['$' . $setting] = $setting;
+ }
+ $contents = file_get_contents($settings_file);
+ if ($contents !== FALSE) {
+ // Initialize the contents for the settings.php file if it is empty.
+ if (trim($contents) === '') {
+ $contents = "<?php\n";
+ }
+ // Step through each token in settings.php and replace any variables that
+ // are in the passed-in array.
+ $buffer = '';
+ $state = 'default';
+ foreach (token_get_all($contents) as $token) {
+ if (is_array($token)) {
+ [$type, $value] = $token;
+ }
+ else {
+ $type = -1;
+ $value = $token;
+ }
+ // Do not operate on whitespace.
+ if (!in_array($type, [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], TRUE)) {
+ switch ($state) {
+ case 'default':
+ if ($type === T_VARIABLE && isset($variable_names[$value])) {
+ // This will be necessary to unset the dumped variable.
+ $parent = &$settings;
+ // This is the current index in parent.
+ $index = $variable_names[$value];
+ // This will be necessary for descending into the array.
+ $current = &$parent[$index];
+ $state = 'candidate_left';
+ }
+ break;
+
+ case 'candidate_left':
+ if ($value === '[') {
+ $state = 'array_index';
+ }
+ if ($value === '=') {
+ $state = 'candidate_right';
+ }
+ break;
+
+ case 'array_index':
+ if (self::isArrayIndex($type)) {
+ $index = trim($value, '\'"');
+ $state = 'right_bracket';
+ }
+ else {
+ // $a[foo()] or $a[$bar] or something like that.
+ throw new \Exception('invalid array index');
+ }
+ break;
+
+ case 'right_bracket':
+ if ($value === ']') {
+ if (isset($current[$index])) {
+ // If the new settings has this index, descend into it.
+ $parent = &$current;
+ $current = &$parent[$index];
+ $state = 'candidate_left';
+ }
+ else {
+ // Otherwise, jump back to the default state.
+ $state = 'wait_for_semicolon';
+ }
+ }
+ else {
+ // $a[1 + 2].
+ throw new \Exception('] expected');
+ }
+ break;
+
+ case 'candidate_right':
+ if (self::isSimple($type, $value)) {
+ $value = self::exportSingleSettingToPhp($current);
+ // Unsetting $current would not affect $settings at all.
+ unset($parent[$index]);
+ // Skip the semicolon because self::dumpOne() added one.
+ $state = 'semicolon_skip';
+ }
+ else {
+ $state = 'wait_for_semicolon';
+ }
+ break;
+
+ case 'wait_for_semicolon':
+ if ($value === ';') {
+ $state = 'default';
+ }
+ break;
+
+ case 'semicolon_skip':
+ if ($value === ';') {
+ $value = '';
+ $state = 'default';
+ }
+ else {
+ // If the expression was $a = 1 + 2; then we replaced 1 and
+ // the + is unexpected.
+ throw new \Exception('Unexpected token after replacing value.');
+ }
+ break;
+ }
+ }
+ $buffer .= $value;
+ }
+ foreach ($settings as $name => $setting) {
+ $buffer .= self::exportSettingsToPhp($setting, '$' . $name);
+ }
+
+ // Write the new settings file.
+ if (file_put_contents($settings_file, $buffer) === FALSE) {
+ throw new \Exception("Failed to modify '$settings_file'. Verify the file permissions.");
+ }
+ // In case any $settings variables were written, import them into the
+ // Settings singleton.
+ if (!empty($settings_settings)) {
+ $old_settings = Settings::getAll();
+ new Settings($settings_settings + $old_settings);
+ }
+ // The existing settings.php file might have been included already. In
+ // case an opcode cache is enabled, the rewritten contents of the file
+ // will not be reflected in this process. Ensure to invalidate the file
+ // in case an opcode cache is enabled.
+ OpCodeCache::invalidate(DRUPAL_ROOT . '/' . $settings_file);
+ }
+ else {
+ throw new \Exception("Failed to open '$settings_file'. Verify the file permissions.");
+ }
+ }
+
+ /**
+ * Checks whether the given token represents a scalar or NULL.
+ *
+ * @param int $type
+ * The token type.
+ * @param string $value
+ * The value of the token.
+ *
+ * @return bool
+ * TRUE if this token represents a scalar or NULL.
+ *
+ * @see token_name()
+ */
+ private static function isSimple(int $type, string $value): bool {
+ $is_integer = $type === T_LNUMBER;
+ $is_float = $type === T_DNUMBER;
+ $is_string = $type === T_CONSTANT_ENCAPSED_STRING;
+ $is_boolean_or_null = $type === T_STRING && in_array(
+ strtoupper($value),
+ ['TRUE', 'FALSE', 'NULL']
+ );
+ return $is_integer || $is_float || $is_string || $is_boolean_or_null;
+ }
+
+ /**
+ * Checks whether the token is a valid array index (a number or string).
+ *
+ * @param int $type
+ * The token type.
+ *
+ * @return bool
+ * TRUE if this token represents a number or a string.
+ *
+ * @see token_name()
+ */
+ private static function isArrayIndex(int $type): bool {
+ $is_integer = $type === T_LNUMBER;
+ $is_float = $type === T_DNUMBER;
+ $is_string = $type === T_CONSTANT_ENCAPSED_STRING;
+ return $is_integer || $is_float || $is_string;
+ }
+
+ /**
+ * Makes the given setting global.
+ *
+ * @param mixed $ref
+ * A reference to a nested index in $GLOBALS.
+ * @param array|object $variable
+ * The nested value of the setting being copied.
+ */
+ private static function setGlobal(mixed &$ref, array|object $variable): void {
+ if (is_object($variable)) {
+ $ref = $variable->value;
+ }
+ else {
+ foreach ($variable as $k => $v) {
+ self::setGlobal($ref[$k], $v);
+ }
+ }
+ }
+
+ /**
+ * Recursively exports one or more settings to a valid PHP string.
+ *
+ * @param array|object $variable
+ * The container for variable values.
+ * @param string $variable_name
+ * Name of variable.
+ *
+ * @return string
+ * A string containing valid PHP code of the variable suitable for placing
+ * into settings.php.
+ */
+ private static function exportSettingsToPhp(array|object $variable, string $variable_name): string {
+ $return = '';
+ if (is_object($variable)) {
+ if (!empty($variable->required)) {
+ $return .= self::exportSingleSettingToPhp($variable, "$variable_name = ", "\n");
+ }
+ }
+ else {
+ foreach ($variable as $k => $v) {
+ $return .= self::exportSettingsToPhp($v, $variable_name . "['" . $k . "']");
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * Exports the value of a value property and adds the comment if it exists.
+ *
+ * @param object $variable
+ * A stdClass object with at least a value property.
+ * @param string $prefix
+ * A string to prepend to the variable's value.
+ * @param string $suffix
+ * A string to append to the variable's value.
+ *
+ * @return string
+ * A string containing valid PHP code of the variable suitable for placing
+ * into settings.php.
+ */
+ private static function exportSingleSettingToPhp(object $variable, string $prefix = '', string $suffix = ''): string {
+ $return = $prefix . var_export($variable->value, TRUE) . ';';
+ if (!empty($variable->comment)) {
+ $return .= ' // ' . $variable->comment;
+ }
+ $return .= $suffix;
+ return $return;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index 5d37d5c8adb..15a1ee80de8 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -16,6 +16,7 @@ use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Session\UserSession;
use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\SettingsEditor;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Tests\SessionTestTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -152,9 +153,9 @@ trait FunctionalTestSetupTrait {
*
* @param array $settings
* An array of settings to write out, in the format expected by
- * drupal_rewrite_settings().
+ * SettingsEditor::rewrite().
*
- * @see drupal_rewrite_settings()
+ * @see \Drupal\Core\Site\SettingsEditor::rewrite()
*/
protected function writeSettings(array $settings) {
include_once DRUPAL_ROOT . '/core/includes/install.inc';
@@ -163,7 +164,7 @@ trait FunctionalTestSetupTrait {
// whenever it is invoked.
// Not using File API; a potential error must trigger a PHP warning.
chmod($filename, 0666);
- drupal_rewrite_settings($settings, $filename);
+ SettingsEditor::rewrite($filename, $settings);
}
/**
diff --git a/core/phpstan-baseline.neon b/core/phpstan-baseline.neon
index f26c4db4b38..16aba07556b 100644
--- a/core/phpstan-baseline.neon
+++ b/core/phpstan-baseline.neon
@@ -46,16 +46,6 @@ parameters:
path: includes/install.core.inc
-
- message: "#^Variable \\$current might not be defined\\.$#"
- count: 1
- path: includes/install.inc
-
- -
- message: "#^Variable \\$index might not be defined\\.$#"
- count: 3
- path: includes/install.inc
-
- -
message: "#^Variable \\$items might not be defined\\.$#"
count: 1
path: includes/theme.inc
@@ -726,6 +716,16 @@ parameters:
path: lib/Drupal/Core/Session/SessionManager.php
-
+ message: "#^Variable \\$current might not be defined\\.$#"
+ count: 1
+ path: lib/Drupal/Core/Site/SettingsEditor.php
+
+ -
+ message: "#^Variable \\$index might not be defined\\.$#"
+ count: 3
+ path: lib/Drupal/Core/Site/SettingsEditor.php
+
+ -
message: "#^Method Drupal\\\\Core\\\\Template\\\\AttributeValueBase\\:\\:render\\(\\) should return string but return statement is missing\\.$#"
count: 1
path: lib/Drupal/Core/Template/AttributeValueBase.php
diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
index 5bf4918d084..6ec3919d6a8 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
@@ -28,7 +28,9 @@ abstract class InstallerTestBase extends BrowserTestBase {
*
* @var array
* An array of settings to write out, in the format expected by
- * drupal_rewrite_settings().
+ * SettingsEditor::rewrite().
+ *
+ * @see \Drupal\Core\Site\SettingsEditor::rewrite()
*/
protected $settings = [];
diff --git a/core/tests/Drupal/KernelTests/Core/Site/LegacySettingsRewriteTest.php b/core/tests/Drupal/KernelTests/Core/Site/LegacySettingsRewriteTest.php
new file mode 100644
index 00000000000..99666ced3b7
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Site/LegacySettingsRewriteTest.php
@@ -0,0 +1,131 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Site;
+
+use Drupal\Core\Site\Settings;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the drupal_rewrite_settings() function.
+ *
+ * @group system
+ * @group legacy
+ * @covers drupal_rewrite_settings()
+ */
+class LegacySettingsRewriteTest extends KernelTestBase {
+
+ /**
+ * Tests the drupal_rewrite_settings() function.
+ */
+ public function testDrupalRewriteSettings() {
+ include_once $this->root . '/core/includes/install.inc';
+ $site_path = $this->container->getParameter('site.path');
+ $tests = [
+ [
+ 'original' => '$no_index_value_scalar = TRUE;',
+ 'settings' => [
+ 'no_index_value_scalar' => (object) [
+ 'value' => FALSE,
+ 'comment' => 'comment',
+ ],
+ ],
+ 'expected' => '$no_index_value_scalar = false; // comment',
+ ],
+ [
+ 'original' => '$no_index_value_scalar = TRUE;',
+ 'settings' => [
+ 'no_index_value_foo' => [
+ 'foo' => [
+ 'value' => (object) [
+ 'value' => NULL,
+ 'required' => TRUE,
+ 'comment' => 'comment',
+ ],
+ ],
+ ],
+ ],
+ 'expected' => <<<'EXPECTED'
+$no_index_value_scalar = TRUE;
+$no_index_value_foo['foo']['value'] = NULL; // comment
+EXPECTED
+ ],
+ [
+ 'original' => '$no_index_value_array = array("old" => "value");',
+ 'settings' => [
+ 'no_index_value_array' => (object) [
+ 'value' => FALSE,
+ 'required' => TRUE,
+ 'comment' => 'comment',
+ ],
+ ],
+ 'expected' => '$no_index_value_array = array("old" => "value");
+$no_index_value_array = false; // comment',
+ ],
+ [
+ 'original' => '$has_index_value_scalar["foo"]["bar"] = NULL;',
+ 'settings' => [
+ 'has_index_value_scalar' => [
+ 'foo' => [
+ 'bar' => (object) [
+ 'value' => FALSE,
+ 'required' => TRUE,
+ 'comment' => 'comment',
+ ],
+ ],
+ ],
+ ],
+ 'expected' => '$has_index_value_scalar["foo"]["bar"] = false; // comment',
+ ],
+ [
+ 'original' => '$has_index_value_scalar["foo"]["bar"] = "foo";',
+ 'settings' => [
+ 'has_index_value_scalar' => [
+ 'foo' => [
+ 'value' => (object) [
+ 'value' => ['value' => 2],
+ 'required' => TRUE,
+ 'comment' => 'comment',
+ ],
+ ],
+ ],
+ ],
+ 'expected' => <<<'EXPECTED'
+$has_index_value_scalar["foo"]["bar"] = "foo";
+$has_index_value_scalar['foo']['value'] = array (
+ 'value' => 2,
+); // comment
+EXPECTED
+ ],
+ ];
+ foreach ($tests as $test) {
+ $filename = Settings::get('file_public_path', $site_path . '/files') . '/mock_settings.php';
+ file_put_contents($filename, "<?php\n" . $test['original'] . "\n");
+ $this->expectDeprecation('drupal_rewrite_settings() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. The order of the arguments has also changed: $settings_file is now required and is the first argument of the method. See https://www.drupal.org/node/3244583');
+ drupal_rewrite_settings($test['settings'], $filename);
+ $this->assertEquals("<?php\n" . $test['expected'] . "\n", file_get_contents($filename));
+ }
+
+ // Test that <?php gets added to the start of an empty settings file.
+ // Set the array of settings that will be written to the file.
+ $test = [
+ 'settings' => [
+ 'no_index' => (object) [
+ 'value' => TRUE,
+ 'required' => TRUE,
+ ],
+ ],
+ 'expected' => '$no_index = true;',
+ ];
+ // Make an empty file.
+ $filename = Settings::get('file_public_path', $site_path . '/files') . '/mock_settings.php';
+ file_put_contents($filename, "");
+
+ $this->expectDeprecation('drupal_rewrite_settings() is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. Use SettingsEditor::rewrite() instead. The order of the arguments has also changed: $settings_file is now required and is the first argument of the method. See https://www.drupal.org/node/3244583');
+ // Write the setting to the file.
+ drupal_rewrite_settings($test['settings'], $filename);
+
+ // Check that the result is just the php opening tag and the settings.
+ $this->assertEquals("<?php\n" . $test['expected'] . "\n", file_get_contents($filename));
+ }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Site/SettingsRewriteTest.php b/core/tests/Drupal/KernelTests/Core/Site/SettingsRewriteTest.php
index bc521a22f15..3955205e86d 100644
--- a/core/tests/Drupal/KernelTests/Core/Site/SettingsRewriteTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Site/SettingsRewriteTest.php
@@ -3,17 +3,20 @@
namespace Drupal\KernelTests\Core\Site;
use Drupal\Core\Site\Settings;
+use Drupal\Core\Site\SettingsEditor;
use Drupal\KernelTests\KernelTestBase;
/**
- * Tests the drupal_rewrite_settings() function.
+ * Tests the SettingsEditor::rewrite() function.
*
* @group system
+ *
+ * @covers \Drupal\Core\Site\SettingsEditor::rewrite()
*/
class SettingsRewriteTest extends KernelTestBase {
/**
- * Tests the drupal_rewrite_settings() function.
+ * Tests the SettingsEditor::rewrite() function.
*/
public function testDrupalRewriteSettings() {
include_once $this->root . '/core/includes/install.inc';
@@ -98,7 +101,7 @@ EXPECTED
foreach ($tests as $test) {
$filename = Settings::get('file_public_path', $site_path . '/files') . '/mock_settings.php';
file_put_contents($filename, "<?php\n" . $test['original'] . "\n");
- drupal_rewrite_settings($test['settings'], $filename);
+ SettingsEditor::rewrite($filename, $test['settings']);
$this->assertEquals("<?php\n" . $test['expected'] . "\n", file_get_contents($filename));
}
@@ -118,7 +121,7 @@ EXPECTED
file_put_contents($filename, "");
// Write the setting to the file.
- drupal_rewrite_settings($test['settings'], $filename);
+ SettingsEditor::rewrite($filename, $test['settings']);
// Check that the result is just the php opening tag and the settings.
$this->assertEquals("<?php\n" . $test['expected'] . "\n", file_get_contents($filename));
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index cd75578c4eb..283cffc0b63 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -126,9 +126,11 @@ abstract class BrowserTestBase extends TestCase {
protected $defaultTheme;
/**
- * An array of custom translations suitable for drupal_rewrite_settings().
+ * An array of custom translations suitable for SettingsEditor::rewrite().
*
* @var array
+ *
+ * @see \Drupal\Core\Site\SettingsEditor::rewrite()
*/
protected $customTranslations;