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

Skip to content

Commit c7791f4

Browse files
committed
Add Yaml::PARSE_EXCEPTION_ON_DUPLICATE to throw exceptions on duplicates
1 parent e408b50 commit c7791f4

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

src/Symfony/Component/Yaml/Inline.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Inline
2929
private static $objectSupport = false;
3030
private static $objectForMap = false;
3131
private static $constantSupport = false;
32+
private static $exceptionOnDuplicate = false;
3233

3334
/**
3435
* Converts a YAML string to a PHP array.
@@ -79,6 +80,7 @@ public static function parse($value, $flags = 0, $references = array())
7980
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
8081
self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
8182
self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
83+
self::$exceptionOnDuplicate = (bool) (Yaml::PARSE_EXCEPTION_ON_DUPLICATE & $flags);
8284

8385
$value = trim($value);
8486

@@ -476,6 +478,9 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
476478
if (!isset($output[$key])) {
477479
$output[$key] = $value;
478480
}
481+
elseif (static::$exceptionOnDuplicate) {
482+
throw new ParseException(sprintf('Duplicate key "%s" detected whilst parsing YAML', $key));
483+
}
479484
$done = true;
480485
break;
481486
case '{':
@@ -487,6 +492,9 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
487492
if (!isset($output[$key])) {
488493
$output[$key] = $value;
489494
}
495+
elseif (static::$exceptionOnDuplicate) {
496+
throw new ParseException(sprintf('Duplicate key "%s" detected whilst parsing YAML', $key));
497+
}
490498
$done = true;
491499
break;
492500
case ':':
@@ -500,6 +508,9 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar
500508
if (!isset($output[$key])) {
501509
$output[$key] = $value;
502510
}
511+
elseif (static::$exceptionOnDuplicate) {
512+
throw new ParseException(sprintf('Duplicate key "%s" detected whilst parsing YAML', $key));
513+
}
503514
$done = true;
504515
--$i;
505516
}

src/Symfony/Component/Yaml/Parser.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public function parse($value, $flags = 0)
104104
$data = array();
105105
$context = null;
106106
$allowOverwrite = false;
107+
$exceptionOnDuplicate = (bool) (Yaml::PARSE_EXCEPTION_ON_DUPLICATE & $flags);
107108
while ($this->moveToNextLine()) {
108109
if ($this->isCurrentLineEmpty()) {
109110
continue;
@@ -242,13 +243,19 @@ public function parse($value, $flags = 0)
242243
if ($allowOverwrite || !isset($data[$key])) {
243244
$data[$key] = null;
244245
}
246+
elseif ($exceptionOnDuplicate) {
247+
throw new ParseException(sprintf('Duplicate key "%s" detected whilst parsing YAML', $key));
248+
}
245249
} else {
246250
$value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags);
247251
// Spec: Keys MUST be unique; first one wins.
248252
// But overwriting is allowed when a merge node is used in current block.
249253
if ($allowOverwrite || !isset($data[$key])) {
250254
$data[$key] = $value;
251255
}
256+
elseif ($exceptionOnDuplicate) {
257+
throw new ParseException(sprintf('Duplicate key "%s" detected whilst parsing YAML', $key));
258+
}
252259
}
253260
} else {
254261
$value = $this->parseValue($values['value'], $flags, $context);
@@ -257,6 +264,9 @@ public function parse($value, $flags = 0)
257264
if ($allowOverwrite || !isset($data[$key])) {
258265
$data[$key] = $value;
259266
}
267+
elseif ($exceptionOnDuplicate) {
268+
throw new ParseException(sprintf('Duplicate key "%s" detected whilst parsing YAML', $key));
269+
}
260270
}
261271
if ($isRef) {
262272
$this->refs[$isRef] = $data[$key];

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,70 @@ public function testMappingDuplicateKeyFlow()
803803
$this->assertSame($expected, Yaml::parse($input));
804804
}
805805

806+
/**
807+
* @dataProvider getParseExceptionOnDuplicateData
808+
*/
809+
public function testParseExceptionOnDuplicate($input, $duplicate_key) {
810+
$this->setExpectedException('\Symfony\Component\Yaml\Exception\ParseException', 'Duplicate key "' . $duplicate_key . '" detected whilst parsing YAML');
811+
Yaml::parse($input, Yaml::PARSE_EXCEPTION_ON_DUPLICATE);
812+
}
813+
814+
public function getParseExceptionOnDuplicateData() {
815+
$tests = array();
816+
817+
$yaml = <<<EOD
818+
parent: { child: first, child: duplicate }
819+
EOD;
820+
$tests[] = [$yaml, 'child'];
821+
822+
$yaml = <<<EOD
823+
parent:
824+
child: first,
825+
child: duplicate
826+
EOD;
827+
$tests[] = [$yaml, 'child'];
828+
829+
$yaml = <<<EOD
830+
parent: { child: foo }
831+
parent: { child: bar }
832+
EOD;
833+
$tests[] = [$yaml, 'parent'];
834+
835+
$yaml = <<<EOD
836+
parent: { child_mapping: { value: bar}, child_mapping: { value: bar} }
837+
EOD;
838+
$tests[] = [$yaml, 'child_mapping'];
839+
840+
$yaml = <<<EOD
841+
parent:
842+
child_mapping:
843+
value: bar
844+
child_mapping:
845+
value: bar
846+
EOD;
847+
$tests[] = [$yaml, 'child_mapping'];
848+
849+
$yaml = <<<EOD
850+
parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] }
851+
EOD;
852+
$tests[] = [$yaml, 'child_sequence'];
853+
854+
$yaml = <<<EOD
855+
parent:
856+
child_sequence:
857+
- key1
858+
- key2
859+
- key3
860+
child_sequence:
861+
- key1
862+
- key2
863+
- key3
864+
EOD;
865+
$tests[] = [$yaml, 'child_sequence'];
866+
867+
return $tests;
868+
}
869+
806870
public function testEmptyValue()
807871
{
808872
$input = <<<'EOF'

src/Symfony/Component/Yaml/Yaml.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Yaml
2929
const DUMP_OBJECT_AS_MAP = 64;
3030
const DUMP_MULTI_LINE_LITERAL_BLOCK = 128;
3131
const PARSE_CONSTANT = 256;
32+
const PARSE_EXCEPTION_ON_DUPLICATE = 512;
3233

3334
/**
3435
* Parses YAML into a PHP value.

0 commit comments

Comments
 (0)
0