Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.6] View Cleaning #17018

Merged
merged 6 commits into from
Dec 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/Illuminate/View/Compilers/Concerns/CompilesLayouts.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

trait CompilesLayouts
{
/**
* The name of the last section that was started.
*
* @var string
*/
protected $lastSection;

/**
* Compile the extends statements into valid PHP.
*
Expand All @@ -31,6 +38,8 @@ protected function compileExtends($expression)
*/
protected function compileSection($expression)
{
$this->lastSection = trim($expression, "()'");

return "<?php \$__env->startSection{$expression}; ?>";
}

Expand All @@ -41,7 +50,7 @@ protected function compileSection($expression)
*/
protected function compileParent()
{
return ViewFactory::parentPlaceholder();
return ViewFactory::parentPlaceholder($this->lastSection ?: '');
}

/**
Expand Down
8 changes: 4 additions & 4 deletions src/Illuminate/View/Compilers/Concerns/CompilesLoops.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected function compileForelse($expression)

$initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);";

$iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getFirstLoop();';
$iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();';

return "<?php {$empty} = true; {$initLoop} foreach(\$__currentLoopData as {$iteration}): {$iterateLoop} {$empty} = false; ?>";
}
Expand All @@ -37,7 +37,7 @@ protected function compileEmpty($expression)
{
$empty = '$__empty_'.$this->forElseCounter--;

return "<?php endforeach; \$__env->popLoop(); \$loop = \$__env->getFirstLoop(); if ({$empty}): ?>";
return "<?php endforeach; \$__env->popLoop(); \$loop = \$__env->getLastLoop(); if ({$empty}): ?>";
}

/**
Expand Down Expand Up @@ -78,7 +78,7 @@ protected function compileForeach($expression)

$initLoop = "\$__currentLoopData = {$iteratee}; \$__env->addLoop(\$__currentLoopData);";

$iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getFirstLoop();';
$iterateLoop = '$__env->incrementLoopIndices(); $loop = $__env->getLastLoop();';

return "<?php {$initLoop} foreach(\$__currentLoopData as {$iteration}): {$iterateLoop} ?>";
}
Expand Down Expand Up @@ -124,7 +124,7 @@ protected function compileEndfor($expression)
*/
protected function compileEndforeach($expression)
{
return '<?php endforeach; $__env->popLoop(); $loop = $__env->getFirstLoop(); ?>';
return '<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>';
}

/**
Expand Down
123 changes: 123 additions & 0 deletions src/Illuminate/View/Concerns/ManagesComponents.php
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]);
}
}
200 changes: 200 additions & 0 deletions src/Illuminate/View/Concerns/ManagesEvents.php
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]);
}
}
Loading