Permalink
Browse files

Merge branch '2.2-configure' into 2.2

  • Loading branch information...
2 parents b57489f + e18200a commit 1b288b74d9b17bdaa13974ad90063d78f5da7a1f @markstory markstory committed May 3, 2012
@@ -16,13 +16,15 @@
* @since CakePHP(tm) v 2.0
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
+App::uses('Hash', 'Utility');
/**
- * Ini file configuration parser. Since IniReader uses parse_ini_file underneath,
- * you should be aware that this class shares the same behavior, especially with
- * regards to boolean and null values.
+ * Ini file configuration engine.
*
- * In addition to the native parse_ini_file features, IniReader also allows you
+ * Since IniReader uses parse_ini_file underneath, you should be aware that this
+ * class shares the same behavior, especially with regards to boolean and null values.
+ *
+ * In addition to the native `parse_ini_file` features, IniReader also allows you
* to create nested array structures through usage of `.` delimited names. This allows
* you to create nested arrays structures in an ini config file. For example:
*
@@ -126,6 +128,7 @@ protected function _parseNestedValues($values) {
if ($value === '') {
$value = false;
}
+ unset($values[$key]);
if (strpos($key, '.') !== false) {
$values = Hash::insert($values, $key, $value);
} else {
@@ -135,4 +138,47 @@ protected function _parseNestedValues($values) {
return $values;
}
+/**
+ * Dumps the state of Configure data into an ini formatted string.
+ *
+ * @param string $filename The filename on $this->_path to save into.
+ * @param array $data The data to convert to ini file.
+ * @return int Bytes saved.
+ */
+ public function dump($filename, $data) {
+ $result = array();
+ foreach ($data as $key => $value) {
+ if ($key[0] != '[') {
+ $result[] = "[$key]";
+ }
+ if (is_array($value)) {
+ $keyValues = Hash::flatten($value, '.');
+ foreach ($keyValues as $k => $v) {
+ $result[] = "$k = " . $this->_value($v);
+ }
+ }
+ }
+ $contents = join("\n", $result);
+ return file_put_contents($this->_path . $filename, $contents);
+ }
+
+/**
+ * Converts a value into the ini equivalent
+ *
+ * @param mixed $value to export.
+ * @return string String value for ini file.
+ */
+ protected function _value($val) {
+ if ($val === null) {
+ return 'null';
+ }
+ if ($val === true) {
+ return 'true';
+ }
+ if ($val === false) {
+ return 'false';
+ }
+ return (string)$val;
+ }
+
}
@@ -87,4 +87,17 @@ public function read($key) {
return $config;
}
+/**
+ * Converts the provided $data into a string of PHP code that can
+ * be used saved into a file and loaded later.
+ *
+ * @param string $filename The filename to create on $this->_path.
+ * @param array $data Data to dump.
+ * @return int Bytes saved.
+ */
+ public function dump($filename, $data) {
+ $contents = '<?php' . "\n" . '$config = ' . var_export($data, true) . ';';
+ return file_put_contents($this->_path . $filename, $contents);
+ }
+
}
@@ -279,6 +279,45 @@ public static function load($key, $config = 'default', $merge = true) {
}
/**
+ * Dump data currently in Configure into $filename. The serialization format
+ * is decided by the config reader attached as $config. For example, if the
+ * 'default' adapter is a PhpReader, the generated file will be a PHP
+ * configuration file loadable by the PhpReader.
+ *
+ * ## Usage
+ *
+ * Given that the 'default' reader is an instance of PhpReader.
+ * Save all data in Configure to the file `my_config.php`:
+ *
+ * `Configure::dump('my_config.php', 'default');`
+ *
+ * Save only the error handling configuration:
+ *
+ * `Configure::dump('error.php', 'default', array('Error', 'Exception');`
+ *
+ * @param string $key The identifier to create in the config adapter.
+ * This could be a filename or a cache key depending on the adapter being used.
+ * @param string $config The name of the configured adapter to dump data with.
+ * @param array $keys The name of the top-level keys you want to dump.
+ * This allows you save only some data stored in Configure.
+ * @return boolean success
+ * @throws ConfigureException if the adapter does not implement a `dump` method.
+ */
+ public static function dump($key, $config = 'default', $keys = array()) {
+ if (empty(self::$_readers[$config])) {
+ throw new ConfigureException(__d('cake', 'There is no "%s" adapter.', $config));
+ }
+ if (!method_exists(self::$_readers[$config], 'dump')) {
+ throw new ConfigureException(__d('cake', 'The "%s" adapter, does not have a dump() method.', $config));
+ }
+ $values = self::$_values;
+ if (!empty($keys) && is_array($keys)) {
+ $values = array_intersect_key($values, array_flip($keys));
+ }
+ return (bool)self::$_readers[$config]->dump($key, $values);
+ }
+
+/**
* Used to determine the current version of CakePHP.
*
* Usage `Configure::version();`
@@ -21,11 +21,24 @@
class IniReaderTest extends CakeTestCase {
/**
- * The test file that will be read.
+ * Test data to serialize and unserialize.
*
- * @var string
+ * @var array
*/
- public $file;
+ public $testData = array(
+ 'One' => array(
+ 'two' => 'value',
+ 'three' => array(
+ 'four' => 'value four'
+ ),
+ 'is_null' => null,
+ 'bool_false' => false,
+ 'bool_true' => true,
+ ),
+ 'Asset' => array(
+ 'timestamp' => 'force'
+ ),
+ );
/**
* setup
@@ -92,6 +105,8 @@ public function testReadingValuesWithDots() {
$this->assertTrue(isset($config['database']['db']['username']));
$this->assertEquals('mark', $config['database']['db']['username']);
$this->assertEquals(3, $config['nesting']['one']['two']['three']);
+ $this->assertFalse(isset($config['database.db.username']));
+ $this->assertFalse(isset($config['database']['db.username']));
}
/**
@@ -125,4 +140,49 @@ public function testReadingWithoutExtension() {
$config = $reader->read('nested');
$this->assertTrue($config['bools']['test_on']);
}
+
+/**
+ * test dump method.
+ *
+ * @return void
+ */
+ public function testDump() {
+ $reader = new IniReader(TMP);
+ $result = $reader->dump('test.ini', $this->testData);
+ $this->assertTrue($result > 0);
+
+ $expected = <<<INI
+[One]
+two = value
+three.four = value four
+is_null = null
+bool_false = false
+bool_true = true
+[Asset]
+timestamp = force
+INI;
+ $file = TMP . 'test.ini';
+ $result = file_get_contents($file);
+ unlink($file);
+
+ $this->assertTextEquals($expected, $result);
+ }
+
+/**
+ * Test that dump() makes files read() can read.
+ *
+ * @return void
+ */
+ public function testDumpRead() {
+ $reader = new IniReader(TMP);
+ $reader->dump('test.ini', $this->testData);
+ $result = $reader->read('test.ini');
+ unlink(TMP . 'test.ini');
+
+ $expected = $this->testData;
+ $expected['One']['is_null'] = false;
+
+ $this->assertEquals($expected, $result);
+ }
+
}
@@ -21,6 +21,26 @@
class PhpReaderTest extends CakeTestCase {
/**
+ * Test data to serialize and unserialize.
+ *
+ * @var array
+ */
+ public $testData = array(
+ 'One' => array(
+ 'two' => 'value',
+ 'three' => array(
+ 'four' => 'value four'
+ ),
+ 'is_null' => null,
+ 'bool_false' => false,
+ 'bool_true' => true,
+ ),
+ 'Asset' => array(
+ 'timestamp' => 'force'
+ ),
+ );
+
+/**
* setup
*
* @return void
@@ -96,4 +116,55 @@ public function testReadPluginValue() {
$this->assertTrue(isset($result['plugin_load']));
CakePlugin::unload();
}
+
+/**
+ * Test dumping data to PHP format.
+ *
+ * @return void
+ */
+ public function testDump() {
+ $reader = new PhpReader(TMP);
+ $result = $reader->dump('test.php', $this->testData);
+ $this->assertTrue($result > 0);
+ $expected = <<<PHP
+<?php
+\$config = array (
+ 'One' =>
+ array (
+ 'two' => 'value',
+ 'three' =>
+ array (
+ 'four' => 'value four',
+ ),
+ 'is_null' => NULL,
+ 'bool_false' => false,
+ 'bool_true' => true,
+ ),
+ 'Asset' =>
+ array (
+ 'timestamp' => 'force',
+ ),
+);
+PHP;
+ $file = TMP . 'test.php';
+ $contents = file_get_contents($file);
+
+ unlink($file);
+ $this->assertTextEquals($expected, $contents);
+ }
+
+/**
+ * Test that dump() makes files read() can read.
+ *
+ * @return void
+ */
+ public function testDumpRead() {
+ $reader = new PhpReader(TMP);
+ $reader->dump('test.php', $this->testData);
+ $result = $reader->read('test.php');
+ unlink(TMP . 'test.php');
+
+ $this->assertEquals($this->testData, $result);
+ }
+
}
@@ -362,4 +362,47 @@ public function testClear() {
$this->assertNull(Configure::read('debug'));
$this->assertNull(Configure::read('test'));
}
+
+/**
+ * @expectedException ConfigureException
+ */
+ public function testDumpNoAdapter() {
+ Configure::dump(TMP . 'test.php', 'does_not_exist');
+ }
+
+/**
+ * test dump integrated with the PhpReader.
+ *
+ * @return void
+ */
+ public function testDump() {
+ Configure::config('test_reader', new PhpReader(TMP));
+
+ $result = Configure::dump('config_test.php', 'test_reader');
+ $this->assertTrue($result > 0);
+ $result = file_get_contents(TMP . 'config_test.php');
+ $this->assertContains('<?php', $result);
+ $this->assertContains('$config = ', $result);
+ @unlink(TMP . 'config_test.php');
+ }
+
+/**
+ * Test dumping only some of the data.
+ *
+ * @return
+ */
+ public function testDumpPartial() {
+ Configure::config('test_reader', new PhpReader(TMP));
+
+ $result = Configure::dump('config_test.php', 'test_reader', array('Error'));
+ $this->assertTrue($result > 0);
+ $result = file_get_contents(TMP . 'config_test.php');
+ $this->assertContains('<?php', $result);
+ $this->assertContains('$config = ', $result);
+ $this->assertContains('Error', $result);
+ $this->assertNotContains('debug', $result);
+
+ @unlink(TMP . 'config_test.php');
+ }
+
}

0 comments on commit 1b288b7

Please sign in to comment.