Skip to content

Commit ddb5fef

Browse files
[8.x] Consume Blade Directive (#39100)
* initial pass at consume directive * rename method * Track render data for consume * Add more variety to tests * formatting * Update tests * Handle flushComponents * rename to aware * formatting * formatting Co-authored-by: Taylor Otwell <[email protected]>
1 parent 8b2cdb1 commit ddb5fef

File tree

6 files changed

+117
-9
lines changed

6 files changed

+117
-9
lines changed

src/Illuminate/View/Compilers/Concerns/CompilesComponents.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,20 @@ protected function compileProps($expression)
161161
<?php unset(\$__defined_vars); ?>";
162162
}
163163

164+
/**
165+
* Compile the aware statement into valid PHP.
166+
*
167+
* @param string $expression
168+
* @return string
169+
*/
170+
protected function compileAware($expression)
171+
{
172+
return "<?php foreach ({$expression} as \$__key => \$__value) {
173+
\$__consumeVariable = is_string(\$__key) ? \$__key : \$__value;
174+
\$\$__consumeVariable = is_string(\$__key) ? \$__env->getConsumableComponentData(\$__key, \$__value) : \$__env->getConsumableComponentData(\$__value);
175+
} ?>";
176+
}
177+
164178
/**
165179
* Sanitize the given component attribute value.
166180
*

src/Illuminate/View/Concerns/ManagesComponents.php

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ trait ManagesComponents
2424
*/
2525
protected $componentData = [];
2626

27+
/**
28+
* The component data for the component that is currently being rendered.
29+
*
30+
* @var array
31+
*/
32+
protected $currentComponentData = [];
33+
2734
/**
2835
* The slot contents for the component.
2936
*
@@ -81,16 +88,23 @@ public function renderComponent()
8188
{
8289
$view = array_pop($this->componentStack);
8390

84-
$data = $this->componentData();
85-
86-
$view = value($view, $data);
91+
$this->currentComponentData = array_merge(
92+
$previousComponentData = $this->currentComponentData,
93+
$data = $this->componentData()
94+
);
8795

88-
if ($view instanceof View) {
89-
return $view->with($data)->render();
90-
} elseif ($view instanceof Htmlable) {
91-
return $view->toHtml();
92-
} else {
93-
return $this->make($view, $data)->render();
96+
try {
97+
$view = value($view, $data);
98+
99+
if ($view instanceof View) {
100+
return $view->with($data)->render();
101+
} elseif ($view instanceof Htmlable) {
102+
return $view->toHtml();
103+
} else {
104+
return $this->make($view, $data)->render();
105+
}
106+
} finally {
107+
$this->currentComponentData = $previousComponentData;
94108
}
95109
}
96110

@@ -115,6 +129,36 @@ protected function componentData()
115129
);
116130
}
117131

132+
/**
133+
* Get an item from the component data that exists above the current component.
134+
*
135+
* @param string $key
136+
* @param mixed $default
137+
* @return mixed|null
138+
*/
139+
public function getConsumableComponentData($key, $default = null)
140+
{
141+
if (array_key_exists($key, $this->currentComponentData)) {
142+
return $this->currentComponentData[$key];
143+
}
144+
145+
$currentComponent = count($this->componentStack);
146+
147+
if ($currentComponent === 0) {
148+
return value($default);
149+
}
150+
151+
for ($i = $currentComponent - 1; $i >= 0; $i--) {
152+
$data = $this->componentData[$i] ?? [];
153+
154+
if (array_key_exists($key, $data)) {
155+
return $data[$key];
156+
}
157+
}
158+
159+
return value($default);
160+
}
161+
118162
/**
119163
* Start the slot rendering process.
120164
*
@@ -173,5 +217,6 @@ protected function flushComponents()
173217
{
174218
$this->componentStack = [];
175219
$this->componentData = [];
220+
$this->currentComponentData = [];
176221
}
177222
}

tests/Integration/View/BladeTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,32 @@ public function tested_nested_anonymous_attribute_proxying_works_correctly()
7676
$this->assertSame('<input class="disabled-class" foo="bar" type="text" disabled />', trim($view));
7777
}
7878

79+
public function test_consume_defaults()
80+
{
81+
$view = View::make('consume')->render();
82+
83+
$this->assertSame('<h1>Menu</h1>
84+
<div>Slot: A, Color: orange, Default: foo</div>
85+
<div>Slot: B, Color: red, Default: foo</div>
86+
<div>Slot: C, Color: blue, Default: foo</div>
87+
<div>Slot: D, Color: red, Default: foo</div>
88+
<div>Slot: E, Color: red, Default: foo</div>
89+
<div>Slot: F, Color: yellow, Default: foo</div>', trim($view));
90+
}
91+
92+
public function test_consume_with_props()
93+
{
94+
$view = View::make('consume', ['color' => 'rebeccapurple'])->render();
95+
96+
$this->assertSame('<h1>Menu</h1>
97+
<div>Slot: A, Color: orange, Default: foo</div>
98+
<div>Slot: B, Color: rebeccapurple, Default: foo</div>
99+
<div>Slot: C, Color: blue, Default: foo</div>
100+
<div>Slot: D, Color: rebeccapurple, Default: foo</div>
101+
<div>Slot: E, Color: rebeccapurple, Default: foo</div>
102+
<div>Slot: F, Color: yellow, Default: foo</div>', trim($view));
103+
}
104+
79105
protected function getEnvironmentSetUp($app)
80106
{
81107
$app['config']->set('view.paths', [__DIR__.'/templates']);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@aware(['color' => 'red', 'default' => 'foo'])
2+
<div>Slot: {{ $slot }}, Color: {{ $color }}, Default: {{ $default }}</div>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<h1>Menu</h1>
2+
<x-menu-item color="orange">A</x-menu-item>
3+
<x-menu-item>B</x-menu-item>
4+
{{ $slot }}
5+
<x-menu-item>E</x-menu-item>
6+
<x-menu-item color="yellow">F</x-menu-item>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@isset($color)
2+
3+
<x-menu :color="$color">
4+
<x-menu-item color="blue">C</x-menu-item>
5+
<x-menu-item>D</x-menu-item>
6+
</x-menu>
7+
8+
@else
9+
10+
<x-menu>
11+
<x-menu-item color="blue">C</x-menu-item>
12+
<x-menu-item>D</x-menu-item>
13+
</x-menu>
14+
15+
@endisset

0 commit comments

Comments
 (0)