Skip to content

Commit ef49916

Browse files
committed
Don't run post processors when compiling views
1 parent 0838ff3 commit ef49916

File tree

5 files changed

+184
-5
lines changed

5 files changed

+184
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Changed
6+
7+
- Post-processors don't run if Laravel is compiling views.
8+
59
## 0.5.2 - 2021-08-02
610

711
### Fixed

src/Blade/EngineDecorator.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* @author Aaron Francis <aaron@hammerstone.dev|https://twitter.com/aarondfrancis>
4+
*/
5+
6+
namespace Torchlight\Blade;
7+
8+
use Illuminate\Contracts\View\Engine;
9+
use Torchlight\Torchlight;
10+
11+
class EngineDecorator implements Engine
12+
{
13+
public $decorated;
14+
15+
public function __construct($resolved)
16+
{
17+
$this->decorated = $resolved;
18+
}
19+
20+
public function __get($name)
21+
{
22+
return $this->decorated->{$name};
23+
}
24+
25+
public function __set($name, $value)
26+
{
27+
$this->decorated->{$name} = $value;
28+
}
29+
30+
public function __call($name, $arguments)
31+
{
32+
return call_user_func_array([$this->decorated, $name], $arguments);
33+
}
34+
35+
public function get($path, array $data = [])
36+
{
37+
Torchlight::currentlyCompilingViews(true);
38+
39+
$result = $this->decorated->get($path, $data);
40+
41+
Torchlight::currentlyCompilingViews(false);
42+
43+
return $result;
44+
}
45+
}

src/Manager.php

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class Manager
4242
*/
4343
protected $postProcessors = [];
4444

45+
/**
46+
* @var bool
47+
*/
48+
protected $currentlyCompilingViews = false;
49+
4550
/**
4651
* @param Client $client
4752
* @return Manager
@@ -65,6 +70,14 @@ public function client()
6570
return $this->client;
6671
}
6772

73+
/**
74+
* @param $value
75+
*/
76+
public function currentlyCompilingViews($value)
77+
{
78+
$this->currentlyCompilingViews = $value;
79+
}
80+
6881
/**
6982
* @param $blocks
7083
* @return mixed
@@ -73,11 +86,7 @@ public function highlight($blocks)
7386
{
7487
$blocks = $this->client()->highlight($blocks);
7588

76-
foreach ($blocks as $block) {
77-
foreach ($this->postProcessors as $processor) {
78-
app($processor)->process($block);
79-
}
80-
}
89+
$this->postProcessBlocks($blocks);
8190

8291
return $blocks;
8392
}
@@ -116,6 +125,31 @@ public function addPostProcessors($classes)
116125
}
117126
}
118127

128+
/**
129+
* @param $blocks
130+
*/
131+
public function postProcessBlocks($blocks)
132+
{
133+
foreach ($this->postProcessors as $processor) {
134+
$processor = app($processor);
135+
136+
// By default we do _not_ run post-processors when Laravel is compiling
137+
// views, because it could lead to data leaks if a post-processor swaps
138+
// user data in. If the developer understands this, they can turn
139+
// `processEvenWhenCompiling` on and we'll happily run them.
140+
$processWhenCompiling = property_exists($processor, 'processEvenWhenCompiling')
141+
&& $processor->processEvenWhenCompiling;
142+
143+
if ($this->currentlyCompilingViews && !$processWhenCompiling) {
144+
continue;
145+
}
146+
147+
foreach ($blocks as $block) {
148+
$processor->process($block);
149+
}
150+
}
151+
}
152+
119153
/**
120154
* Get an item out of the config using dot notation.
121155
*

src/TorchlightServiceProvider.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Illuminate\Support\ServiceProvider;
99
use Torchlight\Blade\BladeManager;
1010
use Torchlight\Blade\CodeComponent;
11+
use Torchlight\Blade\EngineDecorator;
1112
use Torchlight\Commands\Install;
1213
use Torchlight\Middleware\RenderTorchlight;
1314

@@ -20,6 +21,7 @@ public function boot()
2021
$this->publishConfig();
2122
$this->registerBladeComponent();
2223
$this->registerLivewire();
24+
$this->decorateGrahamCampbellEngines();
2325
}
2426

2527
public function bindManagerSingleton()
@@ -71,6 +73,53 @@ public function registerLivewire()
7173
}
7274
}
7375

76+
/**
77+
* Graham Campbell's Markdown package is a common (and excellent) package that many
78+
* Laravel developers use for markdown. It registers a few view engines so you can
79+
* just return e.g. `view("file.md")` and the markdown will get rendered to HTML.
80+
*
81+
* The markdown file will get parsed *once* and saved to the disk, which could lead
82+
* to data leaks if you're using a post processor that injects some sort of user
83+
* details. The first user that hits the page will have their information saved
84+
* into the compiled views.
85+
*
86+
* We decorate the engines that Graham uses so we can alert our post processors
87+
* not to run when the views are being compiled.
88+
*/
89+
public function decorateGrahamCampbellEngines()
90+
{
91+
if (!class_exists('\\GrahamCampbell\\Markdown\\MarkdownServiceProvider')) {
92+
return;
93+
}
94+
95+
// The engines won't be registered if this is false.
96+
if (!$this->app->config->get('markdown.views')) {
97+
return;
98+
}
99+
100+
// Decorate all the engines that Graham's package registers.
101+
$this->decorateEngine('md');
102+
$this->decorateEngine('phpmd');
103+
$this->decorateEngine('blademd');
104+
}
105+
106+
/**
107+
* Decorate a single view engine.
108+
* @param $name
109+
*/
110+
protected function decorateEngine($name)
111+
{
112+
// No engine registered.
113+
if (!$resolved = $this->app->view->getEngineResolver()->resolve($name)) {
114+
return;
115+
}
116+
117+
// Wrap the existing engine in our decorator.
118+
$this->app->view->getEngineResolver()->register($name, function () use ($resolved) {
119+
return new EngineDecorator($resolved);
120+
});
121+
}
122+
74123
public function register()
75124
{
76125
$this->mergeConfigFrom(__DIR__ . '/../config/torchlight.php', 'torchlight');

tests/PostProcessorTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,43 @@ public function it_runs_post_processors()
3636
$this->assertEquals($blocks[0]->highlighted, '<div class=\'highlighted\'>echo "goodbye world";</div>');
3737
}
3838

39+
/** @test */
40+
public function it_doesnt_run_when_compiling()
41+
{
42+
$this->fakeSuccessfulResponse('id');
43+
44+
Torchlight::addPostProcessors([
45+
GoodbyePostProcessor::class
46+
]);
47+
48+
Torchlight::currentlyCompilingViews(true);
49+
50+
$blocks = Torchlight::highlight(
51+
Block::make('id')->language('php')->code('echo "hello world";')
52+
);
53+
54+
$this->assertEquals($blocks[0]->highlighted, '<div class=\'highlighted\'>echo "hello world";</div>');
55+
}
56+
57+
/** @test */
58+
public function it_runs_when_compiling_if_requested()
59+
{
60+
$this->fakeSuccessfulResponse('id');
61+
62+
Torchlight::addPostProcessors([
63+
GoodbyePostProcessor::class,
64+
RunWhileCompilingProcessor::class,
65+
]);
66+
67+
Torchlight::currentlyCompilingViews(true);
68+
69+
$blocks = Torchlight::highlight(
70+
Block::make('id')->language('php')->code('echo "hello world";')
71+
);
72+
73+
$this->assertEquals($blocks[0]->highlighted, '<div class=\'highlighted\'>echo "compiled world";</div>');
74+
}
75+
3976
/** @test */
4077
public function null_processor_works()
4178
{
@@ -103,3 +140,13 @@ public function process(Block $block)
103140
$block->highlighted = str_replace('goodbye', 'goodbye cruel', $block->highlighted);
104141
}
105142
}
143+
144+
class RunWhileCompilingProcessor implements PostProcessor
145+
{
146+
public $processEvenWhenCompiling = true;
147+
148+
public function process(Block $block)
149+
{
150+
$block->highlighted = str_replace('hello', 'compiled', $block->highlighted);
151+
}
152+
}

0 commit comments

Comments
 (0)