|
1 | 1 | <?php |
2 | 2 | /** |
3 | | - * YAML handler (last modified: 2022.02.21). |
| 3 | + * YAML handler (last modified: 2023.03.24). |
4 | 4 | * |
5 | 5 | * This file is a part of the "common classes package", utilised by a number of |
6 | 6 | * packages and projects, including CIDRAM and phpMussel. |
@@ -132,7 +132,7 @@ class YAML |
132 | 132 | * be needed by some implementations to ensure compatibility). |
133 | 133 | * @link https://github.com/Maikuolan/Common/tags |
134 | 134 | */ |
135 | | - public const VERSION = '2.9.0'; |
| 135 | + public const VERSION = '2.9.6'; |
136 | 136 |
|
137 | 137 | /** |
138 | 138 | * Can optionally begin processing data as soon as the object is |
@@ -380,7 +380,7 @@ public function process(string $In, array &$Arr, int $Depth = 0, bool $Refs = fa |
380 | 380 | $Success = true; |
381 | 381 |
|
382 | 382 | /** Needed for processing any remaining data. */ |
383 | | - if ($SendTo && !empty($Key)) { |
| 383 | + if ($SendTo) { |
384 | 384 | if (!$this->MultiLine && !$this->MultiLineFolded) { |
385 | 385 | if (!isset($Arr[$Key]) || !is_array($Arr[$Key])) { |
386 | 386 | $Arr[$Key] = []; |
@@ -448,22 +448,32 @@ public function reconstruct(array $Arr, bool $UseCaptured = false, bool $DoWithA |
448 | 448 | * |
449 | 449 | * @param mixed $Data The data to traverse. |
450 | 450 | * @param string|array $Path The path to traverse. |
| 451 | + * @param bool $AllowNonScalar Whether to allow non-scalar returns. |
451 | 452 | * @return mixed The traversed data, or an empty string on failure. |
452 | 453 | */ |
453 | | - public function dataTraverse(&$Data, $Path = []) |
| 454 | + public function dataTraverse(&$Data, $Path = [], bool $AllowNonScalar = false) |
454 | 455 | { |
455 | 456 | if (!is_array($Path)) { |
456 | 457 | $Path = preg_split('~(?<!\\\)\.~', $Path) ?: []; |
457 | 458 | } |
458 | 459 | $Segment = array_shift($Path); |
459 | 460 | if ($Segment === null || strlen($Segment) === 0) { |
460 | | - return is_scalar($Data) ? $Data : ''; |
| 461 | + return $AllowNonScalar || is_scalar($Data) ? $Data : ''; |
461 | 462 | } |
462 | 463 | $Segment = str_replace('\.', '.', $Segment); |
463 | | - if (is_array($Data)) { |
464 | | - return isset($Data[$Segment]) ? $this->dataTraverse($Data[$Segment], $Path) : ''; |
| 464 | + if (is_array($Data) && isset($Data[$Segment])) { |
| 465 | + return $this->dataTraverse($Data[$Segment], $Path, $AllowNonScalar); |
465 | 466 | } |
466 | | - return $this->dataTraverse($Data, $Path); |
| 467 | + if (is_object($Data) && property_exists($Data, $Segment)) { |
| 468 | + return $this->dataTraverse($Data->$Segment, $Path, $AllowNonScalar); |
| 469 | + } |
| 470 | + if (is_string($Data)) { |
| 471 | + if (preg_match('~^(?:trim|str(?:tolower|toupper|len))\(\)~i', $Segment)) { |
| 472 | + $Segment = substr($Segment, 0, -2); |
| 473 | + $Data = $Segment($Data); |
| 474 | + } |
| 475 | + } |
| 476 | + return $this->dataTraverse($Data, $Path, $AllowNonScalar); |
467 | 477 | } |
468 | 478 |
|
469 | 479 | /** |
@@ -766,66 +776,67 @@ private function processInner(array $Arr, string &$Out, int $Depth = 0): void |
766 | 776 | if ($Depth === $this->FlowRebuildDepth) { |
767 | 777 | $Out .= "\n"; |
768 | 778 | } |
769 | | - } else { |
770 | | - foreach ($Arr as $Key => $Value) { |
771 | | - if ($Key === '---' && $Value === null) { |
772 | | - $Out .= "---\n"; |
773 | | - continue; |
774 | | - } |
775 | | - if ($Key === '...' && $Value === null) { |
776 | | - $Out .= "...\n"; |
777 | | - continue; |
778 | | - } |
779 | | - $ThisDepth = str_repeat($this->Indent, $Depth); |
780 | | - if ($NullSet && !$Sequential) { |
781 | | - $Out .= $ThisDepth . '?'; |
782 | | - $Value = $Key; |
783 | | - } else { |
784 | | - $Out .= $ThisDepth . ($Sequential ? '-' : ($this->QuoteKeys ? $this->scalarToString($Key) : $Key) . ':'); |
785 | | - } |
786 | | - if (is_array($Value)) { |
787 | | - if ($Depth < $this->FlowRebuildDepth - 1) { |
788 | | - $Out .= "\n"; |
789 | | - } |
790 | | - $this->processInner($Value, $Out, $Depth + 1); |
791 | | - continue; |
| 779 | + return; |
| 780 | + } |
| 781 | + foreach ($Arr as $Key => $Value) { |
| 782 | + if ($Key === '---' && $Value === null) { |
| 783 | + $Out .= "---\n"; |
| 784 | + continue; |
| 785 | + } |
| 786 | + if ($Key === '...' && $Value === null) { |
| 787 | + $Out .= "...\n"; |
| 788 | + continue; |
| 789 | + } |
| 790 | + $ThisDepth = str_repeat($this->Indent, $Depth); |
| 791 | + if ($NullSet && !$Sequential) { |
| 792 | + $Out .= $ThisDepth . '?'; |
| 793 | + $Value = $Key; |
| 794 | + } else { |
| 795 | + $Out .= $ThisDepth . ($Sequential ? '-' : ($this->QuoteKeys ? $this->scalarToString($Key) : $Key) . ':'); |
| 796 | + } |
| 797 | + if (is_array($Value)) { |
| 798 | + if ($Depth < $this->FlowRebuildDepth - 1) { |
| 799 | + $Out .= "\n"; |
792 | 800 | } |
793 | | - $Out .= ' '; |
794 | | - if (is_string($Value)) { |
795 | | - if (strpos($Value, "\n") !== false) { |
796 | | - if (preg_match('~\n{2,}$~m', $Value)) { |
797 | | - $ToAdd = "|+\n" . $ThisDepth . $this->Indent; |
798 | | - } else { |
799 | | - $ToAdd = "|\n" . $ThisDepth . $this->Indent; |
800 | | - } |
801 | | - $ToAdd .= preg_replace('~\n(?=[^\n])~m', "\n" . $ThisDepth . $this->Indent, $Value); |
802 | | - } elseif ($this->FoldedAt > 0 && strpos($Value, ' ') !== false && strlen($Value) >= $this->FoldedAt) { |
803 | | - $ToAdd = ">\n" . $ThisDepth . $this->Indent . wordwrap( |
804 | | - $Value, |
805 | | - $this->FoldedAt, |
806 | | - "\n" . $ThisDepth . $this->Indent |
807 | | - ); |
| 801 | + $this->processInner($Value, $Out, $Depth + 1); |
| 802 | + continue; |
| 803 | + } |
| 804 | + $Out .= ' '; |
| 805 | + if (is_string($Value)) { |
| 806 | + $HasHash = strpos($Value, '#') !== false; |
| 807 | + if (!$HasHash && strpos($Value, "\n") !== false) { |
| 808 | + if (preg_match('~\n{2,}$~m', $Value)) { |
| 809 | + $ToAdd = "|+\n" . $ThisDepth . $this->Indent; |
808 | 810 | } else { |
809 | | - $ToAdd = $this->Quotes . $this->escape($Value) . $this->Quotes; |
| 811 | + $ToAdd = "|\n" . $ThisDepth . $this->Indent; |
810 | 812 | } |
| 813 | + $ToAdd .= preg_replace('~\n(?=[^\n])~m', "\n" . $ThisDepth . $this->Indent, $Value); |
| 814 | + } elseif (!$HasHash && $this->FoldedAt > 0 && strpos($Value, ' ') !== false && strlen($Value) >= $this->FoldedAt) { |
| 815 | + $ToAdd = ">\n" . $ThisDepth . $this->Indent . wordwrap( |
| 816 | + $Value, |
| 817 | + $this->FoldedAt, |
| 818 | + "\n" . $ThisDepth . $this->Indent |
| 819 | + ); |
811 | 820 | } else { |
812 | | - $ToAdd = $this->scalarToString($Value); |
| 821 | + $ToAdd = $this->Quotes . $this->escape($Value) . $this->Quotes; |
813 | 822 | } |
814 | | - if ($this->DoWithAnchors) { |
815 | | - foreach ($this->Anchors as $Name => $Data) { |
816 | | - if ($Data === $ToAdd) { |
817 | | - if (empty($this->AnchorsDone[$Name])) { |
818 | | - $ToAdd = '&' . $Name . ' ' . $ToAdd; |
819 | | - $this->AnchorsDone[$Name] = true; |
820 | | - } else { |
821 | | - $ToAdd = '*' . $Name; |
822 | | - } |
823 | | - break; |
| 823 | + } else { |
| 824 | + $ToAdd = $this->scalarToString($Value); |
| 825 | + } |
| 826 | + if ($this->DoWithAnchors) { |
| 827 | + foreach ($this->Anchors as $Name => $Data) { |
| 828 | + if ($Data === $ToAdd) { |
| 829 | + if (empty($this->AnchorsDone[$Name])) { |
| 830 | + $ToAdd = '&' . $Name . ' ' . $ToAdd; |
| 831 | + $this->AnchorsDone[$Name] = true; |
| 832 | + } else { |
| 833 | + $ToAdd = '*' . $Name; |
824 | 834 | } |
| 835 | + break; |
825 | 836 | } |
826 | 837 | } |
827 | | - $Out .= $ToAdd . "\n"; |
828 | 838 | } |
| 839 | + $Out .= $ToAdd . "\n"; |
829 | 840 | } |
830 | 841 | } |
831 | 842 |
|
@@ -1426,6 +1437,12 @@ private function scalarToString($In): string |
1426 | 1437 | if (is_string($In)) { |
1427 | 1438 | return $this->Quotes . $this->escape($In) . $this->Quotes; |
1428 | 1439 | } |
| 1440 | + if (is_object($In)) { |
| 1441 | + if (method_exists($In, '__toString')) { |
| 1442 | + return $this->Quotes . $this->escape((string)$In) . $this->Quotes; |
| 1443 | + } |
| 1444 | + throw new \Error('Non-stringable object detected while attempting to reconstruct YAML data'); |
| 1445 | + } |
1429 | 1446 | return $In; |
1430 | 1447 | } |
1431 | 1448 | } |
0 commit comments