Browse Source

Add JsonConfig configure engine.

ADmad 11 years ago
parent
commit
9d4893f591

+ 82 - 0
src/Core/Configure/Engine/JsonConfig.php

@@ -0,0 +1,82 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         3.0.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Core\Configure\Engine;
+
+use Cake\Core\Configure\ConfigEngineInterface;
+use Cake\Core\Configure\FileConfigTrait;
+use Cake\Core\Plugin;
+
+/**
+ * JSON engine allows Configure to load configuration values from
+ * files containing JSON strings.
+ */
+class JsonConfig implements ConfigEngineInterface
+{
+
+    use FileConfigTrait;
+
+    /**
+     * File extension.
+     *
+     * @var string
+     */
+    protected $_extension = '.json';
+
+    /**
+     * Constructor for JSON Config file reading.
+     *
+     * @param string|null $path The path to read config files from. Defaults to CONFIG.
+     */
+    public function __construct($path = null)
+    {
+        if ($path === null) {
+            $path = CONFIG;
+        }
+        $this->_path = $path;
+    }
+
+    /**
+     * Read a config file and return its contents.
+     *
+     * Files with `.` in the name will be treated as values in plugins. Instead of
+     * reading from the initialized path, plugin keys will be located using Plugin::path().
+     *
+     * @param string $key The identifier to read from. If the key has a . it will be treated
+     *   as a plugin prefix.
+     * @return array Parsed configuration values.
+     * @throws \Cake\Core\Exception\Exception When files don't exist or when
+     *   files contain '..' as this could lead to abusive reads.
+     */
+    public function read($key)
+    {
+        $file = $this->_getFilePath($key, true);
+        return (array)json_decode(file_get_contents($file), true);
+    }
+
+    /**
+     * Converts the provided $data into a JSON string that can be used saved
+     * into a file and loaded later.
+     *
+     * @param string $key The identifier to write to. If the key has a . it will
+     *  be treated as a plugin prefix.
+     * @param array $data Data to dump.
+     * @return int Bytes saved.
+     */
+    public function dump($key, array $data)
+    {
+        $filename = $this->_getFilePath($key);
+        return file_put_contents($filename, json_encode($data));
+    }
+}

+ 175 - 0
tests/TestCase/Core/Configure/Engine/JsonConfigTest.php

@@ -0,0 +1,175 @@
+<?php
+/**
+ * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
+ * @since         3.0.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Test\TestCase\Core\Configure\Engine;
+
+use Cake\Core\App;
+use Cake\Core\Configure\Engine\JsonConfig;
+use Cake\Core\Plugin;
+use Cake\TestSuite\TestCase;
+
+/**
+ * Class JsonConfigTest
+ *
+ */
+class JsonConfigTest extends TestCase
+{
+
+    /**
+     * Test data to serialize and unserialize.
+     *
+     * @var array
+     */
+    public $testData = [
+        'One' => [
+            'two' => 'value',
+            'three' => [
+                'four' => 'value four'
+            ],
+            'is_null' => null,
+            'bool_false' => false,
+            'bool_true' => true,
+        ],
+        'Asset' => [
+            'timestamp' => 'force'
+        ],
+    ];
+
+    /**
+     * Setup.
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        parent::setUp();
+        $this->path = CONFIG;
+    }
+
+    /**
+     * Test reading files.
+     *
+     * @return void
+     */
+    public function testRead()
+    {
+        $engine = new JsonConfig($this->path);
+        $values = $engine->read('json_test');
+        $this->assertEquals('value', $values['Json']);
+        $this->assertEquals('buried', $values['Deep']['Deeper']['Deepest']);
+    }
+
+    /**
+     * Test an exception is thrown by reading files that exist without .php extension.
+     *
+     * @expectedException \Cake\Core\Exception\Exception
+     * @return void
+     */
+    public function testReadWithExistentFileWithoutExtension()
+    {
+        $engine = new JsonConfig($this->path);
+        $engine->read('no_json_extension');
+    }
+
+    /**
+     * Test an exception is thrown by reading files that don't exist.
+     *
+     * @expectedException \Cake\Core\Exception\Exception
+     * @return void
+     */
+    public function testReadWithNonExistentFile()
+    {
+        $engine = new JsonConfig($this->path);
+        $engine->read('fake_values');
+    }
+
+    /**
+     * Test reading an empty file.
+     *
+     * @return void
+     */
+    public function testReadEmptyFile()
+    {
+        $engine = new JsonConfig($this->path);
+        $config = $engine->read('empty');
+        $this->assertEquals([], $config);
+    }
+
+    /**
+     * Test reading keys with ../ doesn't work.
+     *
+     * @expectedException \Cake\Core\Exception\Exception
+     * @return void
+     */
+    public function testReadWithDots()
+    {
+        $engine = new JsonConfig($this->path);
+        $engine->read('../empty');
+    }
+
+    /**
+     * Test reading from plugins.
+     *
+     * @return void
+     */
+    public function testReadPluginValue()
+    {
+        Plugin::load('TestPlugin');
+        $engine = new JsonConfig($this->path);
+        $result = $engine->read('TestPlugin.load');
+        $this->assertTrue(isset($result['plugin_load']));
+
+        Plugin::unload();
+    }
+
+    /**
+     * Test dumping data to json format.
+     *
+     * @return void
+     */
+    public function testDump()
+    {
+        $engine = new JsonConfig(TMP);
+        $result = $engine->dump('test', $this->testData);
+        $this->assertTrue($result > 0);
+        $expected = '{"One":{"two":"value","three":{"four":"value four"},"is_null":null,"bool_false":false,"bool_true":true},"Asset":{"timestamp":"force"}}';
+        $file = TMP . 'test.json';
+        $contents = file_get_contents($file);
+
+        unlink($file);
+        $this->assertTextEquals($expected, $contents);
+
+        $result = $engine->dump('test', $this->testData);
+        $this->assertTrue($result > 0);
+
+        $contents = file_get_contents($file);
+        $this->assertTextEquals($expected, $contents);
+        unlink($file);
+    }
+
+    /**
+     * Test that dump() makes files read() can read.
+     *
+     * @return void
+     */
+    public function testDumpRead()
+    {
+        $engine = new JsonConfig(TMP);
+        $engine->dump('test', $this->testData);
+        $result = $engine->read('test');
+        unlink(TMP . 'test.json');
+
+        $this->assertEquals($this->testData, $result);
+    }
+}

+ 1 - 0
tests/test_app/Plugin/TestPlugin/config/load.json

@@ -0,0 +1 @@
+{"plugin_load":"\/test_app\/Plugin\/TestPlugin\/Config\/load.json"}

+ 0 - 0
tests/test_app/config/empty.json


+ 1 - 0
tests/test_app/config/json_test.json

@@ -0,0 +1 @@
+{"Json":"value","Deep":{"Deeper":{"Deepest":"buried"}},"TestAcl":{"classname":"Original"}}

+ 1 - 0
tests/test_app/config/no_json_extension

@@ -0,0 +1 @@
+{"Deep":{"Third":{"ThirdDeepest":"buried3"}}}