8000 Add Yaml::PARSE_EXCEPTION_ON_DUPLICATE to throw exceptions on duplicates by alexpott · Pull Request #19529 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

Add Yaml::PARSE_EXCEPTION_ON_DUPLICATE to throw exceptions on duplicates #19529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
6 changes: 6 additions & 0 deletions UPGRADE-3.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,9 @@ Validator
// ...
}
```

Yaml
----

* Support for silently ignoring duplicate keys in YAML has been deprecated and
will lead to a `ParseException` in Symfony 4.0.
3 changes: 3 additions & 0 deletions UPGRADE-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ Yaml
* The `!!php/object` tag to indicate dumped PHP objects was removed in favor of
the `!php/object` tag.

* Duplicate keys in YAML leads to a `ParseException`.


Validator
---------

Expand Down
3 changes: 3 additions & 0 deletions src/Symfony/Component/Yaml/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ CHANGELOG
Yaml::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_CONSTANT);
```

* Support for silently ignoring duplicate keys in YAML has been deprecated and
will lead to a `ParseException` in Symfony 4.0.

3.1.0
-----

Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Yaml/Inline.php
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
// are processed sequentially.
if (!isset($output[$key])) {
$output[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key), E_USER_DEPRECATED);
}
$done = true;
break;
Expand All @@ -486,6 +488,8 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
// are processed sequentially.
if (!isset($output[$key])) {
$output[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key), E_USER_DEPRECATED);
}
$done = true;
break;
Expand All @@ -499,6 +503,8 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
// are processed sequentially.
if (!isset($output[$key])) {
$output[$key] = $value;
} else {
@trigger_error(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key), E_USER_DEPRECATED);
}
$done = true;
--$i;
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Yaml/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,17 @@ public function parse($value, $flags = 0)
// 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 whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key), E_USER_DEPRECATED);
}
} else {
$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 whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key), E_USER_DEPRECATED);
}
}
} else {
Expand All @@ -256,6 +260,8 @@ public function parse($value, $flags = 0)
// 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 whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key), E_USER_DEPRECATED);
}
}
if ($isRef) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ php: |
array(
'fixed' => 1230.15,
)
---
test: Float
yaml: |
canonical: 1.23015e+3
Expand Down
5 changes: 0 additions & 5 deletions src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml
A3E2
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,7 @@ yaml: |
x: Oren
c:
foo: bar
foo: ignore
bar: foo
duplicate:
foo: bar
foo: ignore
foo2: &foo2
a: Ballmer
ding: &dong [ fi, fei, fo, fam]
Expand All @@ -48,7 +44,6 @@ 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'),
'foo2' => array('a' => 'Ballmer'),
'ding' => array('fi', 'fei', 'fo', 'fam'),
'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'),
Expand Down
74 changes: 74 additions & 0 deletions src/Symfony/Component/Yaml/Tests/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Symfony\Component\Yaml\Tests;

use Symfony\Bridge\PhpUnit\ErrorAssert;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Yaml\Parser;

Expand Down Expand Up @@ -770,6 +771,7 @@ public function testScalarInSequence()
*
* @see http://yaml.org/spec/1.2/spec.html#id2759572
* @see http://yaml.org/spec/1.1/#id932806
* @group legacy
*/
public function testMappingDuplicateKeyBlock()
{
Expand All @@ -789,6 +791,9 @@ public function testMappingDuplicateKeyBlock()
$this->assertSame($expected, Yaml::parse($input));
}

/**
* @group legacy
*/
public function testMappingDuplicateKeyFlow()
{
$input = <<<EOD
Expand All @@ -803,6 +808,75 @@ public function testMappingDuplicateKeyFlow()
$this->assertSame($expected, Yaml::parse($input));
}

/**
* @dataProvider getParseExceptionOnDuplicateData
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing note saying that this should turned to an @expectedException assertion on 4.0, isn't it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we need it, the test will fail anyway when the deprecation will be removed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need it, but it may help the one doing the cleanup when preparing 4.0...

* @requires function Symfony\Bridge\PhpUnit\ErrorAssert::assertDeprecationsAreTriggered
* throws \Symfony\Component\Yaml\Exception\ParseException in 4.0
*/
public function testParseExceptionOnDuplicate($input, $duplicate_key)
{
ErrorAssert::assertDeprecationsAreTriggered(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicates in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $duplicate_key), function () use ($input) {
Yaml::parse($input);
});
}

public function getParseExceptionOnDuplicateData()
{
$tests = array();

$yaml = <<<EOD
parent: { child: first, child: duplicate }
EOD;
$tests[] = array($yaml, 'child');

$yaml = <<<EOD
parent:
child: first,
child: duplicate
EOD;
$tests[] = array($yaml, 'child');

$yaml = <<<EOD
parent: { child: foo }
parent: { child: bar }
EOD;
$tests[] = array($yaml, 'parent');

$yaml = <<<EOD
parent: { child_mapping: { value: bar}, child_mapping: { value: bar} }
EOD;
$tests[] = array($yaml, 'child_mapping');

$yaml = <<<EOD
parent:
child_mapping:
value: bar
child_mapping:
value: bar
EOD;
$tests[] = array($yaml, 'child_mapping');

$yaml = <<<EOD
parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] }
EOD;
$tests[] = array($yaml, 'child_sequence');

$yaml = <<<EOD
parent:
child_sequence:
- key1
- key2
- key3
child_sequence:
- key1
- key2
- key3
EOD;
$tests[] = array($yaml, 'child_sequence');

return $tests;
}

public function testEmptyValue()
{
$input = <<<'EOF'
Expand Down
0