diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php index c0d2617..6c4c3b7 100644 --- a/core/lib/Drupal/Core/Config/Config.php +++ b/core/lib/Drupal/Core/Config/Config.php @@ -189,13 +189,6 @@ public function isNew() { * would return array('bar' => 'baz'). * If no key is specified, then the entire data array is returned. * - * The configuration system does not retain data types. Every saved value is - * casted to a string. In most cases this is not an issue; however, it can - * cause issues with Booleans, which are casted to "1" (TRUE) or "0" (FALSE). - * In particular, code relying on === or !== will no longer function properly. - * - * @see http://php.net/manual/language.operators.comparison.php - * * @return mixed * The data that was requested. */ @@ -319,8 +312,6 @@ public function set($key, $value) { if (!$this->isLoaded) { $this->load(); } - // Type-cast value into a string. - $value = $this->castValue($value); // The dot/period is a reserved character; it may appear between keys, but // not within keys. @@ -336,46 +327,6 @@ public function set($key, $value) { } /** - * Casts a saved value to a string. - * - * The configuration system only saves strings or arrays. Any scalar - * non-string value is cast to a string. The one exception is boolean FALSE - * which would normally become '' when cast to a string, but is manually - * cast to '0' here for convenience and consistency. - * - * Any non-scalar value that is not an array (aka objects) gets cast - * to an array. - * - * @param mixed $value - * A value being saved into the configuration system. - * - * @return string - * The value cast to a string or array. - */ - public function castValue($value) { - if (is_scalar($value) || $value === NULL) { - // Handle special case of FALSE, which should be '0' instead of ''. - if ($value === FALSE) { - $value = '0'; - } - else { - $value = (string) $value; - } - } - else { - // Any non-scalar value must be an array. - if (!is_array($value)) { - $value = (array) $value; - } - // Recurse into any nested keys. - foreach ($value as $key => $nested_value) { - $value[$key] = $this->castValue($nested_value); - } - } - return $value; - } - - /** * Unsets value in this config object. * * @param string $key diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index 6422e9d..a08af4b 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -140,6 +140,7 @@ protected function getDumper() { // 2 spaces for consistency with Drupal coding standards. $this->dumper->setIndentation(2); } + return $this->dumper; } @@ -162,8 +163,9 @@ protected function getParser() { */ public function encode($data) { // The level where you switch to inline YAML is set to PHP_INT_MAX to ensure - // this does not occur. - return $this->getDumper()->dump($data, PHP_INT_MAX); + // this does not occur. Also set the exceptionOnInvalidType parameter to + // TRUE, so exceptions are thrown for an invalid data type. + return $this->getDumper()->dump($data, PHP_INT_MAX, 0, TRUE); } /** diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php index b6bded3..fec4aee 100644 --- a/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php +++ b/core/modules/config/lib/Drupal/config/Tests/ConfigCRUDTest.php @@ -9,6 +9,7 @@ use Drupal\Core\Config\ConfigNameException; use Drupal\simpletest\DrupalUnitTestBase; +use Drupal\Core\Config\FileStorage; /** * Tests CRUD operations on configuration objects. @@ -181,4 +182,53 @@ function testNameValidation() { $this->assertFalse(config_import(), "Config import failed when trying to importing an object with an invalid name"); } + /** + * Tests data type handling. + */ + function testDataTypes() { + module_enable(array('config_test')); + $storage = new FileStorage($this->configDirectories[CONFIG_ACTIVE_DIRECTORY]); + $name = 'config_test.types'; + $config = config($name); + + $original_content = file_get_contents($storage->getFilePath($name)); + $this->verbose('
' . $original_content . "\n" . var_export($storage->read($name), TRUE));
+
+    // Verify variable data types are intact.
+    $data = array(
+      'array' => array(),
+      'boolean' => TRUE,
+      'exp' => 1.2e+34,
+      'float' => 3.14159,
+      'hex' => 0xC,
+      'int' => 99,
+      'octal' => 0775,
+      'string' => 'string',
+      'string_int' => '1',
+    );
+    $this->assertIdentical($config->get(), $data);
+
+    // Re-set each key using Config::set().
+    foreach($data as $key => $value) {
+      $config->set($key, $value);
+    }
+    $config->save();
+    $this->assertIdentical($config->get(), $data);
+    $this->verbose('
' . file_get_contents($storage->getFilePath($name)) . var_export($storage->read($name), TRUE));
+
+    // Set data using config::setData().
+    $config->setData($data)->save();
+    $this->assertIdentical($config->get(), $data);
+
+    try {
+      $config->set('stream', fopen(__FILE__, 'r'))->save();
+      $this->fail('No Exception thrown upon saving invalid data type.');
+    }
+    catch (\Exception $e) {
+      $this->pass(format_string('%class thrown upon saving invalid data type.', array(
+        '%class' => get_class($e),
+      )));
+    }
+  }
+
 }
diff --git a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php
index a2b3448..8b3fc54 100644
--- a/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php
+++ b/core/modules/config/lib/Drupal/config/Tests/Storage/ConfigStorageTestBase.php
@@ -161,6 +161,30 @@ function testCRUD() {
 
   }
 
+  /**
+   * Tests storage controller writing and reading data preserving data type.
+   */
+  function testDataTypes() {
+    $name = 'config_test.types';
+    $data = array(
+      'array' => array(),
+      'boolean' => TRUE,
+      'exp' => 1.2e+34,
+      'float' => 3.14159,
+      'hex' => 0xC,
+      'int' => 99,
+      'octal' => 0775,
+      'string' => 'string',
+    );
+
+    $result = $this->storage->write($name, $data);
+    $this->assertIdentical($result, TRUE);
+
+    $read_data = $this->storage->read($name);
+    $this->assertIdentical($read_data, $data);
+  }
+
+
   abstract protected function read($name);
 
   abstract protected function insert($name, $data);
diff --git a/core/modules/config/tests/config_test/config/config_test.types.yml b/core/modules/config/tests/config_test/config/config_test.types.yml
new file mode 100644
index 0000000..4ab2cdc
--- /dev/null
+++ b/core/modules/config/tests/config_test/config/config_test.types.yml
@@ -0,0 +1,9 @@
+array: []
+boolean: true
+exp: 1.2e+34
+float: 3.14159
+hex: 0xC
+int: 99
+octal: 0775
+string: string
+string_int: '1'