diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 82e29d252f22..ee387786b8f9 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -902,6 +902,50 @@ protected function compileIncludeIf($expression) return "exists($expression)) echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; } + /** + * Compile the component statements into valid PHP. + * + * @param string $expression + * @return string + */ + protected function compileComponent($expression) + { + return "startComponent{$expression}; ?>"; + } + + /** + * Compile the end component statements into valid PHP. + * + * @param string $expression + * @return string + */ + protected function compileEndComponent($expression) + { + return "renderComponent(); ?>"; + } + + /** + * Compile the slot statements into valid PHP. + * + * @param string $expression + * @return string + */ + protected function compileSlot($expression) + { + return "slot{$expression}; ?>"; + } + + /** + * Compile the end slot statements into valid PHP. + * + * @param string $expression + * @return string + */ + protected function compileEndSlot($expression) + { + return "endSlot(); ?>"; + } + /** * Compile the stack statements into the content. * diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php index 207d0ce6c05f..89ceb54a10fd 100755 --- a/src/Illuminate/View/Factory.php +++ b/src/Illuminate/View/Factory.php @@ -7,6 +7,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; +use Illuminate\Support\HtmlString; use Illuminate\Contracts\Support\Arrayable; use Illuminate\View\Engines\EngineResolver; use Illuminate\Contracts\Events\Dispatcher; @@ -93,6 +94,34 @@ class Factory implements FactoryContract */ protected $sectionStack = []; + /** + * The components being rendered. + * + * @var array + */ + protected $componentStack = []; + + /** + * The original data passed to the component. + * + * @var array + */ + protected $componentData = []; + + /** + * The slot contents for the component. + * + * @var array + */ + protected $slots = []; + + /** + * The names of the slots being rendered. + * + * @var array + */ + protected $slotStack = []; + /** * The stack of in-progress loops. * @@ -680,6 +709,75 @@ public static function parentPlaceholder() return static::$parentPlaceholder; } + /** + * Start a component rendering process. + * + * @param string $name + * @param array $data + * @return void + */ + public function startComponent($name, array $data = []) + { + if (ob_start()) { + $this->componentStack[] = $name; + + $this->componentData[$name] = $data; + + $this->slots[$name] = []; + } + } + + /** + * Render the current component. + * + * @return string + */ + public function renderComponent() + { + $contents = ob_get_clean(); + + $name = array_pop($this->componentStack); + + $baseData = $this->componentData[$name]; + + $data = array_merge( + $baseData, ['slot' => new HtmlString($contents)], $this->slots[$name] + ); + + return tap($this->make($name, $data)->render(), function () use ($name) { + unset($this->slots[$name]); + unset($this->slotStack[$name]); + unset($this->componentData[$name]); + }); + } + + /** + * Start the slot rendering process. + * + * @param string $name + * @return void + */ + public function slot($name) + { + if (ob_start()) { + $this->slots[last($this->componentStack)][$name] = ''; + + $this->slotStack[last($this->componentStack)][] = $name; + } + } + + /** + * Save the slot content for rendering. + * + * @return void + */ + public function endSlot() + { + $current = last($this->componentStack); + + $this->slots[$current][array_pop($this->slotStack[$current])] = new HtmlString(ob_get_clean()); + } + /** * Start injecting content into a push section. * @@ -729,6 +827,7 @@ protected function extendPush($section, $content) if (! isset($this->pushes[$section])) { $this->pushes[$section] = []; } + if (! isset($this->pushes[$section][$this->renderCount])) { $this->pushes[$section][$this->renderCount] = $content; } else {