Skip to content

Commit e8c993f

Browse files
committed
Add in-memory blade views caching support
1 parent 5721e8a commit e8c993f

File tree

4 files changed

+51
-28
lines changed

4 files changed

+51
-28
lines changed

src/Illuminate/View/Compilers/BladeCompiler.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ public function compile($path = null)
181181
}
182182

183183
if (! is_null($this->cachePath)) {
184-
$contents = $this->compileString($this->files->get($this->getPath()));
184+
$contents = $this->wrapInCallback(
185+
$this->compileString($this->files->get($this->getPath()))
186+
);
185187

186188
if (! empty($this->getPath())) {
187189
$contents = $this->appendFilePath($contents);
@@ -195,6 +197,23 @@ public function compile($path = null)
195197
}
196198
}
197199

200+
/**
201+
* Wrap the compiled string by a function.
202+
*
203+
* @param string $contents
204+
* @return string
205+
*/
206+
protected function wrapInCallback($contents)
207+
{
208+
$tokens = $this->getOpenAndClosingPhpTokens($contents);
209+
210+
if ($tokens->isNotEmpty() && $tokens->last() !== T_CLOSE_TAG) {
211+
$contents .= ' ?>';
212+
}
213+
214+
return "<?php return function (\$__laravel_data) { extract(\$__laravel_data, EXTR_SKIP); ?>$contents<?php } ?>";
215+
}
216+
198217
/**
199218
* Append the file path to the compiled string.
200219
*

src/Illuminate/View/Engines/PhpEngine.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,11 @@ protected function evaluatePath($path, $data)
5555
// flush out any stray output that might get out before an error occurs or
5656
// an exception is thrown. This prevents any partial views from leaking.
5757
try {
58-
$this->files->getRequire($path, $data);
58+
$requiredView = $this->files->getRequire($path, $data, fn ($require) => is_callable($require));
59+
60+
if (is_callable($requiredView)) {
61+
$requiredView($data);
62+
}
5963
} catch (Throwable $e) {
6064
$this->handleViewException($e, $obLevel);
6165
}

tests/View/ViewBladeCompilerTest.php

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public function testCompileCompilesFileAndReturnsContents()
6666
$compiler = new BladeCompiler($files = $this->getFiles(), __DIR__);
6767
$files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World');
6868
$files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true);
69-
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World<?php /**PATH foo ENDPATH**/ ?>');
69+
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', '<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?><?php /**PATH foo ENDPATH**/ ?>');
7070
$compiler->compile('foo');
7171
}
7272

@@ -76,7 +76,7 @@ public function testCompileCompilesFileAndReturnsContentsCreatingDirectory()
7676
$files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World');
7777
$files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(false);
7878
$files->shouldReceive('makeDirectory')->once()->with(__DIR__, 0777, true, true);
79-
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World<?php /**PATH foo ENDPATH**/ ?>');
79+
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', '<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?><?php /**PATH foo ENDPATH**/ ?>');
8080
$compiler->compile('foo');
8181
}
8282

@@ -85,7 +85,7 @@ public function testCompileCompilesAndGetThePath()
8585
$compiler = new BladeCompiler($files = $this->getFiles(), __DIR__);
8686
$files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World');
8787
$files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true);
88-
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World<?php /**PATH foo ENDPATH**/ ?>');
88+
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', '<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?><?php /**PATH foo ENDPATH**/ ?>');
8989
$compiler->compile('foo');
9090
$this->assertSame('foo', $compiler->getPath());
9191
}
@@ -102,7 +102,7 @@ public function testCompileWithPathSetBefore()
102102
$compiler = new BladeCompiler($files = $this->getFiles(), __DIR__);
103103
$files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World');
104104
$files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true);
105-
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', 'Hello World<?php /**PATH foo ENDPATH**/ ?>');
105+
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2foo').'.php', '<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?><?php /**PATH foo ENDPATH**/ ?>');
106106
// set path before compilation
107107
$compiler->setPath('foo');
108108
// trigger compilation with $path
@@ -145,39 +145,39 @@ public static function appendViewPathDataProvider()
145145
return [
146146
'No PHP blocks' => [
147147
'Hello World',
148-
'Hello World<?php /**PATH foo ENDPATH**/ ?>',
148+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?><?php /**PATH foo ENDPATH**/ ?>',
149149
],
150150
'Single PHP block without closing ?>' => [
151151
'<?php echo $path',
152-
'<?php echo $path ?><?php /**PATH foo ENDPATH**/ ?>',
152+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?><?php echo $path ?><?php } ?><?php /**PATH foo ENDPATH**/ ?>',
153153
],
154154
'Ending PHP block.' => [
155155
'Hello world<?php echo $path ?>',
156-
'Hello world<?php echo $path ?><?php /**PATH foo ENDPATH**/ ?>',
156+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello world<?php echo $path ?><?php } ?><?php /**PATH foo ENDPATH**/ ?>',
157157
],
158158
'Ending PHP block without closing ?>' => [
159159
'Hello world<?php echo $path',
160-
'Hello world<?php echo $path ?><?php /**PATH foo ENDPATH**/ ?>',
160+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello world<?php echo $path ?><?php } ?><?php /**PATH foo ENDPATH**/ ?>',
161161
],
162162
'PHP block between content.' => [
163163
'Hello world<?php echo $path ?>Hi There',
164-
'Hello world<?php echo $path ?>Hi There<?php /**PATH foo ENDPATH**/ ?>',
164+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello world<?php echo $path ?>Hi There<?php } ?><?php /**PATH foo ENDPATH**/ ?>',
165165
],
166166
'Multiple PHP blocks.' => [
167167
'Hello world<?php echo $path ?>Hi There<?php echo $path ?>Hello Again',
168-
'Hello world<?php echo $path ?>Hi There<?php echo $path ?>Hello Again<?php /**PATH foo ENDPATH**/ ?>',
168+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello world<?php echo $path ?>Hi There<?php echo $path ?>Hello Again<?php } ?><?php /**PATH foo ENDPATH**/ ?>',
169169
],
170170
'Multiple PHP blocks without closing ?>' => [
171171
'Hello world<?php echo $path ?>Hi There<?php echo $path',
172-
'Hello world<?php echo $path ?>Hi There<?php echo $path ?><?php /**PATH foo ENDPATH**/ ?>',
172+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello world<?php echo $path ?>Hi There<?php echo $path ?><?php } ?><?php /**PATH foo ENDPATH**/ ?>',
173173
],
174174
'Short open echo tag' => [
175175
'Hello world<?= echo $path',
176-
'Hello world<?= echo $path ?><?php /**PATH foo ENDPATH**/ ?>',
176+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello world<?= echo $path ?><?php } ?><?php /**PATH foo ENDPATH**/ ?>',
177177
],
178178
'Echo XML declaration' => [
179179
'<?php echo \'<?xml version="1.0" encoding="UTF-8"?>\';',
180-
'<?php echo \'<?xml version="1.0" encoding="UTF-8"?>\'; ?><?php /**PATH foo ENDPATH**/ ?>',
180+
'<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?><?php echo \'<?xml version="1.0" encoding="UTF-8"?>\'; ?><?php } ?><?php /**PATH foo ENDPATH**/ ?>',
181181
],
182182
];
183183
}
@@ -187,7 +187,7 @@ public function testDontIncludeEmptyPath()
187187
$compiler = new BladeCompiler($files = $this->getFiles(), __DIR__);
188188
$files->shouldReceive('get')->once()->with('')->andReturn('Hello World');
189189
$files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true);
190-
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php', 'Hello World');
190+
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php', '<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?>');
191191
$compiler->setPath('');
192192
$compiler->compile();
193193
}
@@ -197,7 +197,7 @@ public function testDontIncludeNullPath()
197197
$compiler = new BladeCompiler($files = $this->getFiles(), __DIR__);
198198
$files->shouldReceive('get')->once()->with(null)->andReturn('Hello World');
199199
$files->shouldReceive('exists')->once()->with(__DIR__)->andReturn(true);
200-
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php', 'Hello World');
200+
$files->shouldReceive('put')->once()->with(__DIR__.'/'.hash('xxh128', 'v2').'.php', '<?php return function ($__laravel_data) { extract($__laravel_data, EXTR_SKIP); ?>Hello World<?php } ?>');
201201
$compiler->setPath(null);
202202
$compiler->compile();
203203
}

tests/View/ViewCompilerEngineTest.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,19 @@ public function testViewsAreRecompiledWhenCompiledViewIsMissingViaFileNotFoundEx
9494

9595
$files->shouldReceive('getRequire')
9696
->once()
97-
->with($compiled, [])
97+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
9898
->andReturn('compiled-content');
9999

100100
$files->shouldReceive('getRequire')
101101
->once()
102-
->with($compiled, [])
102+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
103103
->andThrow(new FileNotFoundException(
104104
"File does not exist at path {$path}."
105105
));
106106

107107
$files->shouldReceive('getRequire')
108108
->once()
109-
->with($compiled, [])
109+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
110110
->andReturn('compiled-content');
111111

112112
$engine->getCompiler()
@@ -139,19 +139,19 @@ public function testViewsAreRecompiledWhenCompiledViewIsMissingViaRequireExcepti
139139

140140
$files->shouldReceive('getRequire')
141141
->once()
142-
->with($compiled, [])
142+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
143143
->andReturn('compiled-content');
144144

145145
$files->shouldReceive('getRequire')
146146
->once()
147-
->with($compiled, [])
147+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
148148
->andThrow(new ErrorException(
149149
"require({$path}): Failed to open stream: No such file or directory",
150150
));
151151

152152
$files->shouldReceive('getRequire')
153153
->once()
154-
->with($compiled, [])
154+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
155155
->andReturn('compiled-content');
156156

157157
$engine->getCompiler()
@@ -184,19 +184,19 @@ public function testViewsAreRecompiledJustOnceWhenCompiledViewIsMissing()
184184

185185
$files->shouldReceive('getRequire')
186186
->once()
187-
->with($compiled, [])
187+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
188188
->andReturn('compiled-content');
189189

190190
$files->shouldReceive('getRequire')
191191
->once()
192-
->with($compiled, [])
192+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
193193
->andThrow(new FileNotFoundException(
194194
"File does not exist at path {$path}."
195195
));
196196

197197
$files->shouldReceive('getRequire')
198198
->once()
199-
->with($compiled, [])
199+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
200200
->andThrow(new FileNotFoundException(
201201
"File does not exist at path {$path}."
202202
));
@@ -234,7 +234,7 @@ public function testViewsAreNotRecompiledOnRegularViewException()
234234

235235
$files->shouldReceive('getRequire')
236236
->once()
237-
->with($compiled, [])
237+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
238238
->andThrow(new Exception(
239239
'Just an regular error...'
240240
));
@@ -269,7 +269,7 @@ public function testViewsAreNotRecompiledIfTheyWereJustCompiled()
269269

270270
$files->shouldReceive('getRequire')
271271
->once()
272-
->with($compiled, [])
272+
->with($compiled, [], m::on(fn ($c) => $c(1) == false && $c(fn() => 'test') == true))
273273
->andThrow(new FileNotFoundException(
274274
"File does not exist at path {$path}."
275275
));

0 commit comments

Comments
 (0)