-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This cleans up the view component and extracts some traits.
- Loading branch information
1 parent
aec1d04
commit 59816bb
Showing
15 changed files
with
1,006 additions
and
946 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
<?php | ||
|
||
namespace Illuminate\View\Concerns; | ||
|
||
use Illuminate\Support\HtmlString; | ||
|
||
trait ManagesComponents | ||
{ | ||
/** | ||
* 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 = []; | ||
|
||
/** | ||
* 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() | ||
{ | ||
$name = array_pop($this->componentStack); | ||
|
||
return tap($this->make($name, $this->componentData($name))->render(), function () use ($name) { | ||
$this->resetComponent($name); | ||
}); | ||
} | ||
|
||
/** | ||
* Get the data for the given component. | ||
* | ||
* @param string $name | ||
* @return array | ||
*/ | ||
protected function componentData($name) | ||
{ | ||
$slot = ['slot' => new HtmlString(trim(ob_get_clean()))]; | ||
|
||
return array_merge($this->componentData[$name], $slot, $this->slots[$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); | ||
|
||
$currentSlot = array_pop($this->slotStack[$current]); | ||
|
||
$this->slots[$current][$currentSlot] = new HtmlString(trim(ob_get_clean())); | ||
} | ||
|
||
/** | ||
* Reset the state for the given component. | ||
* | ||
* @param string $name | ||
* @return void | ||
*/ | ||
protected function resetComponent($name) | ||
{ | ||
unset($this->slots[$name]); | ||
unset($this->slotStack[$name]); | ||
unset($this->componentData[$name]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
<?php | ||
|
||
namespace Illuminate\View\Concerns; | ||
|
||
use Closure; | ||
use Illuminate\Support\Str; | ||
use Illuminate\Contracts\Events\Dispatcher; | ||
use Illuminate\Contracts\Container\Container; | ||
use Illuminate\Contracts\View\View as ViewContract; | ||
|
||
trait ManagesEvents | ||
{ | ||
/** | ||
* Register a view creator event. | ||
* | ||
* @param array|string $views | ||
* @param \Closure|string $callback | ||
* @return array | ||
*/ | ||
public function creator($views, $callback) | ||
{ | ||
$creators = []; | ||
|
||
foreach ((array) $views as $view) { | ||
$creators[] = $this->addViewEvent($view, $callback, 'creating: '); | ||
} | ||
|
||
return $creators; | ||
} | ||
|
||
/** | ||
* Register multiple view composers via an array. | ||
* | ||
* @param array $composers | ||
* @return array | ||
*/ | ||
public function composers(array $composers) | ||
{ | ||
$registered = []; | ||
|
||
foreach ($composers as $callback => $views) { | ||
$registered = array_merge($registered, $this->composer($views, $callback)); | ||
} | ||
|
||
return $registered; | ||
} | ||
|
||
/** | ||
* Register a view composer event. | ||
* | ||
* @param array|string $views | ||
* @param \Closure|string $callback | ||
* @param int|null $priority | ||
* @return array | ||
*/ | ||
public function composer($views, $callback, $priority = null) | ||
{ | ||
$composers = []; | ||
|
||
foreach ((array) $views as $view) { | ||
$composers[] = $this->addViewEvent($view, $callback, 'composing: ', $priority); | ||
} | ||
|
||
return $composers; | ||
} | ||
|
||
/** | ||
* Add an event for a given view. | ||
* | ||
* @param string $view | ||
* @param \Closure|string $callback | ||
* @param string $prefix | ||
* @param int|null $priority | ||
* @return \Closure|null | ||
*/ | ||
protected function addViewEvent($view, $callback, $prefix = 'composing: ', $priority = null) | ||
{ | ||
$view = $this->normalizeName($view); | ||
|
||
if ($callback instanceof Closure) { | ||
$this->addEventListener($prefix.$view, $callback, $priority); | ||
|
||
return $callback; | ||
} elseif (is_string($callback)) { | ||
return $this->addClassEvent($view, $callback, $prefix, $priority); | ||
} | ||
} | ||
|
||
/** | ||
* Register a class based view composer. | ||
* | ||
* @param string $view | ||
* @param string $class | ||
* @param string $prefix | ||
* @param int|null $priority | ||
* @return \Closure | ||
*/ | ||
protected function addClassEvent($view, $class, $prefix, $priority = null) | ||
{ | ||
$name = $prefix.$view; | ||
|
||
// When registering a class based view "composer", we will simply resolve the | ||
// classes from the application IoC container then call the compose method | ||
// on the instance. This allows for convenient, testable view composers. | ||
$callback = $this->buildClassEventCallback( | ||
$class, $prefix | ||
); | ||
|
||
$this->addEventListener($name, $callback, $priority); | ||
|
||
return $callback; | ||
} | ||
|
||
/** | ||
* Build a class based container callback Closure. | ||
* | ||
* @param string $class | ||
* @param string $prefix | ||
* @return \Closure | ||
*/ | ||
protected function buildClassEventCallback($class, $prefix) | ||
{ | ||
list($class, $method) = $this->parseClassEvent($class, $prefix); | ||
|
||
// Once we have the class and method name, we can build the Closure to resolve | ||
// the instance out of the IoC container and call the method on it with the | ||
// given arguments that are passed to the Closure as the composer's data. | ||
return function () use ($class, $method) { | ||
return call_user_func_array( | ||
[$this->container->make($class), $method], func_get_args() | ||
); | ||
}; | ||
} | ||
|
||
/** | ||
* Parse a class based composer name. | ||
* | ||
* @param string $class | ||
* @param string $prefix | ||
* @return array | ||
*/ | ||
protected function parseClassEvent($class, $prefix) | ||
{ | ||
if (! Str::contains($class, '@')) { | ||
return [$class, $this->classEventMethodForPrefix($prefix)]; | ||
} | ||
|
||
return explode('@', $class); | ||
} | ||
|
||
/** | ||
* Determine the class event method based on the given prefix. | ||
* | ||
* @param string $prefix | ||
* @return string | ||
*/ | ||
protected function classEventMethodForPrefix($prefix) | ||
{ | ||
return Str::contains($prefix, 'composing') ? 'compose' : 'create'; | ||
} | ||
|
||
/** | ||
* Add a listener to the event dispatcher. | ||
* | ||
* @param string $name | ||
* @param \Closure $callback | ||
* @param int|null $priority | ||
* @return void | ||
*/ | ||
protected function addEventListener($name, $callback, $priority = null) | ||
{ | ||
if (is_null($priority)) { | ||
$this->events->listen($name, $callback); | ||
} else { | ||
$this->events->listen($name, $callback, $priority); | ||
} | ||
} | ||
|
||
/** | ||
* Call the composer for a given view. | ||
* | ||
* @param \Illuminate\Contracts\View\View $view | ||
* @return void | ||
*/ | ||
public function callComposer(ViewContract $view) | ||
{ | ||
$this->events->fire('composing: '.$view->name(), [$view]); | ||
} | ||
|
||
/** | ||
* Call the creator for a given view. | ||
* | ||
* @param \Illuminate\Contracts\View\View $view | ||
* @return void | ||
*/ | ||
public function callCreator(ViewContract $view) | ||
{ | ||
$this->events->fire('creating: '.$view->name(), [$view]); | ||
} | ||
} |
Oops, something went wrong.