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

grovik
Člen | 95
+
0
-

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
+
0
-

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
+
+3
-

@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
+
0
-

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
+
+1
-

@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.