diff --git a/composer.json b/composer.json index 8c57f67..bb807e0 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } }, "require": { - "php": ">=5.3.3", + "php": ">=5.3.23", "zendframework/zend-stdlib": "self.version" }, "require-dev": { @@ -33,8 +33,8 @@ }, "extra": { "branch-alias": { - "dev-master": "2.2-dev", - "dev-develop": "2.3-dev" + "dev-master": "2.3-dev", + "dev-develop": "2.4-dev" } }, "autoload-dev": { diff --git a/src/AbstractConfigFactory.php b/src/AbstractConfigFactory.php new file mode 100644 index 0000000..20f04be --- /dev/null +++ b/src/AbstractConfigFactory.php @@ -0,0 +1,172 @@ +configs[$requestedName])) { + return true; + } + + if (!$serviceLocator->has('Config')) { + return false; + } + + $key = $this->match($requestedName); + if (null === $key) { + return false; + } + + $config = $serviceLocator->get('Config'); + return isset($config[$key]); + } + + /** + * Create service with name + * + * @param ServiceManager\ServiceLocatorInterface $serviceLocator + * @param string $name + * @param string $requestedName + * @return string|mixed|array + */ + public function createServiceWithName(ServiceManager\ServiceLocatorInterface $serviceLocator, $name, $requestedName) + { + if (isset($this->configs[$requestedName])) { + return $this->configs[$requestedName]; + } + + $key = $this->match($requestedName); + if (isset($this->configs[$key])) { + $this->configs[$requestedName] = $this->configs[$key]; + return $this->configs[$key]; + } + + $config = $serviceLocator->get('Config'); + $this->configs[$requestedName] = $this->configs[$key] = $config[$key]; + return $config; + } + + /** + * @param string $pattern + * @return self + * @throws Exception\InvalidArgumentException + */ + public function addPattern($pattern) + { + if (!is_string($pattern)) { + throw new Exception\InvalidArgumentException('pattern must be string'); + } + + $patterns = $this->getPatterns(); + array_unshift($patterns, $pattern); + $this->setPatterns($patterns); + return $this; + } + + /** + * @param array|Traversable $patterns + * @return self + * @throws Exception\InvalidArgumentException + */ + public function addPatterns($patterns) + { + if ($patterns instanceof Traversable) { + $patterns = iterator_to_array($patterns); + } + + if (!is_array($patterns)) { + throw new Exception\InvalidArgumentException("patterns must be array or Traversable"); + } + + foreach ($patterns as $pattern) { + $this->addPattern($pattern); + } + + return $this; + } + + /** + * @param array|Traversable $patterns + * @return self + * @throws \InvalidArgumentException + */ + public function setPatterns($patterns) + { + if ($patterns instanceof Traversable) { + $patterns = iterator_to_array($patterns); + } + + if (!is_array($patterns)) { + throw new \InvalidArgumentException("patterns must be array or Traversable"); + } + + $this->patterns = $patterns; + return $this; + } + + /** + * @return array + */ + public function getPatterns() + { + if (null === $this->patterns) { + $this->setPatterns($this->defaultPatterns); + } + return $this->patterns; + } + + /** + * @param string $requestedName + * @return null|string + */ + protected function match($requestedName) + { + foreach ($this->getPatterns() as $pattern) { + if (preg_match($pattern, $requestedName, $matches)) { + return $matches[1]; + } + } + return null; + } +} diff --git a/src/Factory.php b/src/Factory.php index ba7ef07..3cadb81 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -59,13 +59,34 @@ class Factory * * @param string $filename * @param bool $returnConfigObject + * @param bool $useIncludePath * @return array|Config * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException */ - public static function fromFile($filename, $returnConfigObject = false) + public static function fromFile($filename, $returnConfigObject = false, $useIncludePath = false) { - $pathinfo = pathinfo($filename); + $filepath = $filename; + if (!file_exists($filename)) { + if (!$useIncludePath) { + throw new Exception\RuntimeException(sprintf( + 'Filename "%s" cannot be found relative to the working directory', + $filename + )); + } + + $fromIncludePath = stream_resolve_include_path($filename); + if (!$fromIncludePath) { + throw new Exception\RuntimeException(sprintf( + 'Filename "%s" cannot be found relative to the working directory or the include_path ("%s")', + $filename, + get_include_path() + )); + } + $filepath = $fromIncludePath; + } + + $pathinfo = pathinfo($filepath); if (!isset($pathinfo['extension'])) { throw new Exception\RuntimeException(sprintf( @@ -77,14 +98,14 @@ public static function fromFile($filename, $returnConfigObject = false) $extension = strtolower($pathinfo['extension']); if ($extension === 'php') { - if (!is_file($filename) || !is_readable($filename)) { + if (!is_file($filepath) || !is_readable($filepath)) { throw new Exception\RuntimeException(sprintf( "File '%s' doesn't exist or not readable", $filename )); } - $config = include $filename; + $config = include $filepath; } elseif (isset(static::$extensions[$extension])) { $reader = static::$extensions[$extension]; if (!$reader instanceof Reader\ReaderInterface) { @@ -93,7 +114,7 @@ public static function fromFile($filename, $returnConfigObject = false) } /** @var Reader\ReaderInterface $reader */ - $config = $reader->fromFile($filename); + $config = $reader->fromFile($filepath); } else { throw new Exception\RuntimeException(sprintf( 'Unsupported config file extension: .%s', @@ -109,14 +130,15 @@ public static function fromFile($filename, $returnConfigObject = false) * * @param array $files * @param bool $returnConfigObject + * @param bool $useIncludePath * @return array|Config */ - public static function fromFiles(array $files, $returnConfigObject = false) + public static function fromFiles(array $files, $returnConfigObject = false, $useIncludePath = false) { $config = array(); foreach ($files as $file) { - $config = ArrayUtils::merge($config, static::fromFile($file)); + $config = ArrayUtils::merge($config, static::fromFile($file, false, $useIncludePath)); } return ($returnConfigObject) ? new Config($config) : $config; diff --git a/src/Processor/Token.php b/src/Processor/Token.php index cff098b..2af2e1b 100644 --- a/src/Processor/Token.php +++ b/src/Processor/Token.php @@ -176,17 +176,30 @@ public function setToken($token, $value) /** * Build replacement map + * + * @return array */ protected function buildMap() { - if (!$this->suffix && !$this->prefix) { - $this->map = $this->tokens; - } else { - $this->map = array(); - foreach ($this->tokens as $token => $value) { - $this->map[$this->prefix . $token . $this->suffix] = $value; + if (null === $this->map) { + if (!$this->suffix && !$this->prefix) { + $this->map = $this->tokens; + } else { + $this->map = array(); + + foreach ($this->tokens as $token => $value) { + $this->map[$this->prefix . $token . $this->suffix] = $value; + } + } + + foreach (array_keys($this->map) as $key) { + if (empty($key)) { + unset($this->map[$key]); + } } } + + return $this->map; } /** @@ -198,28 +211,7 @@ protected function buildMap() */ public function process(Config $config) { - if ($config->isReadOnly()) { - throw new Exception\InvalidArgumentException('Cannot process config because it is read-only'); - } - - if ($this->map === null) { - $this->buildMap(); - } - - /** - * Walk through config and replace values - */ - $keys = array_keys($this->map); - $values = array_values($this->map); - foreach ($config as $key => $val) { - if ($val instanceof Config) { - $this->process($val); - } else { - $config->$key = str_replace($keys, $values, $val); - } - } - - return $config; + return $this->doProcess($config, $this->buildMap()); } /** @@ -230,12 +222,53 @@ public function process(Config $config) */ public function processValue($value) { - if ($this->map === null) { - $this->buildMap(); + return $this->doProcess($value, $this->buildMap()); + } + + /** + * Applies replacement map to the given value by modifying the value itself + * + * @param mixed $value + * @param array $replacements + * + * @return mixed + * + * @throws Exception\InvalidArgumentException if the provided value is a read-only {@see Config} + */ + private function doProcess($value, array $replacements) + { + if ($value instanceof Config) { + if ($value->isReadOnly()) { + throw new Exception\InvalidArgumentException('Cannot process config because it is read-only'); + } + + foreach ($value as $key => $val) { + $value->$key = $this->doProcess($val, $replacements); + } + + return $value; + } + + if ($value instanceof Traversable || is_array($value)) { + foreach ($value as & $val) { + $val = $this->doProcess($val, $replacements); + } + + return $value; + } + + if (!is_string($value) && (is_bool($value) || is_numeric($value))) { + $stringVal = (string) $value; + $changedVal = strtr($value, $this->map); + + // replace the value only if a string replacement occurred + if ($changedVal !== $stringVal) { + return $changedVal; + } + + return $value; } - $keys = array_keys($this->map); - $values = array_values($this->map); - return str_replace($keys, $values, $value); + return strtr((string) $value, $this->map); } } diff --git a/src/Processor/Translator.php b/src/Processor/Translator.php index 62a2521..48c0985 100644 --- a/src/Processor/Translator.php +++ b/src/Processor/Translator.php @@ -130,7 +130,7 @@ public function process(Config $config) * Process a single value * * @param $value - * @return mixed + * @return string */ public function processValue($value) { diff --git a/src/Reader/JavaProperties.php b/src/Reader/JavaProperties.php new file mode 100644 index 0000000..abd2ceb --- /dev/null +++ b/src/Reader/JavaProperties.php @@ -0,0 +1,138 @@ +directory = dirname($filename); + + $config = $this->parse(file_get_contents($filename)); + + return $this->process($config); + } + + /** + * fromString(): defined by Reader interface. + * + * @see ReaderInterface::fromString() + * @param string $string + * @return array + * @throws Exception\RuntimeException if an @include key is found + */ + public function fromString($string) + { + if (empty($string)) { + return array(); + } + + $this->directory = null; + + $config = $this->parse($string); + + return $this->process($config); + } + + /** + * Process the array for @include + * + * @param array $data + * @return array + * @throws Exception\RuntimeException if an @include key is found + */ + protected function process(array $data) + { + foreach ($data as $key => $value) { + if (trim($key) === '@include') { + if ($this->directory === null) { + throw new Exception\RuntimeException('Cannot process @include statement for a string'); + } + $reader = clone $this; + unset($data[$key]); + $data = array_replace_recursive($data, $reader->fromFile($this->directory . '/' . $value)); + } + } + return $data; + } + + /** + * Parse Java-style properties string + * + * @todo Support use of the equals sign "key=value" as key-value delimiter + * @todo Ignore whitespace that precedes text past the first line of multiline values + * + * @param string $string + * @return array + */ + protected function parse($string) + { + $result = array(); + $lines = explode("\n", $string); + $key = ""; + $isWaitingOtherLine = false; + foreach ($lines as $i => $line) { + // Ignore empty lines and commented lines + if (empty($line) + || (!$isWaitingOtherLine && strpos($line, "#") === 0) + || (!$isWaitingOtherLine && strpos($line, "!") === 0)) { + continue; + } + + // Add a new key-value pair or append value to a previous pair + if (!$isWaitingOtherLine) { + $key = substr($line, 0, strpos($line, ':')); + $value = substr($line, strpos($line, ':') + 1, strlen($line)); + } else { + $value .= $line; + } + + // Check if ends with single '\' (indicating another line is expected) + if (strrpos($value, "\\") === strlen($value) - strlen("\\")) { + $value = substr($value, 0, strlen($value) - 1); + $isWaitingOtherLine = true; + } else { + $isWaitingOtherLine = false; + } + + $result[$key] = stripslashes($value); + unset($lines[$i]); + } + + return $result; + } +} diff --git a/src/Writer/PhpArray.php b/src/Writer/PhpArray.php index fa33604..818a353 100644 --- a/src/Writer/PhpArray.php +++ b/src/Writer/PhpArray.php @@ -9,8 +9,20 @@ namespace Zend\Config\Writer; +use Zend\Config\Exception; + class PhpArray extends AbstractWriter { + /** + * @var string + */ + const INDENT_STRING = ' '; + + /** + * @var bool + */ + protected $useBracketArraySyntax = false; + /** * processConfig(): defined by AbstractWriter. * @@ -19,8 +31,110 @@ class PhpArray extends AbstractWriter */ public function processConfig(array $config) { - $arrayString = " $this->useBracketArraySyntax ? '[' : 'array(', + 'close' => $this->useBracketArraySyntax ? ']' : ')' + ); + + return "processIndented($config, $arraySyntax) . + $arraySyntax['close'] . ";\n"; + } + + /** + * Sets whether or not to use the PHP 5.4+ "[]" array syntax. + * + * @param bool $value + * @return self + */ + public function setUseBracketArraySyntax($value) + { + $this->useBracketArraySyntax = $value; + return $this; + } + + /** + * toFile(): defined by Writer interface. + * + * @see WriterInterface::toFile() + * @param string $filename + * @param mixed $config + * @param bool $exclusiveLock + * @return void + * @throws Exception\InvalidArgumentException + * @throws Exception\RuntimeException + */ + public function toFile($filename, $config, $exclusiveLock = true) + { + if (empty($filename)) { + throw new Exception\InvalidArgumentException('No file name specified'); + } + + $flags = 0; + if ($exclusiveLock) { + $flags |= LOCK_EX; + } + + set_error_handler( + function ($error, $message = '', $file = '', $line = 0) use ($filename) { + throw new Exception\RuntimeException(sprintf( + 'Error writing to "%s": %s', + $filename, $message + ), $error); + }, E_WARNING + ); + + try { + // for Windows, paths are escaped. + $dirname = str_replace('\\', '\\\\', dirname($filename)); + + $string = $this->toString($config); + $string = str_replace("'" . $dirname, "__DIR__ . '", $string); + + file_put_contents($filename, $string, $flags); + } catch (\Exception $e) { + restore_error_handler(); + throw $e; + } + + restore_error_handler(); + } + + /** + * Recursively processes a PHP config array structure into a readable format. + * + * @param array $config + * @param array $arraySyntax + * @param int $indentLevel + * @return string + */ + protected function processIndented(array $config, array $arraySyntax, &$indentLevel = 1) + { + $arrayString = ""; + + foreach ($config as $key => $value) { + $arrayString .= str_repeat(self::INDENT_STRING, $indentLevel); + $arrayString .= (is_int($key) ? $key : "'" . addslashes($key) . "'") . ' => '; + + if (is_array($value)) { + if ($value === array()) { + $arrayString .= $arraySyntax['open'] . $arraySyntax['close'] . ",\n"; + } else { + $indentLevel++; + $arrayString .= $arraySyntax['open'] . "\n" + . $this->processIndented($value, $arraySyntax, $indentLevel) + . str_repeat(self::INDENT_STRING, --$indentLevel) . $arraySyntax['close'] . ",\n"; + } + } elseif (is_object($value) || is_string($value)) { + $arrayString .= var_export($value, true) . ",\n"; + } elseif (is_bool($value)) { + $arrayString .= ($value ? 'true' : 'false') . ",\n"; + } elseif ($value === null) { + $arrayString .= "null,\n"; + } else { + $arrayString .= $value . ",\n"; + } + } return $arrayString; } diff --git a/src/Writer/Xml.php b/src/Writer/Xml.php index 3f46c7d..0fd36b9 100644 --- a/src/Writer/Xml.php +++ b/src/Writer/Xml.php @@ -22,7 +22,7 @@ class Xml extends AbstractWriter */ public function processConfig(array $config) { - $writer = new XMLWriter('UTF-8'); + $writer = new XMLWriter(); $writer->openMemory(); $writer->setIndent(true); $writer->setIndentString(str_repeat(' ', 4)); diff --git a/test/AbstractConfigFactoryTest.php b/test/AbstractConfigFactoryTest.php new file mode 100644 index 0000000..a23d6f7 --- /dev/null +++ b/test/AbstractConfigFactoryTest.php @@ -0,0 +1,134 @@ + + * @link http://github.com/zendframework/zf2 for the canonical source repository + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +namespace ZendTest\Config; + +use Zend\Config\AbstractConfigFactory; +use Zend\Mvc\Service\ServiceManagerConfig; +use Zend\ServiceManager; + +/** + * Class AbstractConfigFactoryTest + */ +class AbstractConfigFactoryTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Zend\Mvc\Application + */ + protected $application; + + /** + * @var \Zend\ServiceManager\ServiceManager + */ + protected $serviceManager; + + /** + * @return void + */ + public function setUp() + { + $config = array( + 'MyModule' => array( + 'foo' => array( + 'bar' + ) + ), + 'phly-blog' => array( + 'foo' => array( + 'bar' + ) + ) + ); + + $sm = $this->serviceManager = new ServiceManager\ServiceManager( + new ServiceManagerConfig(array( + 'abstract_factories' => array( + 'Zend\Config\AbstractConfigFactory', + ) + )) + ); + + $sm->setService('Config', $config); + } + + /** + * @expectedException InvalidArgumentException + * @return void + */ + public function testInvalidPattern() + { + $factory = new AbstractConfigFactory(); + $factory->addPattern(new \stdClass()); + } + + /** + * @expectedException InvalidArgumentException + * @return void + */ + public function testInvalidPatternIterator() + { + $factory = new AbstractConfigFactory(); + $factory->addPatterns('invalid'); + } + + /** + * @return void + */ + public function testPatterns() + { + $factory = new AbstractConfigFactory(); + $defaults = $factory->getPatterns(); + + // Tests that the accessor returns an array + $this->assertInternalType('array', $defaults); + $this->assertGreaterThan(0, count($defaults)); + + // Tests adding a single pattern + $this->assertSame($factory, $factory->addPattern('#foobarone#i')); + $this->assertCount(count($defaults) + 1, $factory->getPatterns()); + + // Tests adding multiple patterns at once + $patterns = $factory->getPatterns(); + $this->assertSame($factory, $factory->addPatterns(array('#foobartwo#i', '#foobarthree#i'))); + $this->assertCount(count($patterns) + 2, $factory->getPatterns()); + + // Tests whether the latest added pattern is the first in stack + $patterns = $factory->getPatterns(); + $this->assertSame('#foobarthree#i', $patterns[0]); + } + + /** + * @return void + */ + public function testCanCreateService() + { + $factory = new AbstractConfigFactory(); + $serviceLocator = $this->serviceManager; + + $this->assertFalse($factory->canCreateServiceWithName($serviceLocator, 'mymodulefail', 'MyModule\Fail')); + $this->assertTrue($factory->canCreateServiceWithName($serviceLocator, 'mymoduleconfig', 'MyModule\Config')); + } + + /** + * @depends testCanCreateService + * @return void + */ + public function testCreateService() + { + $serviceLocator = $this->serviceManager; + $this->assertInternalType('array', $serviceLocator->get('MyModule\Config')); + $this->assertInternalType('array', $serviceLocator->get('MyModule_Config')); + $this->assertInternalType('array', $serviceLocator->get('Config.MyModule')); + $this->assertInternalType('array', $serviceLocator->get('phly-blog.config')); + $this->assertInternalType('array', $serviceLocator->get('phly-blog-config')); + $this->assertInternalType('array', $serviceLocator->get('config-phly-blog')); + } +} diff --git a/test/ConfigTest.php b/test/ConfigTest.php index 5075f1e..f89d0ae 100644 --- a/test/ConfigTest.php +++ b/test/ConfigTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/FactoryTest.php b/test/FactoryTest.php index fa03b44..69ecfa4 100644 --- a/test/FactoryTest.php +++ b/test/FactoryTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -17,6 +17,7 @@ class FactoryTest extends \PHPUnit_Framework_TestCase { protected $tmpFiles = array(); + protected $originalIncludePath; protected function getTestAssetFileName($ext) { @@ -26,8 +27,16 @@ protected function getTestAssetFileName($ext) return $this->tmpfiles[$ext]; } + public function setUp() + { + $this->originalIncludePath = get_include_path(); + set_include_path(__DIR__ . '/TestAssets'); + } + public function tearDown() { + set_include_path($this->originalIncludePath); + foreach ($this->tmpFiles as $file) { if (file_exists($file)) { if (!is_writable($file)) { @@ -102,6 +111,20 @@ public function testFromIniAndXmlAndPhpFiles() $this->assertEquals('baz', $config['last']['bar']); } + public function testFromIniAndXmlAndPhpFilesFromIncludePath() + { + $files = array ( + 'Ini/include-base.ini', + 'Xml/include-base2.xml', + 'Php/include-base3.php', + ); + $config = Factory::fromFiles($files, false, true); + + $this->assertEquals('bar', $config['base']['foo']); + $this->assertEquals('baz', $config['test']['bar']); + $this->assertEquals('baz', $config['last']['bar']); + } + public function testReturnsConfigObjectIfRequestedAndArrayOtherwise() { $files = array ( @@ -177,13 +200,12 @@ public function testFactoryWriteToFile() // build string line by line as we are trailing-whitespace sensitive. $expected = " 'foo',\n"; - $expected .= " 'bar' => \n"; - $expected .= " array (\n"; - $expected .= " 0 => 'baz',\n"; - $expected .= " 1 => 'foo',\n"; - $expected .= " ),\n"; + $expected .= "return array(\n"; + $expected .= " 'test' => 'foo',\n"; + $expected .= " 'bar' => array(\n"; + $expected .= " 0 => 'baz',\n"; + $expected .= " 1 => 'foo',\n"; + $expected .= " ),\n"; $expected .= ");\n"; $this->assertEquals(true, $result); diff --git a/test/ProcessorTest.php b/test/ProcessorTest.php index 02fd833..b20bc23 100644 --- a/test/ProcessorTest.php +++ b/test/ProcessorTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -268,6 +268,75 @@ public function testTokenChangeParams() $this->assertEquals('@@ some text with some replaced value inside @@', $config->nested->inside); } + /** + * @group ZF2-5772 + */ + public function testTokenChangeParamsRetainsType() + { + $config = new Config( + array( + 'trueBoolKey' => true, + 'falseBoolKey' => false, + 'intKey' => 123, + 'floatKey' => (float) 123.456, + 'doubleKey' => (double) 456.789, + ), + true + ); + + $processor = new TokenProcessor(); + + $processor->process($config); + + $this->assertSame(true, $config['trueBoolKey']); + $this->assertSame(false, $config['falseBoolKey']); + $this->assertSame(123, $config['intKey']); + $this->assertSame((float) 123.456, $config['floatKey']); + $this->assertSame((double) 456.789, $config['doubleKey']); + } + + /** + * @group ZF2-5772 + */ + public function testTokenChangeParamsReplacesInNumerics() + { + $config = new Config( + array( + 'foo' => 'bar1', + 'trueBoolKey' => true, + 'falseBoolKey' => false, + 'intKey' => 123, + 'floatKey' => (float) 123.456, + 'doubleKey' => (double) 456.789, + ), + true + ); + + $processor = new TokenProcessor(array('1' => 'R', '9' => 'R')); + + $processor->process($config); + + $this->assertSame('R', $config['trueBoolKey']); + $this->assertSame('barR', $config['foo']); + $this->assertSame(false, $config['falseBoolKey']); + $this->assertSame('R23', $config['intKey']); + $this->assertSame('R23.456', $config['floatKey']); + $this->assertSame('456.78R', $config['doubleKey']); + } + + /** + * @group ZF2-5772 + */ + public function testIgnoresEmptyStringReplacement() + { + $config = new Config(array('foo' => 'bar'), true); + $processor = new TokenProcessor(array('' => 'invalid')); + + $processor->process($config); + + $this->assertSame('bar', $config['foo']); + } + /** * @depends testTokenSurround */ diff --git a/test/Reader/AbstractReaderTestCase.php b/test/Reader/AbstractReaderTestCase.php index cb3b777..66e8f25 100644 --- a/test/Reader/AbstractReaderTestCase.php +++ b/test/Reader/AbstractReaderTestCase.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Reader/IniTest.php b/test/Reader/IniTest.php index cb046c1..1413366 100644 --- a/test/Reader/IniTest.php +++ b/test/Reader/IniTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Reader/JavaPropertiesTest.php b/test/Reader/JavaPropertiesTest.php new file mode 100644 index 0000000..7f898aa --- /dev/null +++ b/test/Reader/JavaPropertiesTest.php @@ -0,0 +1,79 @@ +reader = new JavaProperties(); + } + + /** + * getTestAssetPath(): defined by AbstractReaderTestCase. + * + * @see AbstractReaderTestCase::getTestAssetPath() + * @return string + */ + protected function getTestAssetPath($name) + { + return __DIR__ . '/TestAssets/JavaProperties/' . $name . '.properties'; + } + + public function testFromFile() + { + $arrayJavaProperties = $this->reader->fromFile($this->getTestAssetPath('include-target')); + + $this->assertNotEmpty($arrayJavaProperties); + $this->assertEquals($arrayJavaProperties['single.line'], 'test'); + $this->assertEquals($arrayJavaProperties['multiple'], 'line test'); + } + + public function testIncludeAsElement() + { + $arrayJavaProperties = $this->reader->fromFile($this->getTestAssetPath('include-base')); + + $this->assertNotEmpty($arrayJavaProperties); + $this->assertEquals($arrayJavaProperties['single.line'], 'test'); + $this->assertEquals($arrayJavaProperties['multiple'], 'line test'); + } + + public function testFromString() + { + $JavaProperties = <<<'ASSET' +#comment +!comment +single.line:test +multiple:line \ +test +ASSET; + + $arrayJavaProperties = $this->reader->fromString($JavaProperties); + + $this->assertNotEmpty($arrayJavaProperties); + $this->assertEquals($arrayJavaProperties['single.line'], 'test'); + $this->assertEquals($arrayJavaProperties['multiple'], 'line test'); + } + + public function testInvalidIncludeInString() + { + $JavaProperties = '@include:fail.properties'; + + $expectedErrorMessage = 'Cannot process @include statement for a string'; + + $this->setExpectedException('Zend\Config\Exception\RuntimeException', $expectedErrorMessage); + $arrayJavaPropterties = $this->reader->fromString($JavaProperties); + } +} diff --git a/test/Reader/JsonTest.php b/test/Reader/JsonTest.php index 19bf9cd..228589b 100644 --- a/test/Reader/JsonTest.php +++ b/test/Reader/JsonTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Reader/TestAssets/DummyReader.php b/test/Reader/TestAssets/DummyReader.php index 19da1b3..74a2809 100644 --- a/test/Reader/TestAssets/DummyReader.php +++ b/test/Reader/TestAssets/DummyReader.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Reader/TestAssets/JavaProperties/include-base.properties b/test/Reader/TestAssets/JavaProperties/include-base.properties new file mode 100644 index 0000000..a2cdfbf --- /dev/null +++ b/test/Reader/TestAssets/JavaProperties/include-base.properties @@ -0,0 +1,3 @@ +#comment +!comment +@include:include-target.properties diff --git a/test/Reader/TestAssets/JavaProperties/include-target.properties b/test/Reader/TestAssets/JavaProperties/include-target.properties new file mode 100644 index 0000000..e081355 --- /dev/null +++ b/test/Reader/TestAssets/JavaProperties/include-target.properties @@ -0,0 +1,3 @@ +single.line:test +multiple:line \ +test diff --git a/test/Reader/XmlTest.php b/test/Reader/XmlTest.php index 68e9fc0..144ff87 100644 --- a/test/Reader/XmlTest.php +++ b/test/Reader/XmlTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -21,6 +21,11 @@ public function setUp() $this->reader = new Xml(); } + public function tearDown() + { + restore_error_handler(); + } + /** * getTestAssetPath(): defined by AbstractReaderTestCase. * diff --git a/test/Reader/YamlTest.php b/test/Reader/YamlTest.php index d9dd1d4..f6dec62 100644 --- a/test/Reader/YamlTest.php +++ b/test/Reader/YamlTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/AbstractWriterTestCase.php b/test/Writer/AbstractWriterTestCase.php index 35ab392..8d30dfc 100644 --- a/test/Writer/AbstractWriterTestCase.php +++ b/test/Writer/AbstractWriterTestCase.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/IniTest.php b/test/Writer/IniTest.php index cc3856a..4edc9e2 100644 --- a/test/Writer/IniTest.php +++ b/test/Writer/IniTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/JsonTest.php b/test/Writer/JsonTest.php index 44bbafd..4092821 100644 --- a/test/Writer/JsonTest.php +++ b/test/Writer/JsonTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/PhpArrayTest.php b/test/Writer/PhpArrayTest.php index 7ef6743..cd6cf4e 100644 --- a/test/Writer/PhpArrayTest.php +++ b/test/Writer/PhpArrayTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ @@ -31,21 +31,93 @@ public function setUp() */ public function testRender() { - $config = new Config(array('test' => 'foo', 'bar' => array(0 => 'baz', 1 => 'foo'))); + $config = new Config(array( + 'test' => 'foo', + 'bar' => array(0 => 'baz', 1 => 'foo'), + 'emptyArray' => array(), + 'object' => (object) array('foo' => 'bar'), + 'integer' => 123, + 'boolean' => false, + 'null' => null, + )); $configString = $this->writer->toString($config); // build string line by line as we are trailing-whitespace sensitive. $expected = " 'foo',\n"; - $expected .= " 'bar' => \n"; - $expected .= " array (\n"; - $expected .= " 0 => 'baz',\n"; - $expected .= " 1 => 'foo',\n"; - $expected .= " ),\n"; + $expected .= "return array(\n"; + $expected .= " 'test' => 'foo',\n"; + $expected .= " 'bar' => array(\n"; + $expected .= " 0 => 'baz',\n"; + $expected .= " 1 => 'foo',\n"; + $expected .= " ),\n"; + $expected .= " 'emptyArray' => array(),\n"; + $expected .= " 'object' => stdClass::__set_state(array(\n"; + $expected .= " 'foo' => 'bar',\n"; + $expected .= ")),\n"; + $expected .= " 'integer' => 123,\n"; + $expected .= " 'boolean' => false,\n"; + $expected .= " 'null' => null,\n"; $expected .= ");\n"; $this->assertEquals($expected, $configString); } + + public function testRenderWithBracketArraySyntax() + { + $config = new Config(array('test' => 'foo', 'bar' => array(0 => 'baz', 1 => 'foo'), 'emptyArray' => array())); + + $this->writer->setUseBracketArraySyntax(true); + $configString = $this->writer->toString($config); + + // build string line by line as we are trailing-whitespace sensitive. + $expected = " 'foo',\n"; + $expected .= " 'bar' => [\n"; + $expected .= " 0 => 'baz',\n"; + $expected .= " 1 => 'foo',\n"; + $expected .= " ],\n"; + $expected .= " 'emptyArray' => [],\n"; + $expected .= "];\n"; + + $this->assertEquals($expected, $configString); + } + + public function testRenderWithQuotesInString() + { + $config = new Config(array('one' => 'Test with "double" quotes', 'two' => 'Test with \'single\' quotes')); + + $configString = $this->writer->toString($config); + + $expected = " 'Test with \"double\" quotes',\n"; + $expected .= " 'two' => 'Test with \\'single\\' quotes',\n"; + $expected .= ");\n"; + + $this->assertEquals($expected, $configString); + } + + public function testWriteConvertsPathToDirWhenWritingBackToFile() + { + $filename = $this->getTestAssetFileName(); + file_put_contents($filename, file_get_contents(__DIR__ . '/_files/array.php')); + + $this->writer->toFile($filename, include $filename); + + // Ensure file endings are same + $expected = trim(file_get_contents(__DIR__ . '/_files/array.php')); + $expected = preg_replace("~\r\n|\n|\r~", PHP_EOL, $expected); + + $result = trim(file_get_contents($filename)); + $result = preg_replace("~\r\n|\n|\r~", PHP_EOL, $result); + + $this->assertSame($expected, $result); + } + + public function testSetUseBracketArraySyntaxReturnsFluentInterface() + { + $this->assertSame($this->writer, $this->writer->setUseBracketArraySyntax(true)); + } } diff --git a/test/Writer/TestAssets/DummyWriter.php b/test/Writer/TestAssets/DummyWriter.php index 03af543..f7804a8 100755 --- a/test/Writer/TestAssets/DummyWriter.php +++ b/test/Writer/TestAssets/DummyWriter.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/TestAssets/PhpReader.php b/test/Writer/TestAssets/PhpReader.php index fe3845d..568afad 100644 --- a/test/Writer/TestAssets/PhpReader.php +++ b/test/Writer/TestAssets/PhpReader.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/XmlTest.php b/test/Writer/XmlTest.php index 141d2b0..658b817 100644 --- a/test/Writer/XmlTest.php +++ b/test/Writer/XmlTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/YamlTest.php b/test/Writer/YamlTest.php index 61c7213..1f035a9 100644 --- a/test/Writer/YamlTest.php +++ b/test/Writer/YamlTest.php @@ -3,7 +3,7 @@ * Zend Framework (http://framework.zend.com/) * * @link http://github.com/zendframework/zf2 for the canonical source repository - * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ diff --git a/test/Writer/_files/array.php b/test/Writer/_files/array.php new file mode 100644 index 0000000..9d61beb --- /dev/null +++ b/test/Writer/_files/array.php @@ -0,0 +1,4 @@ + __DIR__ . '/foobar.php', +);