Skip to content

Commit d86c32e

Browse files
authored
Thread blade compiler instance through pipeline (#95)
* Refactor Utils calls * Remove parseAttributesArrayToRuntimeArrayString * Add DirectiveCompiler * Delete parseAttributeStringToArray usage * Remove Utils:: parseAttributeStringToArray * Fix imports * Move attribute preprocessing to Parser * Update ComponentSource to accept path * Add failing test * Refactor BladeService to an instance * Add tests * Extract isolated rendering from BladeService * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor * Refactor tests * Fix DirectiveCompiler * Test CI * Test CI * Test CI * Test CI * Test CI * Fix merge conflicts
1 parent 083a3e7 commit d86c32e

32 files changed

+669
-530
lines changed

src/BladeRenderer.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
namespace Livewire\Blaze;
4+
5+
use Illuminate\Contracts\View\Factory;
6+
use Illuminate\Support\Facades\File;
7+
use Illuminate\View\Compilers\BladeCompiler;
8+
use Livewire\Blaze\Runtime\BlazeRuntime;
9+
use ReflectionClass;
10+
11+
/**
12+
* Handles isolated Blade rendering used during compile-time folding.
13+
*/
14+
class BladeRenderer
15+
{
16+
public function __construct(
17+
protected BladeCompiler $blade,
18+
protected Factory $factory,
19+
protected BlazeRuntime $runtime,
20+
protected BlazeManager $manager,
21+
) {}
22+
23+
/**
24+
* Get the temporary cache directory path used during isolated rendering.
25+
*/
26+
public function getTemporaryCachePath(): string
27+
{
28+
return config('view.compiled').'/blaze';
29+
}
30+
31+
/**
32+
* Render a Blade template string in isolation by freezing and restoring compiler state.
33+
*/
34+
public function render(string $template): string
35+
{
36+
$temporaryCachePath = $this->getTemporaryCachePath();
37+
38+
File::ensureDirectoryExists($temporaryCachePath);
39+
40+
$restoreFactory = $this->freezeObjectProperties($this->factory, [
41+
'renderCount' => 0,
42+
'renderedOnce' => [],
43+
'sections' => [],
44+
'sectionStack' => [],
45+
'pushes' => [],
46+
'prepends' => [],
47+
'pushStack' => [],
48+
'componentStack' => [],
49+
'componentData' => [],
50+
'currentComponentData' => [],
51+
'slots' => [],
52+
'slotStack' => [],
53+
'fragments' => [],
54+
'fragmentStack' => [],
55+
'loopsStack' => [],
56+
'translationReplacements' => [],
57+
]);
58+
59+
$restoreCompiler = $this->freezeObjectProperties($this->blade, [
60+
'cachePath' => $temporaryCachePath,
61+
'rawBlocks' => [],
62+
'footer' => [],
63+
'prepareStringsForCompilationUsing' => [
64+
function ($input) {
65+
if (Unblaze::hasUnblaze($input)) {
66+
$input = Unblaze::processUnblazeDirectives($input);
67+
};
68+
69+
$input = $this->manager->compileForFolding($input, $this->blade->getPath());
70+
71+
return $input;
72+
},
73+
],
74+
'path' => null,
75+
'forElseCounter' => 0,
76+
'firstCaseInSwitch' => true,
77+
'lastSection' => null,
78+
'lastFragment' => null,
79+
]);
80+
81+
$restoreRuntime = $this->freezeObjectProperties($this->runtime, [
82+
'compiled' => [],
83+
'paths' => [],
84+
'compiledPath' => $temporaryCachePath,
85+
'dataStack' => [],
86+
'slotsStack' => [],
87+
]);
88+
89+
try {
90+
$this->manager->startFolding();
91+
92+
$result = $this->blade->render($template, deleteCachedView: true);
93+
} finally {
94+
$restoreCompiler();
95+
$restoreFactory();
96+
$restoreRuntime();
97+
98+
$this->manager->stopFolding();
99+
}
100+
101+
$result = Unblaze::replaceUnblazePrecompiledDirectives($result);
102+
103+
return $result;
104+
}
105+
106+
/**
107+
* Delete the temporary cache directory created during isolated rendering.
108+
*/
109+
public function deleteTemporaryCacheDirectory(): void
110+
{
111+
File::deleteDirectory($this->getTemporaryCachePath());
112+
}
113+
114+
/**
115+
* Snapshot object properties and return a restore closure to revert them.
116+
*/
117+
protected function freezeObjectProperties(object $object, array $properties)
118+
{
119+
$reflection = new ReflectionClass($object);
120+
121+
$frozen = [];
122+
123+
foreach ($properties as $key => $value) {
124+
$name = is_numeric($key) ? $value : $key;
125+
126+
$property = $reflection->getProperty($name);
127+
128+
$frozen[$name] = $property->getValue($object);
129+
130+
if (! is_numeric($key)) {
131+
$property->setValue($object, $value);
132+
}
133+
}
134+
135+
return function () use ($reflection, $object, $frozen) {
136+
foreach ($frozen as $name => $value) {
137+
$property = $reflection->getProperty($name);
138+
$property->setValue($object, $value);
139+
}
140+
};
141+
}
142+
}

0 commit comments

Comments
 (0)