Skip to content

Commit 9ec8b5e

Browse files
committed
bug #258 Fix 2 YamlSourceManipulator bugs (weaverryan)
This PR was squashed before being merged into the 1.0-dev branch (closes #258). Discussion ---------- Fix 2 YamlSourceManipulator bugs Fixing 2 separate bugs in `YamlSourceManipulator` reported by @nikophil. These likely aren't affecting the library now, but we'll use these situations soon in some new features :). Cheers! Commits ------- 7f4f77a Fixing a bug where we didn't convert properly from a scalar value to array 3582b1d improving some logging 15d23ae Fixing a bug where we improperly tracked indentation in 2 different ways
2 parents dc5a59f + 7f4f77a commit 9ec8b5e

File tree

4 files changed

+114
-22
lines changed

4 files changed

+114
-22
lines changed

src/Util/YamlSourceManipulator.php

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ private function updateData(array $newData)
130130
$this->arrayTypeForDepths[$this->depth] = $this->isHash($currentData) ? self::ARRAY_TYPE_HASH : self::ARRAY_TYPE_SEQUENCE;
131131

132132
$this->log(sprintf(
133-
'Array type: %s, format: %s ',
133+
'Changing array type & format via updateData()',
134134
$this->arrayTypeForDepths[$this->depth],
135135
$this->arrayFormatForDepths[$this->depth]
136136
));
@@ -333,12 +333,7 @@ private function addNewKeyToYaml($key, $value)
333333
// because we're inside a multi-line array, put this item
334334
// onto the *next* line & indent it
335335

336-
// But, if the *value* is an array, then ITS children will
337-
// also need to be indented artificially by the same amount
338-
$newYamlValue = str_replace("\n", "\n".$this->getCurrentIndentation(), $newYamlValue);
339-
340-
// now add the new line & indentation to the top-level
341-
$newYamlValue = "\n".$this->getCurrentIndentation().$newYamlValue;
336+
$newYamlValue = "\n".$this->indentMultilineYamlArray($newYamlValue);
342337
} else {
343338
if ($firstItemInArray) {
344339
// avoid the starting "," if first item in array
@@ -454,13 +449,23 @@ private function changeValueInYaml($value)
454449

455450
$endValuePosition = $this->findEndPositionOfValue($originalVal);
456451

457-
// empty space between key & value
458-
$newDataString = ' '.$this->convertToYaml($value);
452+
$newYamlValue = $this->convertToYaml($value);
453+
if (!is_array($originalVal) && is_array($value)) {
454+
// we're converting from a scalar to a (multiline) array
455+
// this means we need to break onto the next line
456+
457+
// increase the indentation
458+
$this->manuallyIncrementIndentation();
459+
$newYamlValue = "\n".$this->indentMultilineYamlArray($newYamlValue);
460+
} else {
461+
// empty space between key & value
462+
$newYamlValue = ' '.$newYamlValue;
463+
}
459464
$newContents = substr($this->contents, 0, $this->currentPosition)
460-
.$newDataString
465+
.$newYamlValue
461466
.substr($this->contents, $endValuePosition);
462467

463-
$newPosition = $this->currentPosition + \strlen($newDataString);
468+
$newPosition = $this->currentPosition + \strlen($newYamlValue);
464469

465470
$newData = $this->currentData;
466471
$newData = $this->setValueAtCurrentPath($value, $newData);
@@ -783,6 +788,19 @@ private function advanceCurrentPosition(int $newPosition)
783788
return;
784789
}
785790

791+
/*
792+
* A bit of a workaround. At times, this function will be called when the
793+
* position is at the beginning of the line: so, one character *after*
794+
* a line break. In that case, if there are a group of spaces at the
795+
* beginning of this first line, they *should* be used to calculate the new
796+
* indentation. To force this, if we detect this situation, we move one
797+
* character backwards, so that the first line is considered a valid line
798+
* to look for indentation.
799+
*/
800+
if ($this->isCharLineBreak(substr($this->contents, $originalPosition - 1, 1))) {
801+
$originalPosition--;
802+
}
803+
786804
// look for empty lines and track the current indentation
787805
$advancedContent = substr($this->contents, $originalPosition, $newPosition - $originalPosition);
788806
$previousIndentation = $this->indentationForDepths[$this->depth];
@@ -801,14 +819,7 @@ private function advanceCurrentPosition(int $newPosition)
801819
}
802820
}
803821

804-
/*
805-
if ($newIndentation === $previousIndentation) {
806-
$this->log(sprintf('Indentation unchanged: %d', $newIndentation));
807-
} else {
808-
$this->log(sprintf('Indentation changed to: %d', $newIndentation));
809-
}
810-
*/
811-
822+
$this->log(sprintf('Calculating new indentation: changing from %d to %d', $this->indentationForDepths[$this->depth], $newIndentation), true);
812823
$this->indentationForDepths[$this->depth] = $newIndentation;
813824
}
814825

@@ -837,12 +848,15 @@ private function log(string $message, $includeContent = false)
837848
'key' => isset($this->currentPath[$this->depth]) ? $this->currentPath[$this->depth] : 'n/a',
838849
'depth' => $this->depth,
839850
'position' => $this->currentPosition,
851+
'indentation' => $this->indentationForDepths[$this->depth],
852+
'type' => $this->arrayTypeForDepths[$this->depth],
853+
'format' => $this->arrayFormatForDepths[$this->depth],
840854
];
841855

842856
if ($includeContent) {
843857
$context['content'] = sprintf(
844-
'%s...',
845-
str_replace(["\r\n", "\n"], ['\r\n', '\n'], substr($this->contents, $this->currentPosition, 20))
858+
'>%s<',
859+
str_replace(["\r\n", "\n"], ['\r\n', '\n'], substr($this->contents, $this->currentPosition, 50))
846860
);
847861
}
848862

@@ -872,7 +886,11 @@ private function guessNextArrayTypeAndAdvance(): string
872886

873887
// get the next char & advance immediately
874888
$nextCharacter = substr($this->contents, $this->currentPosition, 1);
875-
$this->advanceCurrentPosition($this->currentPosition + 1);
889+
// advance, but without advanceCurrentPosition()
890+
// because we are either moving along one line until [ {
891+
// or we are finding a line break and stopping: indentation
892+
// should not be calculated
893+
$this->currentPosition++;
876894

877895
if ($this->isCharLineBreak($nextCharacter)) {
878896
return self::ARRAY_FORMAT_MULTILINE;
@@ -1112,4 +1130,21 @@ private function isCharLineBreak(string $char): bool
11121130
{
11131131
return "\n" === $char || "\r" === $char;
11141132
}
1133+
1134+
/**
1135+
* Takes an unindented multi-line YAML string and indents it so
1136+
* it can be inserted into the current position.
1137+
*
1138+
* Usually an empty line needs to be prepended to this result before
1139+
* adding to the content.
1140+
*/
1141+
private function indentMultilineYamlArray(string $yaml): string
1142+
{
1143+
// But, if the *value* is an array, then ITS children will
1144+
// also need to be indented artificially by the same amount
1145+
$yaml = str_replace("\n", "\n".$this->getCurrentIndentation(), $yaml);
1146+
1147+
// now indent this level
1148+
return $this->getCurrentIndentation().$yaml;
1149+
}
11151150
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
security:
2+
firewalls:
3+
main: ~
4+
other_firewall:
5+
security: false
6+
===
7+
$data['security']['firewalls']['main'] = [
8+
'anonymous' => true,
9+
'guard' => [
10+
'authenticators' => [
11+
'some_key' => true,
12+
'great_colors' => ['green', 'pink', 'orange'],
13+
],
14+
],
15+
];
16+
===
17+
security:
18+
firewalls:
19+
main:
20+
anonymous: true
21+
guard:
22+
authenticators:
23+
some_key: true
24+
great_colors:
25+
- green
26+
- pink
27+
- orange
28+
other_firewall:
29+
security: false
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
security:
2+
firewalls:
3+
main: ~
4+
===
5+
$data['security']['firewalls']['main'] = ['anonymous' => true];
6+
===
7+
security:
8+
firewalls:
9+
main:
10+
anonymous: true
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
security:
2+
firewalls:
3+
main:
4+
anonymous: true
5+
guard:
6+
authenticators:
7+
- App\Security\Test
8+
===
9+
$data['security']['firewalls']['main']['guard']['authenticators'][] = 'App\Security\Test2';
10+
===
11+
security:
12+
firewalls:
13+
main:
14+
anonymous: true
15+
guard:
16+
authenticators:
17+
- App\Security\Test
18+
- App\Security\Test2

0 commit comments

Comments
 (0)