How to generate links in templates

simPod
Member | 383
+
0
-

I have the same issue as the guy here https://forum.nette.org/…y-componenty#…

I followed the thread, docs and https://phpfashion.com/…lech-a-nette

I don't want any magic so I went with LatteEngine which is the least magical (it has this though Nette\Bridges\ApplicationLatte\UIMacros::install($latte->getCompiler()); meh)

and I'm getting

Undefined property: stdClass::$uiControl

This is generated when renderToString() is called:

echo LR\Filters::escapeHtmlText($this->global->uiControl->link(...

There's no uiControl registered on global though.

I expected \Nette\Bridges\ApplicationLatte\LatteFactory::create() to give me fully working latte renderer.


So I noticed there's TemplateFactory that requires UI\Control instance and internally setups LatteEngine properly.

I've created this abomination that can be used only from Control (presenters etc.).

    public function create(Control $control): Engine
    {
        $template        = $this->templateFactory->createTemplate($control);
        $reflectionClass = $template instanceof DefaultTemplate
            ? (new ReflectionClass($template))->getParentClass()
            : new ReflectionClass($template);

        $latteProperty = $reflectionClass->getProperty('latte');
        $latteProperty->setAccessible(true);

        return $latteProperty->getValue($template);
    }

I can't use Template because it cannot be rendered to string. Is there's a way to render latte properly using OOP?

simPod
Member | 383
+
0
-

@MarekBartoš helped me with his snippet. This is what I've ended up with and that's enough for the current project. Thanks!

    public function create(Control $control): Engine
    {
        $template = $this->templateFactory->createTemplate($control);

        return $template->getLatte();
    }

Last edited by simPod (2021-07-31 13:28)

Rick Strafy
Nette Blogger | 81
+
+1
-

Hi, try this, use Nette\Bridges\ApplicationLatte\LatteFactory and Nette\Application\LinkGenerator from DI and then

$latte = $this->latteFactory->create();
UIMacros::install($latte->getCompiler());
$latte->addProvider('uiControl', $this->linkGenerator);

and you can use that to render templates to string, for instance

$emailTemplate = new EmailTemplate($latte);
$emailTemplate->something = 'test';
$emailTemplate->renderToString();

It can be used outside of controls/presenters.
EmailTemplate extends Nette\Bridges\ApplicationLatte\Template, that way you can have strict typed templates

Last edited by Rick Strafy (2021-07-31 14:59)

simPod
Member | 383
+
0
-

@RickStrafy even better considering the fact I don't have to pass Control to the factory. 👍🏿

Marek Bartoš
Nette Blogger | 1263
+
0
-

I would go with something like this to not loose functionality of TemplateFactory, most importantly all the macros and filters from outside of Nette

use Nette\Application\LinkGenerator;
use Nette\Bridges\ApplicationLatte\Template;
use Nette\Bridges\ApplicationLatte\TemplateFactory;

class FooTemplate extends Template
{

	public string $foo;

}

class TemplateCreator
{

	public function __construct(
		private TemplateFactory $templateFactory,
		private LinkGenerator $linkGenerator,
	)
	{
	}

	/**
	 * @template T of Template
	 * @param class-string<T> $templateClass
	 * @return T
	 */
	public function createTemplate(string $templateClass): Template
	{
		$template = $this->templateFactory->createTemplate(class: $templateClass);
		assert($template instanceof $templateClass);

		$latte = $template->getLatte();
		$latte->addProvider('uiControl', $this->linkGenerator);

		return $template;
	}

}


$creator = new TemplateCreator();
$template = $creator->createTemplate(FooTemplate::class);

$template->foo = 'bar';
$template->renderToString(__DIR__ . '/path/to/email.latte');

Last edited by Marek Bartoš (2021-07-31 13:56)