Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
bug #24189 [Yaml] parse merge keys with PARSE_OBJECT_FOR_MAP flag (xa…
…bbuh)

This PR was merged into the 3.3 branch.

Discussion
----------

[Yaml] parse merge keys with PARSE_OBJECT_FOR_MAP flag

| Q             | A
| ------------- | ---
| Branch?       | 3.3
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #24133
| License       | MIT
| Doc PR        |

Commits
-------

534eaed parse merge keys with PARSE_OBJECT_FOR_MAP flag
  • Loading branch information
fabpot committed Sep 28, 2017
2 parents cb2a1a3 + 534eaed commit 29433fa
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/Symfony/Component/Yaml/Parser.php
Expand Up @@ -249,14 +249,18 @@ private function doParse($value, $flags)
if ('<<' === $key) {
$mergeNode = true;
$allowOverwrite = true;
if (isset($values['value']) && 0 === strpos($values['value'], '*')) {
if (isset($values['value'][0]) && '*' === $values['value'][0]) {
$refName = substr(rtrim($values['value']), 1);
if (!array_key_exists($refName, $this->refs)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}

$refValue = $this->refs[$refName];

if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $refValue instanceof \stdClass) {
$refValue = (array) $refValue;
}

if (!is_array($refValue)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
Expand All @@ -270,6 +274,10 @@ private function doParse($value, $flags)
}
$parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags);

if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsed instanceof \stdClass) {
$parsed = (array) $parsed;
}

if (!is_array($parsed)) {
throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
Expand All @@ -279,6 +287,10 @@ private function doParse($value, $flags)
// and each of these nodes is merged in turn according to its order in the sequence. Keys in mapping nodes earlier
// in the sequence override keys specified in later mapping nodes.
foreach ($parsed as $parsedItem) {
if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && $parsedItem instanceof \stdClass) {
$parsedItem = (array) $parsedItem;
}

if (!is_array($parsedItem)) {
throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem);
}
Expand Down Expand Up @@ -902,15 +914,15 @@ private function cleanup($value)

// remove leading comments
$trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count);
if (1 == $count) {
if (1 === $count) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
}

// remove start of the document marker (---)
$trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count);
if (1 == $count) {
if (1 === $count) {
// items have been removed, update the offset
$this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n");
$value = $trimmedValue;
Expand Down
37 changes: 37 additions & 0 deletions src/Symfony/Component/Yaml/Tests/ParserTest.php
Expand Up @@ -1865,6 +1865,43 @@ public function testPhpConstantTagMappingKeyWithKeysCastToStrings()

$this->assertSame($expected, $this->parser->parse($yaml, Yaml::PARSE_CONSTANT | Yaml::PARSE_KEYS_AS_STRINGS));
}

public function testMergeKeysWhenMappingsAreParsedAsObjects()
{
$yaml = <<<YAML
foo: &FOO
bar: 1
bar: &BAR
baz: 2
<<: *FOO
baz:
baz_foo: 3
<<:
baz_bar: 4
foobar:
bar: ~
<<: [*FOO, *BAR]
YAML;
$expected = (object) array(
'foo' => (object) array(
'bar' => 1,
),
'bar' => (object) array(
'baz' => 2,
'bar' => 1,
),
'baz' => (object) array(
'baz_foo' => 3,
'baz_bar' => 4,
),
'foobar' => (object) array(
'bar' => null,
'baz' => 2,
),
);

$this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP));
}
}

class B
Expand Down

0 comments on commit 29433fa

Please sign in to comment.