Getting latte filters to run inside included variable text
- madrian
- Member | 6
The setup
I am using Markdown files for subpages. These files get loaded and their
contents get set into variables inside the Presenter. Then every request gets
routed to a single Latte-Template, which is supposed to display the variables.
It's a markdown-sub-template-system so to speak.
The question
I would like to be able to place Latte filters inside the markdown text file
and have these filters eventually evaluated in the layout.latte. For example
consider these steps:
(1) The text is set in the PagePresenter. It includes a latte filter/function.
$vars->pageText = 'Say {="olleH" |reverse} to Latte!';
(2) Defining the main block inside
page.latte
. Text is placed here without escaping.
{define main}
{$vars->pageText |noescape}
{/define}
(3) The block is then included into
@layout.latte
{include main}
I expect to see
Say Hello to Latte!
What I instead see is
Say {="olleH" |reverse} to Latte!
If I place the same code directly into the page.latte
it
obviously works. But when text from a variable gets printed into the
page.latte
the Latte engine does not evaluate the filters.
Thanks for any suggestions!
- madrian
- Member | 6
Additional issue:
Linking does not work with the above solution.
# this works
{php echo time()} also
{="olleH" |reverse}
# but this doesn't
<a n:href=Presenter:page>page</a>
# Latte\CompileException Unknown attribute n:href
{link Presenter:page}
# Latte\CompileException Unknown macro {link}
How come? Any suggestions? Thanks!
- MajklNajt
- Member | 498
you must add provider Nette\Application\LinkGenerator
as
uiControl
:
class YourClassName
{
private $linkGenerator;
public function __construct(\Nette\Application\LinkGenerator $linkGenerator)
{
$this->linkGenerator = $linkGenerator;
}
private function createLatte(): \Latte\Engine
{
$latte = new \Latte\Engine;
$latte->setLoader(new \Latte\Loaders\StringLoader(...));
$latte->addProvider("uiControl", $this->linkGenerator);
return $latte;
}
}
- madrian
- Member | 6
Working solution:
/** @var \Nette\Application\LinkGenerator @inject */
public $linkGenerator;
private function createLatte(): \Latte\Engine
{
$latte = new \Latte\Engine;
$latte->addProvider('uiControl', $this->linkGenerator);
\Nette\Bridges\ApplicationLatte\UIMacros::install($latte->getCompiler());
return $latte;
}
Rest like before but with:
$latte = $this->createLatte();
instead of:
$latte = new \Latte\Engine;
- Marek Bartoš
- Nette Blogger | 1275
To have exactly same posibilities as in presenter/control template, use TemplateFactory
/** @var \Nette\Bridges\ApplicationLatte\TemplateFactory @inject */
public $templateFactory;
private function latteToText(string $latte, ?\Nette\Aplication\UI\Control $control = null): string
{
$template = $this->templateFactory->createTemplate($control);
assert($template instanceof \Nette\Bridges\ApplicationLatte\Template);
$template->getLatte()->setLoader(new \Latte\Loaders\StringLoader());
return $template->renderToString($latte);
}
Last edited by Mabar (2020-03-11 10:24)
- madrian
- Member | 6
Thank you @Mabar for this approach.
The following issues arrise:
(1) Injection missing
Nette\DI\MissingServiceException
Service of type Nette\Bridges\ApplicationLatte\TemplateFactory used in @var annotation at App\Presenters\AbstractPresenter::$templateFactory not found. Did you register it in configuration file?
(2) Type issue
latteToText(string $latte
expects string
, but
new \Latte\Loaders\StringLoader($latte)
expexts array|null
- Marek Bartoš
- Nette Blogger | 1275
- It's expected that you have registered
Nette\Bridges\ApplicationDI\LatteExtension
in DIC. You don't use nette/di? Or nette/bootstrap which should register this extension for you. - Fixed, forgot loader accepts multiple templates. Hope it works now
- madrian
- Member | 6
- It's expected that you have registered
Nette\Bridges\ApplicationDI\LatteExtension
in DIC.
@Mabar: Well, don't expect to much.
I am unable to get you suggested code to run. Always running into the next exception. So I will stick to the former approach. Maybe your code is the superior approach, but it's not working “out of the box”.