Getting latte filters to run inside included variable text

5 months ago

madrian
Member | 6
+
0
-

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!

5 months ago

MajklNajt
Member | 358
+
+1
-

Hi, this is not possible, you must use string loader for parse template in string

5 months ago

madrian
Member | 6
+
0
-

Thank you very much!
This is the working solution:

$latte = new \Latte\Engine;
$latte->setLoader(new \Latte\Loaders\StringLoader([
    'pageText' => 'Say {="olleH" |reverse} to Latte!'
]));
$vars->pageText = $latte->renderToString('pageText');

5 months ago

madrian
Member | 6
+
0
-

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!

5 months ago

MajklNajt
Member | 358
+
+1
-

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;
	}
}

5 months ago

Martk
Member | 558
+
+1
-

@MajklNajt 's answer + UI macros installation:

Nette\Bridges\ApplicationLatte\UIMacros::install($latte->getCompiler());

5 months ago

madrian
Member | 6
+
0
-

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;

5 months ago

Mabar
Member | 286
+
+3
-

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)

5 months ago

madrian
Member | 6
+
0
-

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

5 months ago

Mabar
Member | 286
+
0
-
  1. 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.
  2. Fixed, forgot loader accepts multiple templates. Hope it works now

5 months ago

madrian
Member | 6
+
0
-
  1. 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”.