|
7 | 7 | use Illuminate\Support\Arr; |
8 | 8 | use Illuminate\Support\Str; |
9 | 9 | use InvalidArgumentException; |
| 10 | +use Illuminate\Support\HtmlString; |
10 | 11 | use Illuminate\Contracts\Support\Arrayable; |
11 | 12 | use Illuminate\View\Engines\EngineResolver; |
12 | 13 | use Illuminate\Contracts\Events\Dispatcher; |
@@ -93,6 +94,34 @@ class Factory implements FactoryContract |
93 | 94 | */ |
94 | 95 | protected $sectionStack = []; |
95 | 96 |
|
| 97 | + /** |
| 98 | + * The components being rendered. |
| 99 | + * |
| 100 | + * @var array |
| 101 | + */ |
| 102 | + protected $componentStack = []; |
| 103 | + |
| 104 | + /** |
| 105 | + * The original data passed to the component. |
| 106 | + * |
| 107 | + * @var array |
| 108 | + */ |
| 109 | + protected $componentData = []; |
| 110 | + |
| 111 | + /** |
| 112 | + * The slot contents for the component. |
| 113 | + * |
| 114 | + * @var array |
| 115 | + */ |
| 116 | + protected $slots = []; |
| 117 | + |
| 118 | + /** |
| 119 | + * The names of the slots being rendered. |
| 120 | + * |
| 121 | + * @var array |
| 122 | + */ |
| 123 | + protected $slotStack = []; |
| 124 | + |
96 | 125 | /** |
97 | 126 | * The stack of in-progress loops. |
98 | 127 | * |
@@ -680,6 +709,75 @@ public static function parentPlaceholder() |
680 | 709 | return static::$parentPlaceholder; |
681 | 710 | } |
682 | 711 |
|
| 712 | + /** |
| 713 | + * Start a component rendering process. |
| 714 | + * |
| 715 | + * @param string $name |
| 716 | + * @param array $data |
| 717 | + * @return void |
| 718 | + */ |
| 719 | + public function startComponent($name, array $data = []) |
| 720 | + { |
| 721 | + if (ob_start()) { |
| 722 | + $this->componentStack[] = $name; |
| 723 | + |
| 724 | + $this->componentData[$name] = $data; |
| 725 | + |
| 726 | + $this->slots[$name] = []; |
| 727 | + } |
| 728 | + } |
| 729 | + |
| 730 | + /** |
| 731 | + * Render the current component. |
| 732 | + * |
| 733 | + * @return string |
| 734 | + */ |
| 735 | + public function renderComponent() |
| 736 | + { |
| 737 | + $contents = ob_get_clean(); |
| 738 | + |
| 739 | + $name = array_pop($this->componentStack); |
| 740 | + |
| 741 | + $baseData = $this->componentData[$name]; |
| 742 | + |
| 743 | + $data = array_merge( |
| 744 | + $baseData, ['slot' => new HtmlString($contents)], $this->slots[$name] |
| 745 | + ); |
| 746 | + |
| 747 | + return tap($this->make($name, $data)->render(), function () use ($name) { |
| 748 | + unset($this->slots[$name]); |
| 749 | + unset($this->slotStack[$name]); |
| 750 | + unset($this->componentData[$name]); |
| 751 | + }); |
| 752 | + } |
| 753 | + |
| 754 | + /** |
| 755 | + * Start the slot rendering process. |
| 756 | + * |
| 757 | + * @param string $name |
| 758 | + * @return void |
| 759 | + */ |
| 760 | + public function slot($name) |
| 761 | + { |
| 762 | + if (ob_start()) { |
| 763 | + $this->slots[last($this->componentStack)][$name] = ''; |
| 764 | + |
| 765 | + $this->slotStack[last($this->componentStack)][] = $name; |
| 766 | + } |
| 767 | + } |
| 768 | + |
| 769 | + /** |
| 770 | + * Save the slot content for rendering. |
| 771 | + * |
| 772 | + * @return void |
| 773 | + */ |
| 774 | + public function endSlot() |
| 775 | + { |
| 776 | + $current = last($this->componentStack); |
| 777 | + |
| 778 | + $this->slots[$current][array_pop($this->slotStack[$current])] = new HtmlString(ob_get_clean()); |
| 779 | + } |
| 780 | + |
683 | 781 | /** |
684 | 782 | * Start injecting content into a push section. |
685 | 783 | * |
@@ -729,6 +827,7 @@ protected function extendPush($section, $content) |
729 | 827 | if (! isset($this->pushes[$section])) { |
730 | 828 | $this->pushes[$section] = []; |
731 | 829 | } |
| 830 | + |
732 | 831 | if (! isset($this->pushes[$section][$this->renderCount])) { |
733 | 832 | $this->pushes[$section][$this->renderCount] = $content; |
734 | 833 | } else { |
|
0 commit comments