Skip to content

Commit 56e9876

Browse files
committed
Control: flashMessage() does not create the template
In the most typical flow - flashMessage() followed by redirect() - the template was created just to be thrown away, which builds a whole Latte\Engine instance. The messages are written to the session first and into the template only if it already exists; a template created later gets them from the template factory, which reads the flashes from the session on its own.
1 parent c4e5f92 commit 56e9876

3 files changed

Lines changed: 53 additions & 4 deletions

File tree

‎docs/internals/templates.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ the default. `TemplateFactory::createTemplate` instantiates it around a fresh La
4242
engine and injects the default variables (`user`, `baseUrl`, `basePath`, `flashes`,
4343
`control`, `presenter`).
4444

45+
**`flashes` depends on this injection.** `Control::flashMessage()` writes the
46+
message to the flash session and into the template only if the template already
47+
exists; it never creates one. A template created later gets the messages solely
48+
from the factory, which reads them from the flash session, so a custom
49+
`TemplateFactory` has to inject `flashes` the same way.
50+
4551
## `#[TemplateVariable]`
4652

4753
At `sendTemplate`, `completeTemplate()` copies every `#[TemplateVariable]` property

‎src/Application/UI/Control.php‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,14 @@ public function flashMessage(string|\stdClass|\Stringable $message, string $type
104104
'message' => $message,
105105
'type' => $type,
106106
];
107-
$messages = $this->getPresenter()->getFlashSession()->get($id);
107+
$session = $this->getPresenter()->getFlashSession();
108+
$messages = $session->get($id);
108109
$messages[] = $flash;
109-
$this->getTemplate()->flashes = $messages;
110-
$this->getPresenter()->getFlashSession()->set($id, $messages);
110+
$session->set($id, $messages);
111+
if (isset($this->template)) { // a not-yet-created template gets flashes injected by the template factory
112+
$this->template->flashes = $messages;
113+
}
114+
111115
return $flash;
112116
}
113117

‎tests/UI/Presenter.flashMessage.phpt‎

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ test('multiple flash messages are stored', function () {
142142
});
143143

144144

145-
test('flash message is available in template', function () {
145+
test('flash message is written to an already created template', function () {
146146
$messages = [];
147147
$sessionSection = Mockery::mock(Http\SessionSection::class);
148148
$sessionSection->shouldReceive('get')->andReturnUsing(function () use (&$messages) {
@@ -172,6 +172,45 @@ test('flash message is available in template', function () {
172172

173173
$presenter->run(new Application\Request('Test', 'GET', ['action' => 'default']));
174174

175+
$template = $presenter->getTemplate();
176+
$presenter->flashMessage('Template message');
177+
178+
Assert::count(1, $template->flashes);
179+
Assert::same('Template message', $template->flashes[0]->message);
180+
});
181+
182+
183+
test('flash message is injected into a template created later', function () {
184+
$messages = [];
185+
$sessionSection = Mockery::mock(Http\SessionSection::class);
186+
$sessionSection->shouldReceive('get')->andReturnUsing(function () use (&$messages) {
187+
return $messages;
188+
});
189+
$sessionSection->shouldReceive('set')->andReturnUsing(function ($id, $value) use (&$messages) {
190+
$messages = $value;
191+
});
192+
193+
$session = Mockery::mock(Http\Session::class);
194+
$session->shouldReceive('getSection')->andReturn($sessionSection);
195+
$session->shouldReceive('hasSection')->andReturn(true);
196+
197+
$latte = Mockery::mock(Latte\Engine::class);
198+
$latte->shouldIgnoreMissing();
199+
$latteFactory = Mockery::mock(Nette\Bridges\ApplicationLatte\LatteFactory::class);
200+
$latteFactory->shouldReceive('create')->andReturn($latte);
201+
$templateFactory = new Nette\Bridges\ApplicationLatte\TemplateFactory($latteFactory);
202+
203+
$presenter = new TestPresenter;
204+
$presenter->injectPrimary(
205+
new Http\Request(new Http\UrlScript),
206+
new Http\Response,
207+
session: $session,
208+
templateFactory: $templateFactory,
209+
);
210+
$presenter->autoCanonicalize = false;
211+
212+
$presenter->run(new Application\Request('Test', 'GET', ['action' => 'default']));
213+
175214
$presenter->flashMessage('Template message');
176215

177216
$template = $presenter->getTemplate();

0 commit comments

Comments
 (0)