Skip to content

Instantly share code, notes, and snippets.

@kevyworks
Last active August 29, 2018 18:21
Show Gist options
  • Save kevyworks/8a6575a02c2dd5b2f800f9c64aae350a to your computer and use it in GitHub Desktop.
Save kevyworks/8a6575a02c2dd5b2f800f9c64aae350a to your computer and use it in GitHub Desktop.
A Laravel 5.3 Blade Component
<?php
namespace App\Libraries;
use Illuminate\Support\HtmlString;
use Illuminate\View\Compilers\BladeCompiler;
use Illuminate\View\Factory;
/**
* Class BladeComponentsFactory
*
* This library is for Laravel 5.3 which does not have components. Also, this is a override factory
* from the default laravel 5.3 View Factory a copy of the ManagesComponents. I have some old projects
* that needs some changes and I miss components, so I created this. Yes, just a QUICK FIX,
* traits would be better imho.
*
* Installation `app/Providers/AppServiceProvider.php`
*
* use BladeComponentsFactory as BladeFactory;
* use Illuminate\Support\ServiceProvider;
*
* class AppServiceProvider extends ServiceProvider
* {
* public function register()
* {
* BladeFactory@register();
* }
*
* public function boot()
* {
* BladeFactory@boot();
* }
* }
*
* @package App\Libraries
*/
class BladeComponentsFactory extends Factory
{
/**
* 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 = [];
/**
* Register
*/
public static function register()
{
app()->singleton(
'view',
function ($app) {
$resolver = $app['view.engine.resolver'];
$finder = $app['view.finder'];
$factory = new static($resolver, $finder, $app['events']);
$factory->setContainer($app);
$factory->share('app', $app);
return $factory;
}
);
}
/**
* Boot
*/
public static function boot()
{
$directives = [
'component' => function ($expression) {
return "<?php \$__env->startComponent({$expression}); ?>";
},
'endcomponent' => function () {
return '<?php echo $__env->renderComponent(); ?>';
},
'slot' => function ($expression) {
return "<?php \$__env->slot({$expression}); ?>";
},
'endslot' => function () {
return '<?php $__env->endSlot(); ?>';
},
];
/** @var BladeCompiler $compiler */
$compiler = app('blade.compiler');
foreach ($directives as $name => $closure) {
$compiler->directive($name, $closure);
};
}
/**
* 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[$this->currentComponent()] = $data;
$this->slots[$this->currentComponent()] = [];
}
}
/**
* Get the index for the current component.
*
* @return int
*/
protected function currentComponent()
{
return count($this->componentStack) - 1;
}
/**
* Render the current component.
*
* @return string
*/
public function renderComponent()
{
$name = array_pop($this->componentStack);
return $this->make($name, $this->componentData($name))->render();
}
/**
* Get the data for the given component.
*
* @param string $name
*
* @return array
*/
protected function componentData($name)
{
return array_merge(
$this->componentData[count($this->componentStack)],
['slot' => new HtmlString(trim(ob_get_clean()))],
$this->slots[count($this->componentStack)]
);
}
/**
* Get Component Data
*
* @return array
*/
public function getComponentData()
{
return $this->componentData[count($this->componentStack)];
}
/**
* Start the slot rendering process.
*
* @param string $name
* @param string|null $content
*
* @return void
*/
public function slot($name, $content = null)
{
if (func_num_args() === 2) {
$this->slots[$this->currentComponent()][$name] = $content;
} else {
if (ob_start()) {
$this->slots[$this->currentComponent()][$name] = '';
$this->slotStack[$this->currentComponent()][] = $name;
}
}
}
/**
* Save the slot content for rendering.
*
* @return void
*/
public function endSlot()
{
last($this->componentStack);
$currentSlot = array_pop($this->slotStack[$this->currentComponent()]);
$this->slots[$this->currentComponent()][$currentSlot] = new HtmlString(trim(ob_get_clean()));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment