From dee15623ae4a008b10027ab87803f3136c41ebbd Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 18 Jun 2014 19:47:01 +0200 Subject: [PATCH] [Yaml] fix overwriting of keys after merged map fixes symfony/symfony#11142 --- src/Symfony/Component/Yaml/Parser.php | 17 ++++++++-------- .../Yaml/Tests/Fixtures/sfMergeKey.yml | 20 +++++++++++++++++-- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 05c2db67cf76..0577b5e8853b 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -66,6 +66,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = $data = array(); $context = null; + $allowOverwrite = false; while ($this->moveToNextLine()) { if ($this->isCurrentLineEmpty()) { continue; @@ -133,6 +134,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = if ('<<' === $key) { $mergeNode = true; + $allowOverwrite = true; if (isset($values['value']) && 0 === strpos($values['value'], '*')) { $refName = substr($values['value'], 1); if (!array_key_exists($refName, $this->refs)) { @@ -202,9 +204,8 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = // if next line is less indented or equal, then it means that the current value is null if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) { // Spec: Keys MUST be unique; first one wins. - // Parser cannot abort this mapping earlier, since lines - // are processed sequentially. - if (!isset($data[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ($allowOverwrite || !isset($data[$key])) { $data[$key] = null; } } else { @@ -213,18 +214,16 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport = $parser->refs =& $this->refs; $value = $parser->parse($this->getNextEmbedBlock(), $exceptionOnInvalidType, $objectSupport); // Spec: Keys MUST be unique; first one wins. - // Parser cannot abort this mapping earlier, since lines - // are processed sequentially. - if (!isset($data[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ($allowOverwrite || !isset($data[$key])) { $data[$key] = $value; } } } else { $value = $this->parseValue($values['value'], $exceptionOnInvalidType, $objectSupport); // Spec: Keys MUST be unique; first one wins. - // Parser cannot abort this mapping earlier, since lines - // are processed sequentially. - if (!isset($data[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ($allowOverwrite || !isset($data[$key])) { $data[$key] = $value; } } diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml index c04943eec1d3..fd9910174dad 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml @@ -10,11 +10,19 @@ yaml: | a: Steve b: Clark c: Brian - bar: &bar + bar: a: before d: other <<: *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] @@ -26,4 +34,12 @@ yaml: | head: <<: [ *foo , *dong , *foo2 ] php: | - array('foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian'), 'bar' => array('a' => 'before', 'd' => 'other', 'b' => 'Clark', 'c' => 'Brian', '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')) + 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'), + 'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'fi', 'fei', 'fo', 'fam') + )