Vytvoření vlatního tagu do Latte šablony

- grovik
- Člen | 95
Ahoj,
jsem z toho trošku v úzkých. Snažím se vytvořit několik tagů pro
vkládání dat z DB nebo přímo z MODBAS zařízení. Mám problém tag
vytvořit. Možná dělám něco fakt blbě… už se v tom vrtám asi týden.
Jediné co mám je chyba
`Latte\CompileException
Unexpected tag {ndata} (in ‚…/ControlRoom /default.latte‘ on line 92 at
column 25)`
Mám vytvořený extension
<?php
namespace App\Components\Latte;
use Latte\Extension;
/** @noinspection PhpUnused */
use App\Components\Latte\NDataNode;
/** @noinspection PhpUnused */
use App\Components\Latte\NButtonNode;
/** @noinspection PhpUnused */
use App\Components\Latte\NGrafNode;
use App\Services\ChannelService;
final class ChannelsExtension extends Extension
{
private const _REFS = [NDataNode::class, NGrafNode::class, NButtonNode::class];
public function __construct(private readonly ChannelService $channelService) {
\Tracy\Debugger::barDump('ChannelsExtension constructed', 'Latte');
}
/** @return array<string,callable> */
public function getTags(): array
{
bdump('ChannelsExtension loaded', 'Latte'); // uvidíš v Tracy
return [
'ndata' => [NDataNode::class, 'create'],
'ngraf' => [NGrafNode::class, 'create'],
'nbutton' => [NButtonNode::class, 'create'],
];
}
/** @return array<string,mixed> providers accessible as $this->global->channelsService */
public function getProviders(): array
{
return [
'channelsService' => $this->channelService,
];
}
}
Pro začátek jsem do Presenteru přidal registraci
public function beforeRender():void
{
parent::beforeRender();
$latte = new \Latte\Engine();
$latte->addExtension(new ChannelsExtension($this->channelService));
}
No a v šabloně:
<div class="card">
<div class="card-header">Graf hladiny</div>
<div class="card-body">
<div class="placeholder" style="height:100px;background:#eee;">Graf</div>
{ndata 1}
</div>
</div>
Editoval grovik (8. 10. 15:03)

- grovik
- Člen | 95
Hurá tak jsem na to přišel :D
Asi by to chtělo zanést do návodu. Kudy na to v Presenteru.
protected function createTemplate(?string $class = null): \Nette\Application\UI\Template
{
$template = parent::createTemplate($class);
// získat aktuální Latte Engine
$latte = $template->getLatte();
// přidat Channels
$latte->addExtension(new \App\Components\Latte\ChannelsExtension($this->channelService));
// kontrola jestli to fachčí
bdump($latte->getExtensions(), 'Active Latte extensions after addExtension()');
return $template;
}

- m.brecher
- Generous Backer | 911
@grovik
Pro začátek jsem do Presenteru přidal registraci
$latte = new \Latte\Engine();
$latte->addExtension(new ChannelsExtension($this->channelService));
Vytváříš novou instanci Latte ale nette pracuje s jinou instancí, takže přidanou extension použít nemůže.
Hurá tak jsem na to přišel :D asi by to chtělo zanést do návodu. Kudy na to v Presenteru.
$latte = $template->getLatte();
$latte->addExtension(new \App\Components\Latte\ChannelsExtension($this->channelService))
zde jsi použil existující instanci Latte, takže už to funguje, ale postup je v rozporu s myšlenkou Nette DI, správný postup je použít DIC.
Zkus postupovat cca nějak takto:
1. Nejprve zaregistruj ChannelsExtension jako službu. Pokud používáš ChannelService, musí být také dostupný v DI.
services:
- ChannelsExtension(@ChannelService)
2. Připojení do Latte přes LatteFactory, Nette používá LatteFactory k vytváření instancí Latte. Musíš tedy říct DI kontejneru, aby do této továrny přidal tvoji extension:
latteFactory:
setup:
- addExtension(@ChannelsExtension)
Vyzkoušej a napiš jak jsi dopadl.

- grovik
- Člen | 95
m.brecher napsal(a):
@grovik
>
Vyzkoušej a napiš jak jsi dopadl.
Zkusím až bude chvilka. Za mě je NEON pořád nejvíc chaotická věc. Je
to trochu black box.
Málo přehledné když něco přidám věčně blbnu s mezerama a spol… a
vlastně není úplně jasné co to dělá. To v tom PHP je mi jasné a
zřetelné a pochopitelné.

- m.brecher
- Generous Backer | 911
@grovik
Za mě je NEON pořád nejvíc chaotická věc.
Chápu, můžeš extension přidat i normálně v kódu, ale dodržet nějakou štábní kulturu, využívat createTemplate() je oklika, latte jde získat v presenteru jednoduše a pokud chceš mít tagy k dipozici všude, využij render lifecycle hook BasePresenteru nějak takhle:
abstract class BasePresenter extends Presenter
{
public function injectLatteTags(ChannelService $channelService): void
{
$this->onRender[] = function() use ($channelService) {
$latte = $this->template->getLatte();
$latte->addExtension(new ChannelsExtension($channelService));
};
}
}
metoda inject*() se v presenterech spouští automaticky při inicializaci a předávají se služby podle typů parametrů, Latte získáš referencí z aktuální instance Template v presenteru $template, tím obejdeš problematický neon, ale použiješ standardní, logický postup. Instance Latte i Template se vytvářejí automaticky, je správné použít ty již existující instance.