Update Composer

Signed-off-by: Olivier Paroz (oparoz) <github@oparoz.com>
This commit is contained in:
Olivier Paroz (oparoz) 2017-03-12 00:36:21 +01:00
parent ed760ecf5c
commit 21e82c3e43
No known key found for this signature in database
GPG Key ID: 165E66587C7FE8B1
27 changed files with 2521 additions and 1064 deletions

View File

@ -1,15 +1,15 @@
{
"name": "owncloud/gallery",
"name": "nextcloud/gallery",
"type": "project",
"description": "Media gallery for ownCloud which includes previews for all media types supported by your ownCloud installation.",
"description": "Media gallery for Nextcloud which includes previews for all media types supported by your Nextcloud installation.",
"license": "AGPL-3.0",
"homepage": "https://github.com/owncloud/gallery",
"homepage": "https://github.com/nextcloud/gallery",
"authors": [
{
"name": "Olivier Paroz",
"email": "galleryapps@oparoz.com",
"role": "Developer",
"homepage": "http://www.interfasys.ch"
"homepage": "http://www.oparoz.com"
},
{
"name": "Robin Appelman",
@ -19,22 +19,22 @@
}
],
"support": {
"issues": "https://github.com/owncloud/gallery/issues",
"wiki": "https://github.com/owncloud/gallery/wiki",
"source": "https://github.com/owncloud/gallery"
"issues": "https://github.com/nextcloud/gallery/issues",
"wiki": "https://github.com/nextcloud/gallery/wiki",
"source": "https://github.com/nextcloud/gallery"
},
"require": {
"symfony/yaml": "~2.6"
"symfony/yaml": "~3.2"
},
"require-dev": {
"guzzlehttp/guzzle": "^5.0|^6.2",
"phpunit/phpunit": "^4.0|^5.4",
"guzzlehttp/guzzle": "^6.2",
"phpunit/phpunit": "^5.7|^6.0",
"codeception/codeception": "2.2.*",
"codeception/phpbuiltinserver": "*",
"composer-plugin-api": "^1.0",
"codeception/c3": "2.*",
"flow/jsonpath": "^0.3.1",
"phpdocumentor/phpdocumentor": "^2.8",
"flow/jsonpath": "^0.3.4",
"phpdocumentor/phpdocumentor": "^2.9",
"jakub-onderka/php-parallel-lint": "0.*",
"jakub-onderka/php-console-highlighter": "0.*"
}

1697
composer.lock generated

File diff suppressed because it is too large Load Diff

2
vendor/autoload.php vendored
View File

@ -2,6 +2,6 @@
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66::getLoader();

View File

@ -53,8 +53,9 @@ class ClassLoader
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
@ -271,6 +272,26 @@ class ClassLoader
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
@ -313,29 +334,34 @@ class ClassLoader
*/
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
$this->missingClasses[$class] = true;
}
return $file;
@ -348,9 +374,13 @@ class ClassLoader
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
foreach ($this->prefixDirsPsr4[$search] as $dir) {
$length = $this->prefixLengthsPsr4[$first][$search];
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
@ -399,6 +429,8 @@ class ClassLoader
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}

View File

@ -1,5 +1,5 @@
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -6,6 +6,7 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Yaml\\Command\\LintCommand' => $vendorDir . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => $vendorDir . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => $vendorDir . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => $vendorDir . '/symfony/yaml/Exception/DumpException.php',

View File

@ -23,7 +23,7 @@ class ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';

View File

@ -21,6 +21,7 @@ class ComposerStaticInit3cfd72445e0ad28db5332442bcda1e66
);
public static $classMap = array (
'Symfony\\Component\\Yaml\\Command\\LintCommand' => __DIR__ . '/..' . '/symfony/yaml/Command/LintCommand.php',
'Symfony\\Component\\Yaml\\Dumper' => __DIR__ . '/..' . '/symfony/yaml/Dumper.php',
'Symfony\\Component\\Yaml\\Escaper' => __DIR__ . '/..' . '/symfony/yaml/Escaper.php',
'Symfony\\Component\\Yaml\\Exception\\DumpException' => __DIR__ . '/..' . '/symfony/yaml/Exception/DumpException.php',

View File

@ -1,27 +1,33 @@
[
{
"name": "symfony/yaml",
"version": "v2.8.7",
"version_normalized": "2.8.7.0",
"version": "v3.2.6",
"version_normalized": "3.2.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
"reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
"url": "https://api.github.com/repos/symfony/yaml/zipball/093e416ad096355149e265ea2e4cc1f9ee40ab1a",
"reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
"php": ">=5.5.9"
},
"time": "2016-06-06 11:11:27",
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"time": "2017-03-07T16:47:02+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
"dev-master": "3.2-dev"
}
},
"installation-source": "dist",

View File

@ -1,6 +1,61 @@
CHANGELOG
=========
3.2.0
-----
* Mappings with a colon (`:`) that is not followed by a whitespace are deprecated
and will lead to a `ParseException` in Symfony 4.0 (e.g. `foo:bar` must be
`foo: bar`).
* Added support for parsing PHP constants:
```php
Yaml::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_CONSTANT);
```
* Support for silently ignoring duplicate mapping keys in YAML has been
deprecated and will lead to a `ParseException` in Symfony 4.0.
3.1.0
-----
* Strings that are not UTF-8 encoded will be dumped as base64 encoded binary
data.
* Added support for dumping multi line strings as literal blocks.
* Added support for parsing base64 encoded binary data when they are tagged
with the `!!binary` tag.
* Added support for parsing timestamps as `\DateTime` objects:
```php
Yaml::parse('2001-12-15 21:59:43.10 -5', Yaml::PARSE_DATETIME);
```
* `\DateTime` and `\DateTimeImmutable` objects are dumped as YAML timestamps.
* Deprecated usage of `%` at the beginning of an unquoted string.
* Added support for customizing the YAML parser behavior through an optional bit field:
```php
Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_OBJECT | Yaml::PARSE_OBJECT_FOR_MAP);
```
* Added support for customizing the dumped YAML string through an optional bit field:
```php
Yaml::dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT);
```
3.0.0
-----
* Yaml::parse() now throws an exception when a blackslash is not escaped
in double-quoted strings
2.8.0
-----

View File

@ -23,18 +23,28 @@ class Dumper
*
* @var int
*/
protected $indentation = 4;
protected $indentation;
/**
* @param int $indentation
*/
public function __construct($indentation = 4)
{
if ($indentation < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
}
$this->indentation = $indentation;
}
/**
* Sets the indentation.
*
* @param int $num The amount of spaces to use for indentation of nested nodes.
* @param int $num The amount of spaces to use for indentation of nested nodes
*/
public function setIndentation($num)
{
if ($num < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
}
@trigger_error('The '.__METHOD__.' method is deprecated since version 3.1 and will be removed in 4.0. Pass the indentation to the constructor instead.', E_USER_DEPRECATED);
$this->indentation = (int) $num;
}
@ -42,32 +52,59 @@ class Dumper
/**
* Dumps a PHP value to YAML.
*
* @param mixed $input The PHP value
* @param int $inline The level where you switch to inline YAML
* @param int $indent The level of indentation (used internally)
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport true if object support is enabled, false otherwise
* @param mixed $input The PHP value
* @param int $inline The level where you switch to inline YAML
* @param int $indent The level of indentation (used internally)
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0, $exceptionOnInvalidType = false, $objectSupport = false)
public function dump($input, $inline = 0, $indent = 0, $flags = 0)
{
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 5) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED);
if (func_get_arg(4)) {
$flags |= Yaml::DUMP_OBJECT;
}
}
$output = '';
$prefix = $indent ? str_repeat(' ', $indent) : '';
if ($inline <= 0 || !is_array($input) || empty($input)) {
$output .= $prefix.Inline::dump($input, $exceptionOnInvalidType, $objectSupport);
$output .= $prefix.Inline::dump($input, $flags);
} else {
$isAHash = Inline::isHash($input);
foreach ($input as $key => $value) {
if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && is_string($value) && false !== strpos($value, "\n")) {
$output .= sprintf("%s%s%s |\n", $prefix, $isAHash ? Inline::dump($key, $flags).':' : '-', '');
foreach (preg_split('/\n|\r\n/', $value) as $row) {
$output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row);
}
continue;
}
$willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
$output .= sprintf('%s%s%s%s',
$prefix,
$isAHash ? Inline::dump($key, $exceptionOnInvalidType, $objectSupport).':' : '-',
$isAHash ? Inline::dump($key, $flags).':' : '-',
$willBeInlined ? ' ' : "\n",
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $exceptionOnInvalidType, $objectSupport)
$this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags)
).($willBeInlined ? "\n" : '');
}
}

View File

@ -46,7 +46,7 @@ class Escaper
*
* @param string $value A PHP value
*
* @return bool True if the value would require double quotes.
* @return bool True if the value would require double quotes
*/
public static function requiresDoubleQuoting($value)
{
@ -70,7 +70,7 @@ class Escaper
*
* @param string $value A PHP value
*
* @return bool True if the value would require single quotes.
* @return bool True if the value would require single quotes
*/
public static function requiresSingleQuoting($value)
{

View File

@ -123,12 +123,7 @@ class ParseException extends RuntimeException
}
if (null !== $this->parsedFile) {
if (PHP_VERSION_ID >= 50400) {
$jsonOptions = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
} else {
$jsonOptions = 0;
}
$this->message .= sprintf(' in %s', json_encode($this->parsedFile, $jsonOptions));
$this->message .= sprintf(' in %s', json_encode($this->parsedFile, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}
if ($this->parsedLine >= 0) {

View File

@ -18,33 +18,69 @@ use Symfony\Component\Yaml\Exception\DumpException;
* Inline implements a YAML parser/dumper for the YAML inline syntax.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class Inline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
public static $parsedLineNumber;
private static $exceptionOnInvalidType = false;
private static $objectSupport = false;
private static $objectForMap = false;
private static $constantSupport = false;
/**
* Converts a YAML string to a PHP array.
* Converts a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport true if object support is enabled, false otherwise
* @param bool $objectForMap true if maps should return a stdClass instead of array()
* @param array $references Mapping of variable names to values
* @param string $value A YAML string
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
* @param array $references Mapping of variable names to values
*
* @return array A PHP array representing the YAML string
* @return mixed A PHP value
*
* @throws ParseException
*/
public static function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false, $references = array())
public static function parse($value, $flags = 0, $references = array())
{
self::$exceptionOnInvalidType = $exceptionOnInvalidType;
self::$objectSupport = $objectSupport;
self::$objectForMap = $objectForMap;
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 3 && !is_array($references)) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
if ($references) {
$flags |= Yaml::PARSE_OBJECT;
}
if (func_num_args() >= 4) {
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
if (func_get_arg(3)) {
$flags |= Yaml::PARSE_OBJECT_FOR_MAP;
}
}
if (func_num_args() >= 5) {
$references = func_get_arg(4);
} else {
$references = array();
}
}
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
$value = trim($value);
@ -60,15 +96,15 @@ class Inline
$i = 0;
switch ($value[0]) {
case '[':
$result = self::parseSequence($value, $i, $references);
$result = self::parseSequence($value, $flags, $i, $references);
++$i;
break;
case '{':
$result = self::parseMapping($value, $i, $references);
$result = self::parseMapping($value, $flags, $i, $references);
++$i;
break;
default:
$result = self::parseScalar($value, null, array('"', "'"), $i, true, $references);
$result = self::parseScalar($value, $flags, null, array('"', "'"), $i, true, $references);
}
// some comments are allowed at the end
@ -86,35 +122,58 @@ class Inline
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport true if object support is enabled, false otherwise
* @param mixed $value The PHP variable to convert
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
*
* @return string The YAML string representing the PHP array
* @return string The YAML string representing the PHP value
*
* @throws DumpException When trying to dump PHP resource
*/
public static function dump($value, $exceptionOnInvalidType = false, $objectSupport = false)
public static function dump($value, $flags = 0)
{
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 3) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED);
if (func_get_arg(2)) {
$flags |= Yaml::DUMP_OBJECT;
}
}
switch (true) {
case is_resource($value):
if ($exceptionOnInvalidType) {
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
}
return 'null';
case $value instanceof \DateTimeInterface:
return $value->format('c');
case is_object($value):
if ($objectSupport) {
if (Yaml::DUMP_OBJECT & $flags) {
return '!php/object:'.serialize($value);
}
if ($exceptionOnInvalidType) {
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
return self::dumpArray((array) $value, $flags);
}
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException('Object support when dumping a YAML file has been disabled.');
}
return 'null';
case is_array($value):
return self::dumpArray($value, $exceptionOnInvalidType, $objectSupport);
return self::dumpArray($value, $flags);
case null === $value:
return 'null';
case true === $value:
@ -146,9 +205,12 @@ class Inline
return $repr;
case '' == $value:
return "''";
case self::isBinaryString($value):
return '!!binary '.base64_encode($value);
case Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
case preg_match('{^[0-9]+[_0-9]*$}', $value):
case preg_match(self::getHexRegex(), $value):
case preg_match(self::getTimestampRegex(), $value):
return Escaper::escapeWithSingleQuotes($value);
@ -182,19 +244,18 @@ class Inline
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport true if object support is enabled, false otherwise
* @param array $value The PHP array to dump
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
*
* @return string The YAML string representing the PHP array
*/
private static function dumpArray($value, $exceptionOnInvalidType, $objectSupport)
private static function dumpArray($value, $flags)
{
// array
if ($value && !self::isHash($value)) {
$output = array();
foreach ($value as $val) {
$output[] = self::dump($val, $exceptionOnInvalidType, $objectSupport);
$output[] = self::dump($val, $flags);
}
return sprintf('[%s]', implode(', ', $output));
@ -203,29 +264,30 @@ class Inline
// hash
$output = array();
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $exceptionOnInvalidType, $objectSupport), self::dump($val, $exceptionOnInvalidType, $objectSupport));
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
}
return sprintf('{ %s }', implode(', ', $output));
}
/**
* Parses a scalar to a YAML string.
* Parses a YAML scalar.
*
* @param string $scalar
* @param int $flags
* @param string $delimiters
* @param array $stringDelimiters
* @param int &$i
* @param bool $evaluate
* @param array $references
*
* @return string A YAML string
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*
* @internal
*/
public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
public static function parseScalar($scalar, $flags = 0, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
{
if (in_array($scalar[$i], $stringDelimiters)) {
// quoted scalar
@ -251,19 +313,20 @@ class Inline
$output = $match[1];
$i += strlen($output);
} else {
throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar));
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar));
}
// a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
@trigger_error(sprintf('Not quoting the scalar "%s" starting with "%s" is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $output, $output[0]), E_USER_DEPRECATED);
throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]));
}
// to be thrown in 3.0
// throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]));
if ($output && '%' === $output[0]) {
@trigger_error(sprintf('Not quoting the scalar "%s" starting with the "%%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.', $output), E_USER_DEPRECATED);
}
if ($evaluate) {
$output = self::evaluateScalar($output, $references);
$output = self::evaluateScalar($output, $flags, $references);
}
}
@ -271,19 +334,19 @@ class Inline
}
/**
* Parses a quoted scalar to YAML.
* Parses a YAML quoted scalar.
*
* @param string $scalar
* @param int &$i
*
* @return string A YAML string
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseQuotedScalar($scalar, &$i)
{
if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i)));
throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
@ -301,17 +364,18 @@ class Inline
}
/**
* Parses a sequence to a YAML string.
* Parses a YAML sequence.
*
* @param string $sequence
* @param int $flags
* @param int &$i
* @param array $references
*
* @return string A YAML string
* @return array
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseSequence($sequence, &$i = 0, $references = array())
private static function parseSequence($sequence, $flags, &$i = 0, $references = array())
{
$output = array();
$len = strlen($sequence);
@ -322,11 +386,11 @@ class Inline
switch ($sequence[$i]) {
case '[':
// nested sequence
$output[] = self::parseSequence($sequence, $i, $references);
$output[] = self::parseSequence($sequence, $flags, $i, $references);
break;
case '{':
// nested mapping
$output[] = self::parseMapping($sequence, $i, $references);
$output[] = self::parseMapping($sequence, $flags, $i, $references);
break;
case ']':
return $output;
@ -335,14 +399,14 @@ class Inline
break;
default:
$isQuoted = in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i, true, $references);
$value = self::parseScalar($sequence, $flags, array(',', ']'), array('"', "'"), $i, true, $references);
// the value can be an array if a reference has been resolved to an array var
if (!is_array($value) && !$isQuoted && false !== strpos($value, ': ')) {
if (is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {
// embedded mapping?
try {
$pos = 0;
$value = self::parseMapping('{'.$value.'}', $pos, $references);
$value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
} catch (\InvalidArgumentException $e) {
// no, it's not
}
@ -356,21 +420,22 @@ class Inline
++$i;
}
throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence));
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence));
}
/**
* Parses a mapping to a YAML string.
* Parses a YAML mapping.
*
* @param string $mapping
* @param int $flags
* @param int &$i
* @param array $references
*
* @return string A YAML string
* @return array|\stdClass
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseMapping($mapping, &$i = 0, $references = array())
private static function parseMapping($mapping, $flags, &$i = 0, $references = array())
{
$output = array();
$len = strlen($mapping);
@ -392,7 +457,15 @@ class Inline
}
// key
$key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
$key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false);
if (':' !== $key && false === $i = strpos($mapping, ':', $i)) {
break;
}
if (':' !== $key && (!isset($mapping[$i + 1]) || !in_array($mapping[$i + 1], array(' ', ',', '[', ']', '{', '}'), true))) {
@trigger_error('Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0.', E_USER_DEPRECATED);
}
// value
$done = false;
@ -401,23 +474,27 @@ class Inline
switch ($mapping[$i]) {
case '[':
// nested sequence
$value = self::parseSequence($mapping, $i, $references);
$value = self::parseSequence($mapping, $flags, $i, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
if (!isset($output[$key])) {
$output[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
$done = true;
break;
case '{':
// nested mapping
$value = self::parseMapping($mapping, $i, $references);
$value = self::parseMapping($mapping, $flags, $i, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
if (!isset($output[$key])) {
$output[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
$done = true;
break;
@ -425,12 +502,14 @@ class Inline
case ' ':
break;
default:
$value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i, true, $references);
$value = self::parseScalar($mapping, $flags, array(',', '}'), array('"', "'"), $i, true, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
if (!isset($output[$key])) {
$output[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
$done = true;
--$i;
@ -444,20 +523,21 @@ class Inline
}
}
throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping));
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
* @param int $flags
* @param array $references
*
* @return string A YAML string
*
* @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
*/
private static function evaluateScalar($scalar, $references = array())
private static function evaluateScalar($scalar, $flags, $references = array())
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
@ -496,7 +576,7 @@ class Inline
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return (int) self::parseScalar(substr($scalar, 2));
return (int) self::parseScalar(substr($scalar, 2), $flags);
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 12));
@ -509,6 +589,8 @@ class Inline
return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
@trigger_error('The !!php/object tag to indicate dumped PHP objects is deprecated since version 3.1 and will be removed in 4.0. Use the !php/object tag instead.', E_USER_DEPRECATED);
return unserialize(substr($scalar, 13));
}
@ -516,9 +598,25 @@ class Inline
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!php/const:'):
if (self::$constantSupport) {
if (defined($const = substr($scalar, 11))) {
return constant($const);
}
throw new ParseException(sprintf('The constant "%s" is not defined.', $const));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar));
}
return;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar):
$scalar = str_replace('_', '', (string) $scalar);
// omitting the break / return as integers are handled in the next case
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;
@ -531,15 +629,29 @@ class Inline
return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case preg_match(self::getHexRegex(), $scalar):
$scalar = str_replace('_', '', $scalar);
return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
case '.inf' === $scalarLower:
case '.nan' === $scalarLower:
return -log(0);
case '-.inf' === $scalarLower:
return log(0);
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
return (float) str_replace(',', '', $scalar);
case 0 === strpos($scalar, '!!binary '):
return self::evaluateBinaryScalar(substr($scalar, 9));
case preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar):
case preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
if (false !== strpos($scalar, ',')) {
@trigger_error('Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0.', E_USER_DEPRECATED);
}
return (float) str_replace(array(',', '_'), '', $scalar);
case preg_match(self::getTimestampRegex(), $scalar):
if (Yaml::PARSE_DATETIME & $flags) {
// When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
return new \DateTime($scalar, new \DateTimeZone('UTC'));
}
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strtotime($scalar);
@ -552,6 +664,33 @@ class Inline
}
}
/**
* @param string $scalar
*
* @return string
*
* @internal
*/
public static function evaluateBinaryScalar($scalar)
{
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
if (0 !== (strlen($parsedBinaryData) % 4)) {
throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', strlen($parsedBinaryData)));
}
if (!preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData));
}
return base64_decode($parsedBinaryData, true);
}
private static function isBinaryString($value)
{
return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
}
/**
* Gets a regex that matches a YAML date.
*
@ -584,6 +723,6 @@ EOF;
*/
private static function getHexRegex()
{
return '~^0x[0-9a-f]++$~i';
return '~^0x[0-9a-f_]++$~i';
}
}

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2016 Fabien Potencier
Copyright (c) 2004-2017 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -20,9 +20,8 @@ use Symfony\Component\Yaml\Exception\ParseException;
*/
class Parser
{
const TAG_PATTERN = '((?P<tag>![\w!.\/:-]+) +)?';
const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
// BC - wrongly named
const FOLDED_SCALAR_PATTERN = self::BLOCK_SCALAR_HEADER_PATTERN;
private $offset = 0;
private $totalNumberOfLines;
@ -30,33 +29,61 @@ class Parser
private $currentLineNb = -1;
private $currentLine = '';
private $refs = array();
private $skippedLineNumbers = array();
private $locallySkippedLineNumbers = array();
/**
* Constructor.
*
* @param int $offset The offset of YAML document (used for line numbers in error messages)
* @param int|null $totalNumberOfLines The overall number of lines being parsed
* @param int[] $skippedLineNumbers Number of comment lines that have been skipped by the parser
*/
public function __construct($offset = 0, $totalNumberOfLines = null)
public function __construct($offset = 0, $totalNumberOfLines = null, array $skippedLineNumbers = array())
{
$this->offset = $offset;
$this->totalNumberOfLines = $totalNumberOfLines;
$this->skippedLineNumbers = $skippedLineNumbers;
}
/**
* Parses a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport true if object support is enabled, false otherwise
* @param bool $objectForMap true if maps should return a stdClass instead of array()
* @param string $value A YAML string
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
*
* @return mixed A PHP value
*
* @throws ParseException If the YAML is not valid
*/
public function parse($value, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false)
public function parse($value, $flags = 0)
{
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 3) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
if (func_get_arg(2)) {
$flags |= Yaml::PARSE_OBJECT;
}
}
if (func_num_args() >= 4) {
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
if (func_get_arg(3)) {
$flags |= Yaml::PARSE_OBJECT_FOR_MAP;
}
}
if (!preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear to be valid UTF-8.');
}
@ -101,27 +128,20 @@ class Parser
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $exceptionOnInvalidType, $objectSupport, $objectForMap);
$data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags);
} else {
if (isset($values['leadspaces'])
&& preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches)
) {
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$block = $values['value'];
if ($this->isNextLineIndented()) {
$block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values['leadspaces']) + 1);
}
$data[] = $parser->parse($block, $exceptionOnInvalidType, $objectSupport, $objectForMap);
$data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags);
} else {
$data[] = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
$data[] = $this->parseValue($values['value'], $flags, $context);
}
}
if ($isRef) {
@ -134,8 +154,9 @@ class Parser
$context = 'mapping';
// force correct settings
Inline::parse(null, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
Inline::parse(null, $flags, $this->refs);
try {
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
@ -164,21 +185,14 @@ class Parser
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
foreach ($refValue as $key => $value) {
if (!isset($data[$key])) {
$data[$key] = $value;
}
}
$data += $refValue; // array union
} else {
if (isset($values['value']) && $values['value'] !== '') {
$value = $values['value'];
} else {
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$parsed = $parser->parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap);
$parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags);
if (!is_array($parsed)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
@ -193,20 +207,12 @@ class Parser
throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem);
}
foreach ($parsedItem as $key => $value) {
if (!isset($data[$key])) {
$data[$key] = $value;
}
}
$data += $parsedItem; // array union
}
} else {
// If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the
// current mapping, unless the key already exists in it.
foreach ($parsed as $key => $value) {
if (!isset($data[$key])) {
$data[$key] = $value;
}
}
$data += $parsed; // array union
}
}
} elseif (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
@ -224,24 +230,29 @@ class Parser
// But overwriting is allowed when a merge node is used in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = null;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);
}
} else {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport, $objectForMap);
// remember the parsed line number here in case we need it to provide some contexts in error messages below
$realCurrentLineNbKey = $this->getRealCurrentLineNb();
$value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags);
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is used in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, $realCurrentLineNbKey + 1), E_USER_DEPRECATED);
}
}
} else {
$value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport, $objectForMap, $context);
$value = $this->parseValue($values['value'], $flags, $context);
// Spec: Keys MUST be unique; first one wins.
// But overwriting is allowed when a merge node is used in current block.
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);
}
}
if ($isRef) {
@ -256,7 +267,8 @@ class Parser
// 1-liner optionally followed by newline(s)
if (is_string($value) && $this->lines[0] === trim($value)) {
try {
$value = Inline::parse($this->lines[0], $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
$value = Inline::parse($this->lines[0], $flags, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
@ -264,17 +276,6 @@ class Parser
throw $e;
}
if (is_array($value)) {
$first = reset($value);
if (is_string($first) && 0 === strpos($first, '*')) {
$data = array();
foreach ($value as $alias) {
$data[] = $this->refs[substr($alias, 1)];
}
$value = $data;
}
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
@ -310,7 +311,7 @@ class Parser
mb_internal_encoding($mbEncoding);
}
if ($objectForMap && !is_object($data) && 'mapping' === $context) {
if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && !is_object($data) && 'mapping' === $context) {
$object = new \stdClass();
foreach ($data as $key => $value) {
@ -323,6 +324,24 @@ class Parser
return empty($data) ? null : $data;
}
private function parseBlock($offset, $yaml, $flags)
{
$skippedLineNumbers = $this->skippedLineNumbers;
foreach ($this->locallySkippedLineNumbers as $lineNumber) {
if ($lineNumber < $offset) {
continue;
}
$skippedLineNumbers[] = $lineNumber;
}
$parser = new self($offset, $this->totalNumberOfLines, $skippedLineNumbers);
$parser->refs = &$this->refs;
return $parser->parse($yaml, $flags);
}
/**
* Returns the current line number (takes the offset into account).
*
@ -330,7 +349,17 @@ class Parser
*/
private function getRealCurrentLineNb()
{
return $this->currentLineNb + $this->offset;
$realCurrentLineNumber = $this->currentLineNb + $this->offset;
foreach ($this->skippedLineNumbers as $skippedLineNumber) {
if ($skippedLineNumber > $realCurrentLineNumber) {
break;
}
++$realCurrentLineNumber;
}
return $realCurrentLineNumber;
}
/**
@ -421,7 +450,7 @@ class Parser
$previousLineIndentation = $indent;
if ($isItUnindentedCollection && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
$this->moveToPreviousLine();
break;
}
@ -433,6 +462,14 @@ class Parser
// we ignore "comment" lines only when we are not inside a scalar block
if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) {
// remember ignored comment lines (they are used later in nested
// parser calls to determine real line numbers)
//
// CAUTION: beware to not populate the global property here as it
// will otherwise influence the getRealCurrentLineNb() call here
// for consecutive comment lines and subsequent embedded blocks
$this->locallySkippedLineNumbers[] = $this->getRealCurrentLineNb();
continue;
}
@ -468,26 +505,32 @@ class Parser
/**
* Moves the parser to the previous line.
*
* @return bool
*/
private function moveToPreviousLine()
{
if ($this->currentLineNb < 1) {
return false;
}
$this->currentLine = $this->lines[--$this->currentLineNb];
return true;
}
/**
* Parses a YAML value.
*
* @param string $value A YAML value
* @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is enabled, false otherwise
* @param bool $objectForMap true if maps should return a stdClass instead of array()
* @param string $context The parser context (either sequence or mapping)
* @param string $value A YAML value
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
* @param string $context The parser context (either sequence or mapping)
*
* @return mixed A PHP value
*
* @throws ParseException When reference does not exist
*/
private function parseValue($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $context)
private function parseValue($value, $flags, $context)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
@ -503,20 +546,47 @@ class Parser
return $this->refs[$value];
}
if (preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
if (preg_match('/^'.self::TAG_PATTERN.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
$data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
if (isset($matches['tag']) && '!!binary' === $matches['tag']) {
return Inline::evaluateBinaryScalar($data);
}
return $data;
}
try {
$parsedValue = Inline::parse($value, $exceptionOnInvalidType, $objectSupport, $objectForMap, $this->refs);
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
if ('mapping' === $context && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
@trigger_error(sprintf('Using a colon in the unquoted mapping value "%s" in line %d is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $value, $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED);
// do not take following lines into account when the current line is a quoted single line value
if (null !== $quotation && preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) {
return Inline::parse($value, $flags, $this->refs);
}
// to be thrown in 3.0
// throw new ParseException('A colon cannot be used in an unquoted mapping value.');
while ($this->moveToNextLine()) {
// unquoted strings end before the first unindented line
if (null === $quotation && $this->getCurrentLineIndentation() === 0) {
$this->moveToPreviousLine();
break;
}
$value .= ' '.trim($this->currentLine);
// quoted string values end with a line that is terminated with the quotation character
if ('' !== $this->currentLine && substr($this->currentLine, -1) === $quotation) {
break;
}
}
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
$parsedValue = Inline::parse($value, $flags, $this->refs);
if ('mapping' === $context && is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
throw new ParseException('A colon cannot be used in an unquoted mapping value.');
}
return $parsedValue;
@ -602,7 +672,7 @@ class Parser
$previousLineIndented = false;
$previousLineBlank = false;
for ($i = 0; $i < count($blockLines); ++$i) {
for ($i = 0, $blockLinesCount = count($blockLines); $i < $blockLinesCount; ++$i) {
if ('' === $blockLines[$i]) {
$text .= "\n";
$previousLineIndented = false;

View File

@ -11,10 +11,12 @@
namespace Symfony\Component\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Dumper;
use Symfony\Component\Yaml\Yaml;
class DumperTest extends \PHPUnit_Framework_TestCase
class DumperTest extends TestCase
{
protected $parser;
protected $dumper;
@ -50,6 +52,34 @@ class DumperTest extends \PHPUnit_Framework_TestCase
$this->array = null;
}
public function testIndentationInConstructor()
{
$dumper = new Dumper(7);
$expected = <<<'EOF'
'': bar
foo: '#bar'
'foo''bar': { }
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
foobar:
foo: bar
bar:
- 1
- foo
EOF;
$this->assertEquals($expected, $dumper->dump($this->array, 4, 0));
}
/**
* @group legacy
*/
public function testSetIndentation()
{
$this->dumper->setIndentation(7);
@ -177,6 +207,16 @@ EOF;
}
public function testObjectSupportEnabled()
{
$dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_OBJECT);
$this->assertEquals('{ foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects');
}
/**
* @group legacy
*/
public function testObjectSupportEnabledPassingTrue()
{
$dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, false, true);
@ -195,7 +235,16 @@ EOF;
*/
public function testObjectSupportDisabledWithExceptions()
{
$this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, true, false);
$this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE);
}
/**
* @group legacy
* @expectedException \Symfony\Component\Yaml\Exception\DumpException
*/
public function testObjectSupportDisabledWithExceptionsPassingTrue()
{
$this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, true);
}
/**
@ -209,33 +258,103 @@ EOF;
public function getEscapeSequences()
{
return array(
'null' => array("\t\\0", '"\t\\\\0"'),
'bell' => array("\t\\a", '"\t\\\\a"'),
'backspace' => array("\t\\b", '"\t\\\\b"'),
'horizontal-tab' => array("\t\\t", '"\t\\\\t"'),
'line-feed' => array("\t\\n", '"\t\\\\n"'),
'vertical-tab' => array("\t\\v", '"\t\\\\v"'),
'form-feed' => array("\t\\f", '"\t\\\\f"'),
'carriage-return' => array("\t\\r", '"\t\\\\r"'),
'escape' => array("\t\\e", '"\t\\\\e"'),
'space' => array("\t\\ ", '"\t\\\\ "'),
'double-quote' => array("\t\\\"", '"\t\\\\\\""'),
'slash' => array("\t\\/", '"\t\\\\/"'),
'backslash' => array("\t\\\\", '"\t\\\\\\\\"'),
'next-line' => array("\t\\N", '"\t\\\\N"'),
'non-breaking-space' => array("\t\\<EFBFBD>", '"\t\\\\<5C>"'),
'line-separator' => array("\t\\L", '"\t\\\\L"'),
'paragraph-separator' => array("\t\\P", '"\t\\\\P"'),
'empty string' => array('', "''"),
'null' => array("\x0", '"\\0"'),
'bell' => array("\x7", '"\\a"'),
'backspace' => array("\x8", '"\\b"'),
'horizontal-tab' => array("\t", '"\\t"'),
'line-feed' => array("\n", '"\\n"'),
'vertical-tab' => array("\v", '"\\v"'),
'form-feed' => array("\xC", '"\\f"'),
'carriage-return' => array("\r", '"\\r"'),
'escape' => array("\x1B", '"\\e"'),
'space' => array(' ', "' '"),
'double-quote' => array('"', "'\"'"),
'slash' => array('/', '/'),
'backslash' => array('\\', '\\'),
'next-line' => array("\xC2\x85", '"\\N"'),
'non-breaking-space' => array("\xc2\xa0", '"\\_"'),
'line-separator' => array("\xE2\x80\xA8", '"\\L"'),
'paragraph-separator' => array("\xE2\x80\xA9", '"\\P"'),
'colon' => array(':', "':'"),
);
}
public function testBinaryDataIsDumpedBase64Encoded()
{
$binaryData = file_get_contents(__DIR__.'/Fixtures/arrow.gif');
$expected = '{ data: !!binary '.base64_encode($binaryData).' }';
$this->assertSame($expected, $this->dumper->dump(array('data' => $binaryData)));
}
public function testNonUtf8DataIsDumpedBase64Encoded()
{
// "für" (ISO-8859-1 encoded)
$this->assertSame('!!binary ZsM/cg==', $this->dumper->dump("f\xc3\x3fr"));
}
/**
* @dataProvider objectAsMapProvider
*/
public function testDumpObjectAsMap($object, $expected)
{
$yaml = $this->dumper->dump($object, 0, 0, Yaml::DUMP_OBJECT_AS_MAP);
$this->assertEquals($expected, Yaml::parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
}
public function objectAsMapProvider()
{
$tests = array();
$bar = new \stdClass();
$bar->class = 'classBar';
$bar->args = array('bar');
$zar = new \stdClass();
$foo = new \stdClass();
$foo->bar = $bar;
$foo->zar = $zar;
$object = new \stdClass();
$object->foo = $foo;
$tests['stdClass'] = array($object, $object);
$arrayObject = new \ArrayObject();
$arrayObject['foo'] = 'bar';
$arrayObject['baz'] = 'foobar';
$parsedArrayObject = new \stdClass();
$parsedArrayObject->foo = 'bar';
$parsedArrayObject->baz = 'foobar';
$tests['ArrayObject'] = array($arrayObject, $parsedArrayObject);
$a = new A();
$tests['arbitrary-object'] = array($a, null);
return $tests;
}
public function testDumpMultiLineStringAsScalarBlock()
{
$data = array(
'data' => array(
'single_line' => 'foo bar baz',
'multi_line' => "foo\nline with trailing spaces:\n \nbar\r\ninteger like line:\n123456789\nempty line:\n\nbaz",
'nested_inlined_multi_line_string' => array(
'inlined_multi_line' => "foo\nbar\r\nempty line:\n\nbaz",
),
),
);
$this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The indentation must be greater than zero
*/
public function testZeroIndentationThrowsException()
{
$this->dumper->setIndentation(0);
new Dumper(0);
}
/**
@ -244,7 +363,7 @@ EOF;
*/
public function testNegativeIndentationThrowsException()
{
$this->dumper->setIndentation(-4);
new Dumper(-4);
}
}

View File

@ -509,24 +509,31 @@ test: Integers
spec: 2.19
yaml: |
canonical: 12345
decimal: +12,345
octal: 014
hexadecimal: 0xC
php: |
array(
'canonical' => 12345,
'decimal' => 12345.0,
'octal' => 014,
'hexadecimal' => 0xC
)
---
test: Decimal Integer
deprecated: true
spec: 2.19
yaml: |
decimal: +12,345
php: |
array(
'decimal' => 12345.0,
)
---
# FIX: spec shows parens around -inf and NaN
test: Floating point
spec: 2.20
yaml: |
canonical: 1.23015e+3
exponential: 12.3015e+02
fixed: 1,230.15
negative infinity: -.inf
not a number: .NaN
float as whole number: !!float 1
@ -534,12 +541,21 @@ php: |
array(
'canonical' => 1230.15,
'exponential' => 1230.15,
'fixed' => 1230.15,
'negative infinity' => log(0),
'not a number' => -log(0),
'float as whole number' => (float) 1
)
---
test: Fixed Floating point
deprecated: true
spec: 2.20
yaml: |
fixed: 1,230.15
php: |
array(
'fixed' => 1230.15,
)
---
test: Miscellaneous
spec: 2.21
yaml: |
@ -1532,29 +1548,43 @@ php: |
test: Integer
yaml: |
canonical: 12345
decimal: +12,345
octal: 014
hexadecimal: 0xC
php: |
array(
'canonical' => 12345,
'decimal' => 12345.0,
'octal' => 12,
'hexadecimal' => 12
)
---
test: Decimal
deprecated: true
yaml: |
decimal: +12,345
php: |
array(
'decimal' => 12345.0,
)
---
test: Fixed Float
deprecated: true
yaml: |
fixed: 1,230.15
php: |
array(
'fixed' => 1230.15,
)
---
test: Float
yaml: |
canonical: 1.23015e+3
exponential: 12.3015e+02
fixed: 1,230.15
negative infinity: -.inf
not a number: .NaN
php: |
array(
'canonical' => 1230.15,
'exponential' => 1230.15,
'fixed' => 1230.15,
'negative infinity' => log(0),
'not a number' => -log(0)
)

View File

@ -176,13 +176,37 @@ brief: >
yaml: |
zero: 0
simple: 12
one-thousand: 1,000
negative one-thousand: -1,000
php: |
array(
'zero' => 0,
'simple' => 12,
)
---
test: Positive Big Integer
deprecated: true
dump_skip: true
brief: >
An integer is a series of numbers, optionally
starting with a positive or negative sign. Integers
may also contain commas for readability.
yaml: |
one-thousand: 1,000
php: |
array(
'one-thousand' => 1000.0,
)
---
test: Negative Big Integer
deprecated: true
dump_skip: true
brief: >
An integer is a series of numbers, optionally
starting with a positive or negative sign. Integers
may also contain commas for readability.
yaml: |
negative one-thousand: -1,000
php: |
array(
'negative one-thousand' => -1000.0
)
---
@ -208,15 +232,27 @@ brief: >
positive and negative infinity and "not a number."
yaml: |
a simple float: 2.00
larger float: 1,000.09
scientific notation: 1.00009e+3
php: |
array(
'a simple float' => 2.0,
'larger float' => 1000.09,
'scientific notation' => 1000.09
)
---
test: Larger Float
dump_skip: true
deprecated: true
brief: >
Floats are represented by numbers with decimals,
allowing for scientific notation, as well as
positive and negative infinity and "not a number."
yaml: |
larger float: 1,000.09
php: |
array(
'larger float' => 1000.09,
)
---
test: Time
todo: true
brief: >

View File

@ -10,19 +10,17 @@ yaml: |
a: Steve
b: Clark
c: Brian
e: notnull
bar:
a: before
d: other
e: ~
<<: *foo
b: new
x: Oren
c:
foo: bar
foo: ignore
bar: foo
duplicate:
foo: bar
foo: ignore
foo2: &foo2
a: Ballmer
ding: &dong [ fi, fei, fo, fam]
@ -46,13 +44,12 @@ yaml: |
<<: *nestedref
php: |
array(
'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian'),
'bar' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'),
'duplicate' => array('foo' => 'bar'),
'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'),
'bar' => array('a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'),
'foo2' => array('a' => 'Ballmer'),
'ding' => array('fi', 'fei', 'fo', 'fam'),
'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'),
'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam'),
'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'),
'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
'taz' => array('a' => 'Steve', 'w' => array('p' => 1234)),
'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345))
)

View File

@ -11,9 +11,12 @@
namespace Symfony\Component\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Inline;
use Symfony\Component\Yaml\Yaml;
class InlineTest extends \PHPUnit_Framework_TestCase
class InlineTest extends TestCase
{
/**
* @dataProvider getTestsForParse
@ -27,6 +30,55 @@ class InlineTest extends \PHPUnit_Framework_TestCase
* @dataProvider getTestsForParseWithMapObjects
*/
public function testParseWithMapObjects($yaml, $value)
{
$actual = Inline::parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP);
$this->assertSame(serialize($value), serialize($actual));
}
/**
* @dataProvider getTestsForParsePhpConstants
*/
public function testParsePhpConstants($yaml, $value)
{
$actual = Inline::parse($yaml, Yaml::PARSE_CONSTANT);
$this->assertSame($value, $actual);
}
public function getTestsForParsePhpConstants()
{
return array(
array('!php/const:Symfony\Component\Yaml\Yaml::PARSE_CONSTANT', Yaml::PARSE_CONSTANT),
array('!php/const:PHP_INT_MAX', PHP_INT_MAX),
array('[!php/const:PHP_INT_MAX]', array(PHP_INT_MAX)),
array('{ foo: !php/const:PHP_INT_MAX }', array('foo' => PHP_INT_MAX)),
);
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage The constant "WRONG_CONSTANT" is not defined
*/
public function testParsePhpConstantThrowsExceptionWhenUndefined()
{
Inline::parse('!php/const:WRONG_CONSTANT', Yaml::PARSE_CONSTANT);
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessageRegExp #The string "!php/const:PHP_INT_MAX" could not be parsed as a constant.*#
*/
public function testParsePhpConstantThrowsExceptionOnInvalidType()
{
Inline::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
}
/**
* @group legacy
* @dataProvider getTestsForParseWithMapObjects
*/
public function testParseWithMapObjectsPassingTrue($yaml, $value)
{
$actual = Inline::parse($yaml, false, false, true);
@ -58,10 +110,8 @@ class InlineTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('1.2', Inline::dump(1.2));
$this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0)));
} finally {
setlocale(LC_NUMERIC, $locale);
} catch (\Exception $e) {
setlocale(LC_NUMERIC, $locale);
throw $e;
}
}
@ -73,12 +123,12 @@ class InlineTest extends \PHPUnit_Framework_TestCase
}
/**
* @group legacy
* throws \Symfony\Component\Yaml\Exception\ParseException in 3.0
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage Found unknown escape character "\V".
*/
public function testParseScalarWithNonEscapedBlackslashShouldThrowException()
{
$this->assertSame('Foo\Var', Inline::parse('"Foo\Var"'));
Inline::parse('"Foo\Var"');
}
/**
@ -116,6 +166,16 @@ class InlineTest extends \PHPUnit_Framework_TestCase
Inline::parse($value);
}
/**
* @group legacy
* @expectedDeprecation Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0.
* throws \Symfony\Component\Yaml\Exception\ParseException in 4.0
*/
public function testParseMappingKeyWithColonNotFollowedBySpace()
{
Inline::parse('{1:""}');
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
@ -144,6 +204,15 @@ class InlineTest extends \PHPUnit_Framework_TestCase
* @dataProvider getDataForParseReferences
*/
public function testParseReferences($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml, 0, array('var' => 'var-value')));
}
/**
* @group legacy
* @dataProvider getDataForParseReferences
*/
public function testParseReferencesAsFifthArgument($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml, false, false, false, array('var' => 'var-value')));
}
@ -163,6 +232,19 @@ class InlineTest extends \PHPUnit_Framework_TestCase
}
public function testParseMapReferenceInSequence()
{
$foo = array(
'a' => 'Steve',
'b' => 'Clark',
'c' => 'Brian',
);
$this->assertSame(array($foo), Inline::parse('[*foo]', 0, array('foo' => $foo)));
}
/**
* @group legacy
*/
public function testParseMapReferenceInSequenceAsFifthArgument()
{
$foo = array(
'a' => 'Steve',
@ -191,9 +273,9 @@ class InlineTest extends \PHPUnit_Framework_TestCase
}
/**
* @group legacy
* @dataProvider getReservedIndicators
* throws \Symfony\Component\Yaml\Exception\ParseException in 3.0
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage cannot start a plain scalar; you need to quote the scalar.
*/
public function testParseUnquotedScalarStartingWithReservedIndicator($indicator)
{
@ -206,9 +288,9 @@ class InlineTest extends \PHPUnit_Framework_TestCase
}
/**
* @group legacy
* @dataProvider getScalarIndicators
* throws \Symfony\Component\Yaml\Exception\ParseException in 3.0
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage cannot start a plain scalar; you need to quote the scalar.
*/
public function testParseUnquotedScalarStartingWithScalarIndicator($indicator)
{
@ -220,6 +302,16 @@ class InlineTest extends \PHPUnit_Framework_TestCase
return array(array('|'), array('>'));
}
/**
* @group legacy
* @expectedDeprecation Not quoting the scalar "%bar " starting with the "%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.
* throws \Symfony\Component\Yaml\Exception\ParseException in 4.0
*/
public function testParseUnquotedScalarStartingWithPercentCharacter()
{
Inline::parse('{ foo: %bar }');
}
/**
* @dataProvider getDataForIsHash
*/
@ -247,11 +339,17 @@ class InlineTest extends \PHPUnit_Framework_TestCase
array('true', true),
array('12', 12),
array('-12', -12),
array('1_2', 12),
array('_12', '_12'),
array('12_', 12),
array('"quoted string"', 'quoted string'),
array("'quoted string'", 'quoted string'),
array('12.30e+02', 12.30e+02),
array('123.45_67', 123.4567),
array('0x4D2', 0x4D2),
array('0x_4_D_2_', 0x4D2),
array('02333', 02333),
array('0_2_3_3_3', 02333),
array('.Inf', -log(0)),
array('-.Inf', log(0)),
array("'686e444'", '686e444'),
@ -287,7 +385,7 @@ class InlineTest extends \PHPUnit_Framework_TestCase
array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')),
// mappings
array('{foo:bar,bar:foo,false:false,null:null,integer:12}', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)),
array('{foo: bar,bar: foo,false: false,null: null,integer: 12}', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)),
array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)),
array('{foo: \'bar\', bar: \'foo: bar\'}', array('foo' => 'bar', 'bar' => 'foo: bar')),
array('{\'foo\': \'bar\', "bar": \'foo: bar\'}', array('foo' => 'bar', 'bar' => 'foo: bar')),
@ -299,6 +397,8 @@ class InlineTest extends \PHPUnit_Framework_TestCase
array('[foo, {bar: foo}]', array('foo', array('bar' => 'foo'))),
array('{ foo: {bar: foo} }', array('foo' => array('bar' => 'foo'))),
array('{ foo: [bar, foo] }', array('foo' => array('bar', 'foo'))),
array('{ foo:{bar: foo} }', array('foo' => array('bar' => 'foo'))),
array('{ foo:[bar, foo] }', array('foo' => array('bar', 'foo'))),
array('[ foo, [ bar, foo ] ]', array('foo', array('bar', 'foo'))),
@ -354,7 +454,7 @@ class InlineTest extends \PHPUnit_Framework_TestCase
array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')),
// mappings
array('{foo:bar,bar:foo,false:false,null:null,integer:12}', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)),
array('{foo: bar,bar: foo,false: false,null: null,integer: 12}', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)),
array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)),
array('{foo: \'bar\', bar: \'foo: bar\'}', (object) array('foo' => 'bar', 'bar' => 'foo: bar')),
array('{\'foo\': \'bar\', "bar": \'foo: bar\'}', (object) array('foo' => 'bar', 'bar' => 'foo: bar')),
@ -399,10 +499,15 @@ class InlineTest extends \PHPUnit_Framework_TestCase
array('false', false),
array('true', true),
array('12', 12),
array("'1_2'", '1_2'),
array('_12', '_12'),
array("'12_'", '12_'),
array("'quoted string'", 'quoted string'),
array('!!float 1230', 12.30e+02),
array('1234', 0x4D2),
array('1243', 02333),
array("'0x_4_D_2_'", '0x_4_D_2_'),
array("'0_2_3_3_3'", '0_2_3_3_3'),
array('.Inf', -log(0)),
array('-.Inf', log(0)),
array("'686e444'", '686e444'),
@ -448,4 +553,160 @@ class InlineTest extends \PHPUnit_Framework_TestCase
array('{ foo: { bar: { 1: 2, baz: 3 } } }', array('foo' => array('bar' => array(1 => 2, 'baz' => 3)))),
);
}
/**
* @dataProvider getTimestampTests
*/
public function testParseTimestampAsUnixTimestampByDefault($yaml, $year, $month, $day, $hour, $minute, $second)
{
$this->assertSame(gmmktime($hour, $minute, $second, $month, $day, $year), Inline::parse($yaml));
}
/**
* @dataProvider getTimestampTests
*/
public function testParseTimestampAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second, $timezone)
{
$expected = new \DateTime($yaml);
$expected->setTimeZone(new \DateTimeZone('UTC'));
$expected->setDate($year, $month, $day);
if (PHP_VERSION_ID >= 70100) {
$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second));
} else {
$expected->setTime($hour, $minute, $second);
}
$date = Inline::parse($yaml, Yaml::PARSE_DATETIME);
$this->assertEquals($expected, $date);
$this->assertSame($timezone, $date->format('O'));
}
public function getTimestampTests()
{
return array(
'canonical' => array('2001-12-15T02:59:43.1Z', 2001, 12, 15, 2, 59, 43.1, '+0000'),
'ISO-8601' => array('2001-12-15t21:59:43.10-05:00', 2001, 12, 16, 2, 59, 43.1, '-0500'),
'spaced' => array('2001-12-15 21:59:43.10 -5', 2001, 12, 16, 2, 59, 43.1, '-0500'),
'date' => array('2001-12-15', 2001, 12, 15, 0, 0, 0, '+0000'),
);
}
/**
* @dataProvider getTimestampTests
*/
public function testParseNestedTimestampListAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second)
{
$expected = new \DateTime($yaml);
$expected->setTimeZone(new \DateTimeZone('UTC'));
$expected->setDate($year, $month, $day);
if (PHP_VERSION_ID >= 70100) {
$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second));
} else {
$expected->setTime($hour, $minute, $second);
}
$expectedNested = array('nested' => array($expected));
$yamlNested = "{nested: [$yaml]}";
$this->assertEquals($expectedNested, Inline::parse($yamlNested, Yaml::PARSE_DATETIME));
}
/**
* @dataProvider getDateTimeDumpTests
*/
public function testDumpDateTime($dateTime, $expected)
{
$this->assertSame($expected, Inline::dump($dateTime));
}
public function getDateTimeDumpTests()
{
$tests = array();
$dateTime = new \DateTime('2001-12-15 21:59:43', new \DateTimeZone('UTC'));
$tests['date-time-utc'] = array($dateTime, '2001-12-15T21:59:43+00:00');
$dateTime = new \DateTimeImmutable('2001-07-15 21:59:43', new \DateTimeZone('Europe/Berlin'));
$tests['immutable-date-time-europe-berlin'] = array($dateTime, '2001-07-15T21:59:43+02:00');
return $tests;
}
/**
* @dataProvider getBinaryData
*/
public function testParseBinaryData($data)
{
$this->assertSame('Hello world', Inline::parse($data));
}
public function getBinaryData()
{
return array(
'enclosed with double quotes' => array('!!binary "SGVsbG8gd29ybGQ="'),
'enclosed with single quotes' => array("!!binary 'SGVsbG8gd29ybGQ='"),
'containing spaces' => array('!!binary "SGVs bG8gd 29ybGQ="'),
);
}
/**
* @dataProvider getInvalidBinaryData
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
public function testParseInvalidBinaryData($data, $expectedMessage)
{
if (method_exists($this, 'expectException')) {
$this->expectExceptionMessageRegExp($expectedMessage);
} else {
$this->setExpectedExceptionRegExp(ParseException::class, $expectedMessage);
}
Inline::parse($data);
}
public function getInvalidBinaryData()
{
return array(
'length not a multiple of four' => array('!!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
'too many equals characters' => array('!!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
'misplaced equals character' => array('!!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
);
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage Malformed inline YAML string: {this, is not, supported}.
*/
public function testNotSupportedMissingValue()
{
Inline::parse('{this, is not, supported}');
}
public function testVeryLongQuotedStrings()
{
$longStringWithQuotes = str_repeat("x\r\n\\\"x\"x", 1000);
$yamlString = Inline::dump(array('longStringWithQuotes' => $longStringWithQuotes));
$arrayFromYaml = Inline::parse($yamlString);
$this->assertEquals($longStringWithQuotes, $arrayFromYaml['longStringWithQuotes']);
}
public function testOmittedMappingKeyIsParsedAsColon()
{
$this->assertSame(array(':' => 'foo'), Inline::parse('{: foo}'));
}
public function testBooleanMappingKeysAreConvertedToStrings()
{
$this->assertSame(array('false' => 'foo'), Inline::parse('{false: foo}'));
$this->assertSame(array('true' => 'foo'), Inline::parse('{true: foo}'));
}
public function testTheEmptyStringIsAValidMappingKey()
{
$this->assertSame(array('' => 'foo'), Inline::parse('{ "": foo }'));
}
}

View File

@ -11,18 +11,15 @@
namespace Symfony\Component\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Exception\ParseException;
class ParseExceptionTest extends \PHPUnit_Framework_TestCase
class ParseExceptionTest extends TestCase
{
public function testGetMessage()
{
$exception = new ParseException('Error message', 42, 'foo: bar', '/var/www/app/config.yml');
if (PHP_VERSION_ID >= 50400) {
$message = 'Error message in "/var/www/app/config.yml" at line 42 (near "foo: bar")';
} else {
$message = 'Error message in "\\/var\\/www\\/app\\/config.yml" at line 42 (near "foo: bar")';
}
$message = 'Error message in "/var/www/app/config.yml" at line 42 (near "foo: bar")';
$this->assertEquals($message, $exception->getMessage());
}
@ -30,11 +27,7 @@ class ParseExceptionTest extends \PHPUnit_Framework_TestCase
public function testGetMessageWithUnicodeInFilename()
{
$exception = new ParseException('Error message', 42, 'foo: bar', 'äöü.yml');
if (PHP_VERSION_ID >= 50400) {
$message = 'Error message in "äöü.yml" at line 42 (near "foo: bar")';
} else {
$message = 'Error message in "\u00e4\u00f6\u00fc.yml" at line 42 (near "foo: bar")';
}
$message = 'Error message in "äöü.yml" at line 42 (near "foo: bar")';
$this->assertEquals($message, $exception->getMessage());
}

View File

@ -11,10 +11,12 @@
namespace Symfony\Component\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Yaml\Parser;
class ParserTest extends \PHPUnit_Framework_TestCase
class ParserTest extends TestCase
{
protected $parser;
@ -31,9 +33,34 @@ class ParserTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider getDataFormSpecifications
*/
public function testSpecifications($file, $expected, $yaml, $comment)
public function testSpecifications($file, $expected, $yaml, $comment, $deprecated)
{
$deprecations = array();
if ($deprecated) {
set_error_handler(function ($type, $msg) use (&$deprecations) {
if (E_USER_DEPRECATED !== $type) {
restore_error_handler();
if (class_exists('PHPUnit_Util_ErrorHandler')) {
return call_user_func_array('PHPUnit_Util_ErrorHandler::handleError', func_get_args());
}
return call_user_func_array('PHPUnit\Util\ErrorHandler::handleError', func_get_args());
}
$deprecations[] = $msg;
});
}
$this->assertEquals($expected, var_export($this->parser->parse($yaml), true), $comment);
if ($deprecated) {
restore_error_handler();
$this->assertCount(1, $deprecations);
$this->assertContains('Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0.', $deprecations[0]);
}
}
public function getDataFormSpecifications()
@ -58,7 +85,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase
} else {
eval('$expected = '.trim($test['php']).';');
$tests[] = array($file, var_export($expected, true), $test['yaml'], $test['test']);
$tests[] = array($file, var_export($expected, true), $test['yaml'], $test['test'], isset($test['deprecated']) ? $test['deprecated'] : false);
}
}
}
@ -189,6 +216,22 @@ EOF;
);
$tests['Literal block chomping clip with multiple trailing newlines'] = array($expected, $yaml);
$yaml = <<<'EOF'
foo:
- bar: |
one
two
EOF;
$expected = array(
'foo' => array(
array(
'bar' => "one\n\ntwo",
),
),
);
$tests['Literal block chomping clip with embedded blank line inside unindented collection'] = array($expected, $yaml);
$yaml = <<<'EOF'
foo: |
one
@ -421,19 +464,37 @@ EOF;
public function testObjectSupportEnabled()
{
$input = <<<EOF
foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
$input = <<<'EOF'
foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
bar: 1
EOF;
$this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects');
$this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, Yaml::PARSE_OBJECT), '->parse() is able to parse objects');
}
$input = <<<EOF
/**
* @group legacy
*/
public function testObjectSupportEnabledPassingTrue()
{
$input = <<<'EOF'
foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
bar: 1
EOF;
$this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects');
}
/**
* @group legacy
*/
public function testObjectSupportEnabledWithDeprecatedTag()
{
$input = <<<'EOF'
foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";}
bar: 1
EOF;
$this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, Yaml::PARSE_OBJECT), '->parse() is able to parse objects');
}
/**
* @dataProvider invalidDumpedObjectProvider
*/
@ -446,6 +507,15 @@ EOF;
* @dataProvider getObjectForMapTests
*/
public function testObjectForMap($yaml, $expected)
{
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
}
/**
* @group legacy
* @dataProvider getObjectForMapTests
*/
public function testObjectForMapEnabledWithMappingUsingBooleanToggles($yaml, $expected)
{
$this->assertEquals($expected, $this->parser->parse($yaml, false, false, true));
}
@ -454,7 +524,7 @@ EOF;
{
$tests = array();
$yaml = <<<EOF
$yaml = <<<'EOF'
foo:
fiz: [cat]
EOF;
@ -475,7 +545,7 @@ EOF;
$expected->baz = 'foobar';
$tests['object-for-map-is-applied-after-parsing'] = array($yaml, $expected);
$yaml = <<<EOT
$yaml = <<<'EOT'
array:
- key: one
- key: two
@ -488,7 +558,7 @@ EOT;
$expected->array[1]->key = 'two';
$tests['nest-map-and-sequence'] = array($yaml, $expected);
$yaml = <<<YAML
$yaml = <<<'YAML'
map:
1: one
2: two
@ -499,7 +569,7 @@ YAML;
$expected->map->{2} = 'two';
$tests['numeric-keys'] = array($yaml, $expected);
$yaml = <<<YAML
$yaml = <<<'YAML'
map:
0: one
1: two
@ -519,16 +589,26 @@ YAML;
*/
public function testObjectsSupportDisabledWithExceptions($yaml)
{
$this->parser->parse($yaml, true, false);
$this->parser->parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
}
/**
* @group legacy
* @dataProvider invalidDumpedObjectProvider
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
public function testObjectsSupportDisabledWithExceptionsUsingBooleanToggles($yaml)
{
$this->parser->parse($yaml, true);
}
public function invalidDumpedObjectProvider()
{
$yamlTag = <<<EOF
$yamlTag = <<<'EOF'
foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";}
bar: 1
EOF;
$localTag = <<<EOF
$localTag = <<<'EOF'
foo: !php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";}
bar: 1
EOF;
@ -630,7 +710,7 @@ EOF
public function testSequenceInMappingStartedBySingleDashLine()
{
$yaml = <<<EOT
$yaml = <<<'EOT'
a:
-
b:
@ -656,6 +736,25 @@ EOT;
$this->assertSame($expected, $this->parser->parse($yaml));
}
public function testSequenceFollowedByCommentEmbeddedInMapping()
{
$yaml = <<<'EOT'
a:
b:
- c
# comment
d: e
EOT;
$expected = array(
'a' => array(
'b' => array('c'),
'd' => 'e',
),
);
$this->assertSame($expected, $this->parser->parse($yaml));
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
@ -675,7 +774,7 @@ EOF
*/
public function testScalarInSequence()
{
Yaml::parse(<<<EOF
Yaml::parse(<<<'EOF'
foo:
- bar
"missing colon"
@ -693,10 +792,11 @@ EOF
*
* @see http://yaml.org/spec/1.2/spec.html#id2759572
* @see http://yaml.org/spec/1.1/#id932806
* @group legacy
*/
public function testMappingDuplicateKeyBlock()
{
$input = <<<EOD
$input = <<<'EOD'
parent:
child: first
child: duplicate
@ -712,9 +812,12 @@ EOD;
$this->assertSame($expected, Yaml::parse($input));
}
/**
* @group legacy
*/
public function testMappingDuplicateKeyFlow()
{
$input = <<<EOD
$input = <<<'EOD'
parent: { child: first, child: duplicate }
parent: { child: duplicate, child: duplicate }
EOD;
@ -726,6 +829,74 @@ EOD;
$this->assertSame($expected, Yaml::parse($input));
}
/**
* @group legacy
* @dataProvider getParseExceptionOnDuplicateData
* @expectedDeprecation Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated %s.
* throws \Symfony\Component\Yaml\Exception\ParseException in 4.0
*/
public function testParseExceptionOnDuplicate($input, $duplicateKey, $lineNumber)
{
Yaml::parse($input);
}
public function getParseExceptionOnDuplicateData()
{
$tests = array();
$yaml = <<<EOD
parent: { child: first, child: duplicate }
EOD;
$tests[] = array($yaml, 'child', 1);
$yaml = <<<EOD
parent:
child: first,
child: duplicate
EOD;
$tests[] = array($yaml, 'child', 3);
$yaml = <<<EOD
parent: { child: foo }
parent: { child: bar }
EOD;
$tests[] = array($yaml, 'parent', 2);
$yaml = <<<EOD
parent: { child_mapping: { value: bar}, child_mapping: { value: bar} }
EOD;
$tests[] = array($yaml, 'child_mapping', 1);
$yaml = <<<EOD
parent:
child_mapping:
value: bar
child_mapping:
value: bar
EOD;
$tests[] = array($yaml, 'child_mapping', 4);
$yaml = <<<EOD
parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] }
EOD;
$tests[] = array($yaml, 'child_sequence', 1);
$yaml = <<<EOD
parent:
child_sequence:
- key1
- key2
- key3
child_sequence:
- key1
- key2
- key3
EOD;
$tests[] = array($yaml, 'child_sequence', 6);
return $tests;
}
public function testEmptyValue()
{
$input = <<<'EOF'
@ -906,37 +1077,21 @@ EOF;
}
/**
* @group legacy
* throw ParseException in Symfony 3.0
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage A colon cannot be used in an unquoted mapping value
*/
public function testColonInMappingValueException()
{
$yaml = <<<EOF
$yaml = <<<'EOF'
foo: bar: baz
EOF;
$deprecations = array();
set_error_handler(function ($type, $msg) use (&$deprecations) {
if (E_USER_DEPRECATED !== $type) {
restore_error_handler();
return call_user_func_array('PHPUnit_Util_ErrorHandler::handleError', func_get_args());
}
$deprecations[] = $msg;
});
$this->parser->parse($yaml);
restore_error_handler();
$this->assertCount(1, $deprecations);
$this->assertContains('Using a colon in the unquoted mapping value "bar: baz" in line 1 is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', $deprecations[0]);
}
public function testColonInMappingValueExceptionNotTriggeredByColonInComment()
{
$yaml = <<<EOT
$yaml = <<<'EOT'
foo:
bar: foobar # Note: a comment after a colon
EOT;
@ -1037,7 +1192,7 @@ EOT
);
$tests[] = array($yaml, $expected);
$yaml = <<<EOT
$yaml = <<<'EOT'
foo:
bar:
scalar-block: >
@ -1080,7 +1235,7 @@ EOT;
public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks()
{
$yaml = <<<EOT
$yaml = <<<'EOT'
test: >
<h2>A heading</h2>
@ -1092,7 +1247,7 @@ EOT;
$this->assertSame(
array(
'test' => <<<EOT
'test' => <<<'EOT'
<h2>A heading</h2>
<ul> <li>a list</li> <li>may be a good example</li> </ul>
EOT
@ -1104,7 +1259,7 @@ EOT
public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks()
{
$yaml = <<<EOT
$yaml = <<<'EOT'
test: >
<h2>A heading</h2>
@ -1116,7 +1271,7 @@ EOT;
$this->assertSame(
array(
'test' => <<<EOT
'test' => <<<'EOT'
<h2>A heading</h2>
<ul>
<li>a list</li>
@ -1128,6 +1283,201 @@ EOT
$this->parser->parse($yaml)
);
}
/**
* @dataProvider getBinaryData
*/
public function testParseBinaryData($data)
{
$this->assertSame(array('data' => 'Hello world'), $this->parser->parse($data));
}
public function getBinaryData()
{
return array(
'enclosed with double quotes' => array('data: !!binary "SGVsbG8gd29ybGQ="'),
'enclosed with single quotes' => array("data: !!binary 'SGVsbG8gd29ybGQ='"),
'containing spaces' => array('data: !!binary "SGVs bG8gd 29ybGQ="'),
'in block scalar' => array(
<<<'EOT'
data: !!binary |
SGVsbG8gd29ybGQ=
EOT
),
'containing spaces in block scalar' => array(
<<<'EOT'
data: !!binary |
SGVs bG8gd 29ybGQ=
EOT
),
);
}
/**
* @dataProvider getInvalidBinaryData
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
public function testParseInvalidBinaryData($data, $expectedMessage)
{
if (method_exists($this, 'expectException')) {
$this->expectExceptionMessageRegExp($expectedMessage);
} else {
$this->setExpectedExceptionRegExp(ParseException::class, $expectedMessage);
}
$this->parser->parse($data);
}
public function getInvalidBinaryData()
{
return array(
'length not a multiple of four' => array('data: !!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
'too many equals characters' => array('data: !!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
'misplaced equals character' => array('data: !!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
'length not a multiple of four in block scalar' => array(
<<<'EOT'
data: !!binary |
SGVsbG8d29ybGQ=
EOT
,
'/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/',
),
'invalid characters in block scalar' => array(
<<<'EOT'
data: !!binary |
SGVsbG8#d29ybGQ=
EOT
,
'/The base64 encoded data \(.*\) contains invalid characters/',
),
'too many equals characters in block scalar' => array(
<<<'EOT'
data: !!binary |
SGVsbG8gd29yb===
EOT
,
'/The base64 encoded data \(.*\) contains invalid characters/',
),
'misplaced equals character in block scalar' => array(
<<<'EOT'
data: !!binary |
SGVsbG8gd29ybG=Q
EOT
,
'/The base64 encoded data \(.*\) contains invalid characters/',
),
);
}
public function testParseDateAsMappingValue()
{
$yaml = <<<'EOT'
date: 2002-12-14
EOT;
$expectedDate = new \DateTime();
$expectedDate->setTimeZone(new \DateTimeZone('UTC'));
$expectedDate->setDate(2002, 12, 14);
$expectedDate->setTime(0, 0, 0);
$this->assertEquals(array('date' => $expectedDate), $this->parser->parse($yaml, Yaml::PARSE_DATETIME));
}
/**
* @param $lineNumber
* @param $yaml
* @dataProvider parserThrowsExceptionWithCorrectLineNumberProvider
*/
public function testParserThrowsExceptionWithCorrectLineNumber($lineNumber, $yaml)
{
if (method_exists($this, 'expectException')) {
$this->expectException('\Symfony\Component\Yaml\Exception\ParseException');
$this->expectExceptionMessage(sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber));
} else {
$this->setExpectedException('\Symfony\Component\Yaml\Exception\ParseException', sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber));
}
$this->parser->parse($yaml);
}
public function parserThrowsExceptionWithCorrectLineNumberProvider()
{
return array(
array(
4,
<<<'YAML'
foo:
-
# bar
bar: "123",
YAML
),
array(
5,
<<<'YAML'
foo:
-
# bar
# bar
bar: "123",
YAML
),
array(
8,
<<<'YAML'
foo:
-
# foobar
baz: 123
bar:
-
# bar
bar: "123",
YAML
),
array(
10,
<<<'YAML'
foo:
-
# foobar
# foobar
baz: 123
bar:
-
# bar
# bar
bar: "123",
YAML
),
);
}
public function testParseMultiLineQuotedString()
{
$yaml = <<<EOT
foo: "bar
baz
foobar
foo"
bar: baz
EOT;
$this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml));
}
public function testParseMultiLineUnquotedString()
{
$yaml = <<<EOT
foo: bar
baz
foobar
foo
bar: baz
EOT;
$this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml));
}
}
class B

View File

@ -11,9 +11,10 @@
namespace Symfony\Component\Yaml\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;
class YamlTest extends \PHPUnit_Framework_TestCase
class YamlTest extends TestCase
{
public function testParseAndDump()
{
@ -23,18 +24,6 @@ class YamlTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($data, $parsed);
}
/**
* @group legacy
*/
public function testLegacyParseFromFile()
{
$filename = __DIR__.'/Fixtures/index.yml';
$contents = file_get_contents($filename);
$parsedByFilename = Yaml::parse($filename);
$parsedByContents = Yaml::parse($contents);
$this->assertEquals($parsedByFilename, $parsedByContents);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The indentation must be greater than zero

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;
/**
* Unescaper encapsulates unescaping rules for single and double-quoted
* YAML strings.
@ -21,16 +23,6 @@ namespace Symfony\Component\Yaml;
*/
class Unescaper
{
/**
* Parser and Inline assume UTF-8 encoding, so escaped Unicode characters
* must be converted to that encoding.
*
* @deprecated since version 2.5, to be removed in 3.0
*
* @internal
*/
const ENCODING = 'UTF-8';
/**
* Regex fragment that matches an escaped character in a double quoted string.
*/
@ -39,9 +31,9 @@ class Unescaper
/**
* Unescapes a single quoted string.
*
* @param string $value A single quoted string.
* @param string $value A single quoted string
*
* @return string The unescaped string.
* @return string The unescaped string
*/
public function unescapeSingleQuotedString($value)
{
@ -51,15 +43,14 @@ class Unescaper
/**
* Unescapes a double quoted string.
*
* @param string $value A double quoted string.
* @param string $value A double quoted string
*
* @return string The unescaped string.
* @return string The unescaped string
*/
public function unescapeDoubleQuotedString($value)
{
$self = $this;
$callback = function ($match) use ($self) {
return $self->unescapeCharacter($match[0]);
$callback = function ($match) {
return $this->unescapeCharacter($match[0]);
};
// evaluate the string
@ -72,11 +63,8 @@ class Unescaper
* @param string $value An escaped character
*
* @return string The unescaped character
*
* @internal This method is public to be usable as callback. It should not
* be used in user code. Should be changed in 3.0.
*/
public function unescapeCharacter($value)
private function unescapeCharacter($value)
{
switch ($value[1]) {
case '0':
@ -126,9 +114,7 @@ class Unescaper
case 'U':
return self::utf8chr(hexdec(substr($value, 2, 8)));
default:
@trigger_error('Not escaping a backslash in a double-quoted string is deprecated since Symfony 2.8 and will throw a ParseException in 3.0.', E_USER_DEPRECATED);
return $value;
throw new ParseException(sprintf('Found unknown escape character "%s".', $value));
}
}

View File

@ -20,6 +20,16 @@ use Symfony\Component\Yaml\Exception\ParseException;
*/
class Yaml
{
const DUMP_OBJECT = 1;
const PARSE_EXCEPTION_ON_INVALID_TYPE = 2;
const PARSE_OBJECT = 4;
const PARSE_OBJECT_FOR_MAP = 8;
const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
const PARSE_DATETIME = 32;
const DUMP_OBJECT_AS_MAP = 64;
const DUMP_MULTI_LINE_LITERAL_BLOCK = 128;
const PARSE_CONSTANT = 256;
/**
* Parses YAML into a PHP value.
*
@ -29,72 +39,81 @@ class Yaml
* print_r($array);
* </code>
*
* As this method accepts both plain strings and file names as an input,
* you must validate the input before calling this method. Passing a file
* as an input is a deprecated feature and will be removed in 3.0.
*
* Note: the ability to pass file names to the Yaml::parse method is deprecated since version 2.2 and will be removed in 3.0. Pass the YAML contents of the file instead.
*
* @param string $input Path to a YAML file or a string containing YAML
* @param bool $exceptionOnInvalidType True if an exception must be thrown on invalid types false otherwise
* @param bool $objectSupport True if object support is enabled, false otherwise
* @param bool $objectForMap True if maps should return a stdClass instead of array()
* @param string $input A string containing YAML
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
*
* @return mixed The YAML converted to a PHP value
*
* @throws ParseException If the YAML is not valid
*/
public static function parse($input, $exceptionOnInvalidType = false, $objectSupport = false, $objectForMap = false)
public static function parse($input, $flags = 0)
{
// if input is a file, process it
$file = '';
if (strpos($input, "\n") === false && is_file($input)) {
@trigger_error('The ability to pass file names to the '.__METHOD__.' method is deprecated since version 2.2 and will be removed in 3.0. Pass the YAML contents of the file instead.', E_USER_DEPRECATED);
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if (false === is_readable($input)) {
throw new ParseException(sprintf('Unable to parse "%s" as the file is not readable.', $input));
if ($flags) {
$flags = self::PARSE_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
$file = $input;
$input = file_get_contents($file);
if (func_num_args() >= 3) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
if (func_get_arg(2)) {
$flags |= self::PARSE_OBJECT;
}
}
if (func_num_args() >= 4) {
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
if (func_get_arg(3)) {
$flags |= self::PARSE_OBJECT_FOR_MAP;
}
}
$yaml = new Parser();
try {
return $yaml->parse($input, $exceptionOnInvalidType, $objectSupport, $objectForMap);
} catch (ParseException $e) {
if ($file) {
$e->setParsedFile($file);
}
throw $e;
}
return $yaml->parse($input, $flags);
}
/**
* Dumps a PHP array to a YAML string.
* Dumps a PHP value to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param array $array PHP array
* @param int $inline The level where you switch to inline YAML
* @param int $indent The amount of spaces to use for indentation of nested nodes.
* @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise
* @param bool $objectSupport true if object support is enabled, false otherwise
* @param mixed $input The PHP value
* @param int $inline The level where you switch to inline YAML
* @param int $indent The amount of spaces to use for indentation of nested nodes
* @param int $flags A bit field of DUMP_* constants to customize the dumped YAML string
*
* @return string A YAML string representing the original PHP array
* @return string A YAML string representing the original PHP value
*/
public static function dump($array, $inline = 2, $indent = 4, $exceptionOnInvalidType = false, $objectSupport = false)
public static function dump($input, $inline = 2, $indent = 4, $flags = 0)
{
if ($indent < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = self::DUMP_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
$yaml = new Dumper();
$yaml->setIndentation($indent);
if (func_num_args() >= 5) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the DUMP_OBJECT flag instead.', E_USER_DEPRECATED);
return $yaml->dump($array, $inline, 0, $exceptionOnInvalidType, $objectSupport);
if (func_get_arg(4)) {
$flags |= self::DUMP_OBJECT;
}
}
$yaml = new Dumper($indent);
return $yaml->dump($input, $inline, 0, $flags);
}
}

View File

@ -16,7 +16,13 @@
}
],
"require": {
"php": ">=5.3.9"
"php": ">=5.5.9"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Yaml\\": "" },
@ -27,7 +33,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
"dev-master": "3.2-dev"
}
}
}