8000 Add Yaml::PARSE_EXCEPTION_ON_DUPLICATE to throw exceptions on duplicates · symfony/symfony@cb362f2 · GitHub
[go: up one dir, main page]

Skip to content

Commit cb362f2

Browse files
alexpottfabpot
authored andcommitted
Add Yaml::PARSE_EXCEPTION_ON_DUPLICATE to throw exceptions on duplicates
1 parent e408b50 commit cb362f2

File tree

8 files changed

+99
-5
lines changed

8 files changed

+99
-5
lines changed

UPGRADE-3.2.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,9 @@ Validator
7070
// ...
7171
}
7272
```
73+
74+
Yaml
75+
----
76+
77+
* Support for silently ignoring duplicate keys in YAML has been deprecated and
78+
will lead to a `ParseException` in Symfony 4.0.

UPGRADE-4.0.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ Yaml
230230
* The `!!php/object` tag to indicate dumped PHP objects was removed in favor of
231231
the `!php/object` tag.
232232

233+
* Duplicate keys in YAML leads to a `ParseException`.
234+
235+
233236
Validator
234237
---------
235238

src/Symfony/Component/Yaml/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ CHANGELOG
1010
Yaml::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_CONSTANT);
1111
```
1212

13+
* Support for silently ignoring duplicate keys in YAML has been deprecated and
14+
will lead to a `ParseException` in Symfony 4.0.
15+
1316
3.1.0
1417
-----
1518

src/Symfony/Component/Yaml/Inline.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
475475
// are processed sequentially.
476476
if (!isset($output[$key])) {
477477
$output[$key] = $value;
478+
} else {
479+
@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);
478480
}
479481
$done = true;
480482
break;
@@ -486,6 +488,8 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
486488
// are processed sequentially.
487489
if (!isset($output[$key])) {
488490
$output[$key] = $value;
491+
} else {
492+
@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);
489493
}
490494
$done = true;
491495
break;
@@ -499,6 +503,8 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
499503
// are processed sequentially.
500504
if (!isset($output[$key])) {
501505
$output[$key] = $value;
506+
} else {
507+
@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);
502508
}
503509
$done = true;
504510
--$i;

src/Symfony/Component/Yaml/Parser.php

Lines changed: 6 additions & 0 deletions
266
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,17 @@ public function parse($value, $flags = 0)
241241
// But overwriting is allowed when a merge node is used in current block.
242242
if ($allowOverwrite || !isset($data[$key])) {
243243
$data[$key] = null;
244+
} else {
245+
@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);
244246
}
245247
} else {
246248
$value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags);
247249
// Spec: Keys MUST be unique; first one wins.
248250
// But overwriting is allowed when a merge node is used in current block.
249251
if ($allowOverwrite || !isset($data[$key])) {
250252
$data[$key] = $value;
253+
} else {
254+
@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);
251255
}
252256
}
253257
} else {
@@ -256,6 +260,8 @@ public function parse($value, $flags = 0)
256260
// But overwriting is allowed when a merge node is used in current block.
257261
if ($allowOverwrite || !isset($data[$key])) {
258262
$data[$key] = $value;
263+
} else {
264+
@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);
259265
}
260
}
261267
if ($isRef) {

src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,7 @@ php: |
15741574
array(
15751575
'fixed' => 1230.15,
15761576
)
1577+
---
15771578
test: Float
15781579
yaml: |
15791580
canonical: 1.23015e+3

src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@ yaml: |
1818
x: Oren
1919
c:
2020
foo: bar
21-
foo: ignore
2221
bar: foo
23-
duplicate:
24-
foo: bar
25-
foo: ignore
2622
foo2: &foo2
2723
a: Ballmer
2824
ding: &dong [ fi, fei, fo, fam]
@@ -48,7 +44,6 @@ php: |
4844
array(
4945
'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian'),
5046
'bar' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'),
51-
'duplicate' => array('foo' => 'bar'),
5247
'foo2' => array('a' => 'Ballmer'),
5348
'ding' => array('fi', 'fei', 'fo', 'fam'),
5449
'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'),

src/Symfony/Component/Yaml/Tests/ParserTest.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Yaml\Tests;
1313

14+
use Symfony\Bridge\PhpUnit\ErrorAssert;
1415
use Symfony\Component\Yaml\Yaml;
1516
use Symfony\Component\Yaml\Parser;
1617

@@ -770,6 +771,7 @@ public function testScalarInSequence()
770771
*
771772
* @see http://yaml.org/spec/1.2/spec.html#id2759572
772773
* @see http://yaml.org/spec/1.1/#id932806
774+
* @group legacy
773775
*/
774776
public function testMappingDuplicateKeyBlock()
775777
{
@@ -789,6 +791,9 @@ public function testMappingDuplicateKeyBlock()
789791
$this->assertSame($expected, Yaml::parse($input));
790792
}
791793

794+
/**
795+
* @group legacy
796+
*/
792797
public function testMappingDuplicateKeyFlow()
793798
{
794799
$input = <<<EOD
@@ -803,6 +808,75 @@ public function testMappingDuplicateKeyFlow()
803808
$this->assertSame($expected, Yaml::parse($input));
804809
}
805810

811+
/**
812+
* @dataProvider getParseExceptionOnDuplicateData
813+
* @requires function Symfony\Bridge\PhpUnit\ErrorAssert::assertDeprecationsAreTriggered
814+
* throws \Symfony\Component\Yaml\Exception\ParseException in 4.0
815+
*/
816+
public function testParseExceptionOnDuplicate($input, $duplicate_key)
817+
{
818+
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) {
819+
Yaml::parse($input);
820+
});
821+
}
822+
823+
public function getParseExceptionOnDuplicateData()
824+
{
825+
$tests = array();
826+
827+
$yaml = <<<EOD
828+
parent: { child: first, child: duplicate }
829+
EOD;
830+
$tests[] = array($yaml, 'child');
831+
832+
$yaml = <<<EOD
833+
parent:
834+
child: first,
835+
child: duplicate
836+
EOD;
837+
$tests[] = array($yaml, 'child');
838+
839+
$yaml = <<<EOD
840+
parent: { child: foo }
841+
parent: { child: bar }
842+
EOD;
843+
$tests[] = array($yaml, 'parent');
844+
845+
$yaml = <<<EOD
846+
parent: { child_mapping: { value: bar}, child_mapping: { value: bar} }
847+
EOD;
848+
$tests[] = array($yaml, 'child_mapping');
849+
850+
$yaml = <<<EOD
851+
parent:
852+
child_mapping:
853+
value: bar
854+
child_mapping:
855+
value: bar
856+
EOD;
857+
$tests[] = array($yaml, 'child_mapping');
858+
859+
$yaml = <<<EOD
860+
parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] }
861+
EOD;
862+
$tests[] = array($yaml, 'child_sequence');
863+
864+
$yaml = <<<EOD
865+
parent:
866+
child_sequence:
867+
- key1
868+
- key2
869+
- key3
870+
child_sequence:
871+
- key1
872+
- key2
873+
- key3
874+
EOD;
875+
$tests[] = array($yaml, 'child_sequence');
876+
877+
return $tests;
878+
}
879+
806880
public function testEmptyValue()
807881
{
808882
$input = <<<'EOF'

0 commit comments

Comments
 (0)
0