diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 7d40c0597f..f3f168fee5 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -246,7 +246,7 @@ class Parser $key = (string) $key; } - if ('<<' === $key) { + if ('<<' === $key && (!isset($values['value']) || !self::preg_match('#^&(?P[^ ]+)#u', $values['value'], $refMatches))) { $mergeNode = true; $allowOverwrite = true; if (isset($values['value'][0]) && '*' === $values['value'][0]) { @@ -303,7 +303,7 @@ class Parser $data += $parsed; // array union } } - } elseif (isset($values['value']) && self::preg_match('#^&(?P[^ ]++) *+(?P.*)#u', $values['value'], $matches)) { + } elseif ('<<' !== $key && isset($values['value']) && self::preg_match('#^&(?P[^ ]++) *+(?P.*)#u', $values['value'], $matches)) { $isRef = $matches['ref']; $values['value'] = $matches['value']; } @@ -311,7 +311,7 @@ class Parser $subTag = null; if ($mergeNode) { // Merge keys - } elseif (!isset($values['value']) || '' === $values['value'] || 0 === strpos($values['value'], '#') || (null !== $subTag = $this->getLineTag($values['value'], $flags))) { + } elseif (!isset($values['value']) || '' === $values['value'] || 0 === strpos($values['value'], '#') || (null !== $subTag = $this->getLineTag($values['value'], $flags)) || '<<' === $key) { // hash // if next line is less indented or equal, then it means that the current value is null if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) { @@ -330,9 +330,12 @@ class Parser // remember the parsed line number here in case we need it to provide some contexts in error messages below $realCurrentLineNbKey = $this->getRealCurrentLineNb(); $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])) { + if ('<<' === $key) { + $this->refs[$refMatches['ref']] = $value; + $data += $value; + } elseif ($allowOverwrite || !isset($data[$key])) { + // Spec: Keys MUST be unique; first one wins. + // But overwriting is allowed when a merge node is used in current block. if (null !== $subTag) { $data[$key] = new TaggedValue($subTag, $value); } else { diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 67ed642084..44b4867424 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -1913,6 +1913,34 @@ YAML; $this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP)); } + + public function testParseReferencesOnMergeKeys() + { + $yaml = << array( + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'baz', + ), + 'mergekeyderef' => array( + 'd' => 'quux', + 'b' => 'bar', + 'c' => 'baz', + ), + ); + + $this->assertSame($expected, $this->parser->parse($yaml)); + } } class B