parse merge keys with PARSE_OBJECT_FOR_MAP flag

This commit is contained in:
Christian Flothmann 2017-09-13 19:40:55 +02:00
parent cb2a1a3786
commit 534eaed7ae
2 changed files with 52 additions and 3 deletions

View File

@ -249,7 +249,7 @@ class Parser
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);
@ -257,6 +257,10 @@ class Parser
$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);
}
@ -270,6 +274,10 @@ class Parser
}
$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);
}
@ -279,6 +287,10 @@ class Parser
// 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);
}
@ -902,7 +914,7 @@ class Parser
// 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;
@ -910,7 +922,7 @@ class Parser
// 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;

View File

@ -1865,6 +1865,43 @@ YAML;
$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