Permalink
Browse files

minor #22948 [Yaml] Recommend using quotes instead of PARSE_KEYS_AS_S…

…TRINGS (GuilhemN)

This PR was squashed before being merged into the 3.4 branch (closes #22948).

Discussion
----------

[Yaml] Recommend using quotes instead of PARSE_KEYS_AS_STRINGS

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | no <!-- don't forget updating src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | yes <!-- don't forget updating UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets | #... <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        |

Sorry for opening this so lately... I just realized that we could get rid of `Yaml::PARSE_KEYS_AS_STRINGS` just by recommending using quotes...

~This way we don't allow a behavior not respecting the spec and we won't need to deprecate `PARSE_KEYS_AS_STRINGS` later.~

~Is it too late for this to be merged in 3.3?~

ping @xabbuh

Commits
-------

b63c55c [Yaml] Recommend using quotes instead of PARSE_KEYS_AS_STRINGS
  • Loading branch information...
xabbuh committed Aug 3, 2017
2 parents 2454a4f + b63c55c commit d9bf2534eff9640a9e28baf0b857c35d62467982
View
@@ -162,3 +162,30 @@ Yaml
* Using the non-specific tag `!` is deprecated and will have a different
behavior in 4.0. Use a plain integer or `!!float` instead.
* Using the `Yaml::PARSE_KEYS_AS_STRINGS` flag is deprecated as it will be
removed in 4.0.
Before:
```php
$yaml = <<<YAML
null: null key
true: boolean true
2.0: float key
YAML;
Yaml::parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS);
```
After:
```php
$yaml = <<<YAML
"null": null key
"true": boolean true
"2.0": float key
YAML;
Yaml::parse($yaml);
```
View
@@ -721,6 +721,32 @@ Yaml
Yaml::parse($yaml);
```
* Removed the `Yaml::PARSE_KEYS_AS_STRINGS` flag.
Before:
```php
$yaml = <<<YAML
null: null key
true: boolean true
2.0: float key
YAML;
Yaml::parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS);
```
After:
```php
$yaml = <<<YAML
"null": null key
"true": boolean true
"2.0": float key
YAML;
Yaml::parse($yaml);
```
* Omitting the key of a mapping is not supported anymore and throws a `ParseException`.
* Mappings with a colon (`:`) that is not followed by a whitespace are not
@@ -609,7 +609,7 @@ protected function loadFile($file)
}
try {
$configuration = $this->yamlParser->parse(file_get_contents($file), Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_KEYS_AS_STRINGS);
$configuration = $this->yamlParser->parse(file_get_contents($file), Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
} catch (ParseException $e) {
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $file), 0, $e);
}
@@ -17,7 +17,6 @@
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads Yaml routing files.
@@ -59,7 +58,7 @@ public function load($file, $type = null)
}
try {
$parsedConfig = $this->yamlParser->parse(file_get_contents($path), Yaml::PARSE_KEYS_AS_STRINGS);
$parsedConfig = $this->yamlParser->parse(file_get_contents($path));
} catch (ParseException $e) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
}
@@ -15,7 +15,6 @@
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
use Symfony\Component\Serializer\Mapping\ClassMetadataInterface;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Yaml;
/**
* YAML File Loader.
@@ -114,7 +113,7 @@ private function getClassesFromYaml()
$this->yamlParser = new Parser();
}
$classes = $this->yamlParser->parse(file_get_contents($this->file), Yaml::PARSE_KEYS_AS_STRINGS);
$classes = $this->yamlParser->parse(file_get_contents($this->file));
if (empty($classes)) {
return array();
@@ -15,7 +15,6 @@
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
/**
* YamlFileLoader loads translations from Yaml files.
@@ -40,7 +39,7 @@ protected function loadResource($resource)
}
try {
$messages = $this->yamlParser->parse(file_get_contents($resource), Yaml::PARSE_KEYS_AS_STRINGS);
$messages = $this->yamlParser->parse(file_get_contents($resource));
} catch (ParseException $e) {
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e);
}
@@ -116,7 +116,7 @@ protected function parseNodes(array $nodes)
private function parseFile($path)
{
try {
$classes = $this->yamlParser->parse(file_get_contents($path), Yaml::PARSE_KEYS_AS_STRINGS | Yaml::PARSE_CONSTANT);
$classes = $this->yamlParser->parse(file_get_contents($path), Yaml::PARSE_CONSTANT);
} catch (ParseException $e) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
}
@@ -490,7 +490,7 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
@trigger_error('Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0.', E_USER_DEPRECATED);
}
if (!(Yaml::PARSE_KEYS_AS_STRINGS & $flags)) {
if (!$isKeyQuoted) {
$evaluatedKey = self::evaluateScalar($key, $flags, $references);
if ('' !== $key && $evaluatedKey !== $key && !is_string($evaluatedKey) && !is_int($evaluatedKey)) {
@@ -86,6 +86,10 @@ public function parse($value, $flags = 0)
}
}
if (Yaml::PARSE_KEYS_AS_STRINGS & $flags) {
@trigger_error('Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since version 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable instead.', E_USER_DEPRECATED);
}
if (false === preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear to be valid UTF-8.');
}
@@ -236,7 +240,7 @@ private function doParse($value, $flags)
throw $e;
}
if (!(Yaml::PARSE_KEYS_AS_STRINGS & $flags) && !is_string($key) && !is_int($key)) {
if (!is_string($key) && !is_int($key)) {
$keyType = is_numeric($key) ? 'numeric key' : 'non-string key';
@trigger_error(sprintf('Implicit casting of %s to string is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.', $keyType), E_USER_DEPRECATED);
}
@@ -125,7 +125,7 @@ public function testSpecifications()
// TODO
} else {
eval('$expected = '.trim($test['php']).';');
$this->assertSame($expected, $this->parser->parse($this->dumper->dump($expected, 10), Yaml::PARSE_KEYS_AS_STRINGS), $test['test']);
$this->assertSame($expected, $this->parser->parse($this->dumper->dump($expected, 10)), $test['test']);
}
}
}
@@ -385,8 +385,8 @@ public function getTestsForParse()
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), Yaml::PARSE_KEYS_AS_STRINGS),
array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12), Yaml::PARSE_KEYS_AS_STRINGS),
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')),
array('{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', array('foo\'' => 'bar', 'bar"' => 'foo: bar')),
@@ -456,8 +456,8 @@ public function getTestsForParseWithMapObjects()
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), Yaml::PARSE_OBJECT_FOR_MAP | Yaml::PARSE_KEYS_AS_STRINGS),
array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12), Yaml::PARSE_OBJECT_FOR_MAP | Yaml::PARSE_KEYS_AS_STRINGS),
array('{foo: bar,bar: foo,"false": false,"null": null,integer: 12}', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12), Yaml::PARSE_OBJECT_FOR_MAP),
array('{ foo : bar, bar : foo, "false" : false, "null" : null, integer : 12 }', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12), Yaml::PARSE_OBJECT_FOR_MAP),
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')),
array('{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', (object) array('foo\'' => 'bar', 'bar"' => 'foo: bar')),
@@ -538,7 +538,7 @@ public function getTestsForDump()
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), Yaml::PARSE_KEYS_AS_STRINGS),
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')),
// nested sequences and mappings
@@ -554,7 +554,7 @@ public function getTestsForDump()
array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')),
array('{ foo: { bar: { 1: 2, baz: 3 } } }', array('foo' => array('bar' => array(1 => 2, 'baz' => 3))), Yaml::PARSE_KEYS_AS_STRINGS),
array('{ foo: { bar: { 1: 2, baz: 3 } } }', array('foo' => array('bar' => array(1 => 2, 'baz' => 3)))),
);
}
@@ -739,11 +739,14 @@ public function testImplicitStringCastingOfMappingKeysIsDeprecated($yaml, $expec
}
/**
* @group legacy
* @expectedDeprecation Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since version 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable instead.
* @expectedDeprecation Implicit casting of incompatible mapping keys to strings is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.
* @dataProvider getNotPhpCompatibleMappingKeyData
*/
public function testExplicitStringCastingOfMappingKeys($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS));
$this->assertSame($expected, Yaml::parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS));
}
public function getNotPhpCompatibleMappingKeyData()
@@ -71,6 +71,8 @@ public function getDataFormSpecifications()
}
/**
* @group legacy
* @expectedDeprecationMessage Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since version 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable
* @dataProvider getNonStringMappingKeysData
*/
public function testNonStringMappingKeys($expected, $yaml, $comment)
@@ -510,14 +512,10 @@ public function testObjectSupportDisabledButNoExceptions($input)
/**
* @dataProvider getObjectForMapTests
*/
public function testObjectForMap($yaml, $expected, $explicitlyParseKeysAsStrings = false)
public function testObjectForMap($yaml, $expected)
{
$flags = Yaml::PARSE_OBJECT_FOR_MAP;
if ($explicitlyParseKeysAsStrings) {
$flags |= Yaml::PARSE_KEYS_AS_STRINGS;
}
$this->assertEquals($expected, $this->parser->parse($yaml, $flags));
}
@@ -577,18 +575,18 @@ public function getObjectForMapTests()
$expected->map = new \stdClass();
$expected->map->{1} = 'one';
$expected->map->{2} = 'two';
$tests['numeric-keys'] = array($yaml, $expected, true);
$tests['numeric-keys'] = array($yaml, $expected);
$yaml = <<<'YAML'
map:
0: one
1: two
'0': one
'1': two
YAML;
$expected = new \stdClass();
$expected->map = new \stdClass();
$expected->map->{0} = 'one';
$expected->map->{1} = 'two';
$tests['zero-indexed-numeric-keys'] = array($yaml, $expected, true);
$tests['zero-indexed-numeric-keys'] = array($yaml, $expected);
return $tests;
}
@@ -1120,37 +1118,29 @@ public function testBooleanKeys()
$this->assertEquals($expected, $this->parser->parse($yaml));
}
public function testExplicitStringCastingOfFloatKeys()
public function testExplicitStringCasting()
{
$yaml = <<<'EOF'
foo:
1.2: "bar"
1.3: "baz"
EOF;
'1.2': "bar"
!!str 1.3: "baz"
$expected = array(
'foo' => array(
'1.2' => 'bar',
'1.3' => 'baz',
),
);
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS));
}
'true': foo
!!str false: bar
public function testExplicitStringCastingOfBooleanKeys()
{
$yaml = <<<'EOF'
true: foo
false: bar
!!str null: 'null'
'~': 'null'
EOF;
$expected = array(
'1.2' => 'bar',
'1.3' => 'baz',
'true' => 'foo',
'false' => 'bar',
'null' => 'null',
'~' => 'null',
);
$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS));
$this->assertEquals($expected, $this->parser->parse($yaml));
}
/**
@@ -1843,6 +1833,10 @@ public function testPhpConstantTagMappingKey()
$this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT));
}
/**
* @group legacy
* @expectedDeprecation Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since version 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable instead.
*/
public function testPhpConstantTagMappingKeyWithKeysCastToStrings()
{
$yaml = <<<YAML
@@ -31,6 +31,10 @@ class Yaml
const PARSE_CONSTANT = 256;
const PARSE_CUSTOM_TAGS = 512;
const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
/**
* @deprecated since version 3.4, to be removed in 4.0. Quote your evaluable keys instead.
*/
const PARSE_KEYS_AS_STRINGS = 2048;
/**

0 comments on commit d9bf253

Please sign in to comment.