@@ -76,7 +76,7 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
76
76
throw new ParseException ('A YAML file cannot contain tabs as indentation. ' , $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
77
77
}
78
78
79
- $ isRef = $ isInPlace = $ isProcessed = false ;
79
+ $ isRef = $ mergeNode = false ;
80
80
if (preg_match ('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u ' , $ this ->currentLine , $ values )) {
81
81
if ($ context && 'mapping ' == $ context ) {
82
82
throw new ParseException ('You cannot define a sequence item when in a mapping ' );
@@ -132,10 +132,23 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
132
132
}
133
133
134
134
if ('<< ' === $ key ) {
135
+ $ mergeNode = true ;
135
136
if (isset ($ values ['value ' ]) && 0 === strpos ($ values ['value ' ], '* ' )) {
136
- $ isInPlace = substr ($ values ['value ' ], 1 );
137
- if (!array_key_exists ($ isInPlace , $ this ->refs )) {
138
- throw new ParseException (sprintf ('Reference "%s" does not exist. ' , $ isInPlace ), $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
137
+ $ refName = substr ($ values ['value ' ], 1 );
138
+ if (!array_key_exists ($ refName , $ this ->refs )) {
139
+ throw new ParseException (sprintf ('Reference "%s" does not exist. ' , $ refName ), $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
140
+ }
141
+
142
+ $ refValue = $ this ->refs [$ refName ];
143
+
144
+ if (!is_array ($ refValue )) {
145
+ throw new ParseException ('YAML merge keys used with a scalar value instead of an array. ' , $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
146
+ }
147
+
148
+ foreach ($ refValue as $ key => $ value ) {
149
+ if (!isset ($ data [$ key ])) {
150
+ $ data [$ key ] = $ value ;
151
+ }
139
152
}
140
153
} else {
141
154
if (isset ($ values ['value ' ]) && $ values ['value ' ] !== '' ) {
@@ -152,26 +165,37 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
152
165
throw new ParseException ('YAML merge keys used with a scalar value instead of an array. ' , $ this ->getRealCurrentLineNb () + 1 , $ this ->currentLine );
153
166
}
154
167
155
- $ isProcessed = true ;
156
168
if (isset ($ parsed [0 ])) {
157
- // Numeric array, merge individual elements
169
+ // If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes
170
+ // and each of these nodes is merged in turn according to its order in the sequence. Keys in mapping nodes earlier
171
+ // in the sequence override keys specified in later mapping nodes.
158
172
foreach ($ parsed as $ parsedItem ) {
159
173
if (!is_array ($ parsedItem )) {
160
174
throw new ParseException ('Merge items must be arrays. ' , $ this ->getRealCurrentLineNb () + 1 , $ parsedItem );
161
175
}
162
- $ data = array_merge ($ data , $ parsedItem );
176
+
177
+ foreach ($ parsedItem as $ key => $ value ) {
178
+ if (!isset ($ data [$ key ])) {
179
+ $ data [$ key ] = $ value ;
180
+ }
181
+ }
163
182
}
164
183
} else {
165
- // Associative array
166
- $ data = $ parsed ;
184
+ // If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the
185
+ // current mapping, unless the key already exists in it.
186
+ foreach ($ parsed as $ key => $ value ) {
187
+ if (!isset ($ data [$ key ])) {
188
+ $ data [$ key ] = $ value ;
189
+ }
190
+ }
167
191
}
168
192
}
169
193
} elseif (isset ($ values ['value ' ]) && preg_match ('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u ' , $ values ['value ' ], $ matches )) {
170
194
$ isRef = $ matches ['ref ' ];
171
195
$ values ['value ' ] = $ matches ['value ' ];
172
196
}
173
197
174
- if ($ isProcessed ) {
198
+ if ($ mergeNode ) {
175
199
// Merge keys
176
200
} elseif (!isset ($ values ['value ' ]) || '' == trim ($ values ['value ' ], ' ' ) || 0 === strpos (ltrim ($ values ['value ' ], ' ' ), '# ' )) {
177
201
// hash
@@ -196,16 +220,12 @@ public function parse($value, $exceptionOnInvalidType = false, $objectSupport =
196
220
}
197
221
}
198
222
} else {
199
- if ($ isInPlace ) {
200
- $ data = $ this ->refs [$ isInPlace ];
201
- } else {
202
- $ value = $ this ->parseValue ($ values ['value ' ], $ exceptionOnInvalidType , $ objectSupport );;
203
- // Spec: Keys MUST be unique; first one wins.
204
- // Parser cannot abort this mapping earlier, since lines
205
- // are processed sequentially.
206
- if (!isset ($ data [$ key ])) {
207
- $ data [$ key ] = $ value ;
208
- }
223
+ $ value = $ this ->parseValue ($ values ['value ' ], $ exceptionOnInvalidType , $ objectSupport );
224
+ // Spec: Keys MUST be unique; first one wins.
225
+ // Parser cannot abort this mapping earlier, since lines
226
+ // are processed sequentially.
227
+ if (!isset ($ data [$ key ])) {
228
+ $ data [$ key ] = $ value ;
209
229
}
210
230
}
211
231
} else {
0 commit comments