Skip to content
Closed

Consume #39102

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
19 changes: 18 additions & 1 deletion src/Illuminate/View/Compilers/Concerns/CompilesComponents.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@ public static function compileClassComponentOpening(string $component, string $a
{
return implode("\n", [
'<?php if (isset($component)) { $__componentOriginal'.$hash.' = $component; } ?>',
'<?php if (isset($__componentData)) { $__env->withComponentConsumableData($__componentData); } ?>',
'<?php $component = $__env->getContainer()->make('.Str::finish($component, '::class').', '.($data ?: '[]').'); ?>',
'<?php $component->withName('.$alias.'); ?>',
'<?php if ($component->shouldRender()): ?>',
'<?php $__env->startComponent($component->resolveView(), $component->data()); ?>',
'<?php $__env->startComponent($component->resolveView(), $__componentData = $component->data()); ?>',
]);
}

Expand Down Expand Up @@ -161,6 +162,22 @@ protected function compileProps($expression)
<?php unset(\$__defined_vars); ?>";
}

/**
* Compile the consume statement into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileConsume($expression)
{
return "<?php foreach ({$expression} as \$__key => \$__value) {
\$__consumeVariable = is_string(\$__key) ? \$__key : \$__value;
if (! array_key_exists(\$__consumeVariable, get_defined_vars())) {
\$\$__consumeVariable = is_string(\$__key) ? \$__env->getConsumableComponentData(\$__key, \$__value) : \$__env->getConsumableComponentData(\$__value);
}
} ?>";
}

/**
* Sanitize the given component attribute value.
*
Expand Down
31 changes: 31 additions & 0 deletions src/Illuminate/View/Concerns/ManagesComponents.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ trait ManagesComponents
*/
protected $componentData = [];

/**
* The currently consumable component data.
*
* @var array
*/
protected $consumableData = [];

/**
* The slot contents for the component.
*
Expand Down Expand Up @@ -115,6 +122,29 @@ protected function componentData()
);
}

/**
* Get an item from the component data that exists above the current component.
*
* @param string|null $key
* @param mixed $default
* @return mixed|null
*/
public function getConsumableComponentData($key = null, $default = null)
{
return Arr::get($this->consumableData, $key, $default);
}

/**
* Merge additional component consumable data into the current consumable data array.
*
* @param array $data
* @return void
*/
public function withComponentConsumableData(array $data)
{
$this->consumableData = array_merge($this->consumableData, $data);
}

/**
* Start the slot rendering process.
*
Expand Down Expand Up @@ -173,5 +203,6 @@ protected function flushComponents()
{
$this->componentStack = [];
$this->componentData = [];
$this->consumableData = [];
}
}
12 changes: 12 additions & 0 deletions tests/Integration/View/BladeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@ public function tested_nested_anonymous_attribute_proxying_works_correctly()
$this->assertSame('<input class="disabled-class" foo="bar" type="text" disabled />', trim($view));
}

public function test_consumable_data()
{
$view = View::make('consume')->render();

$this->assertSame('<h1>Menu</h1>
<div>Slot: 1, Color: blue, Default: foo</div>
<div>Slot: 2, Color: blue, Default: foo</div>
<div>Slot: 3, Color: purple, Default: foo</div>
<div>Slot: 4, Color: blue, Default: foo</div>
<div>Slot: 5, Color: orange, Default: foo</div>', trim($view));
}

protected function getEnvironmentSetUp($app)
{
$app['config']->set('view.paths', [__DIR__.'/templates']);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@consume(['color', 'default' => 'foo'])
<div>Slot: {{ $slot }}, Color: {{ $color }}, Default: {{ $default }}</div>
4 changes: 4 additions & 0 deletions tests/Integration/View/templates/components/menu.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<h1>Menu</h1>
{{ $slot }}
<x-menu-item>4</x-menu-item>
<x-menu-item color="orange">5</x-menu-item>
5 changes: 5 additions & 0 deletions tests/Integration/View/templates/consume.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<x-menu color="blue">
<x-menu-item>1</x-menu-item>
<x-menu-item>2</x-menu-item>
<x-menu-item color="purple">3</x-menu-item>
</x-menu>
3 changes: 2 additions & 1 deletion tests/View/Blade/BladeComponentsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ public function testComponentsAreCompiled()
public function testClassComponentsAreCompiled()
{
$this->assertSame('<?php if (isset($component)) { $__componentOriginal35bda42cbf6f9717b161c4f893644ac7a48b0d98 = $component; } ?>
<?php if (isset($__componentData)) { $__env->withComponentConsumableData($__componentData); } ?>
<?php $component = $__env->getContainer()->make(Test::class, ["foo" => "bar"]); ?>
<?php $component->withName(\'test\'); ?>
<?php if ($component->shouldRender()): ?>
<?php $__env->startComponent($component->resolveView(), $component->data()); ?>', $this->compiler->compileString('@component(\'Test::class\', \'test\', ["foo" => "bar"])'));
<?php $__env->startComponent($component->resolveView(), $__componentData = $component->data()); ?>', $this->compiler->compileString('@component(\'Test::class\', \'test\', ["foo" => "bar"])'));
}

public function testEndComponentsAreCompiled()
Expand Down