Object of class App\Presenters\ArticlePresenter could not be converted to string – chyba v Latte?

m.brecher
Generous Backer | 717
+
0
-

Zkoušel jsem tohle a narazil na chybu v šabloně latte:

Založil jsem si v presenteru konstantu – id, abych ji následně použil pro označení sekce, na kterou by měly vést odkazy:

abstract class PublicPresenter extends BasePresenter
{
    public const PRICELIST_SECTION_ID = 'sekce-cenik';
.....
}

mainMenu.latte – tohle funguje:

{var $hash = $presenter::PRICELIST_SECTION_ID}
<a n:href="Article:homepage#$hash, url: null">Ceník</a>

mainMenu.latte – tohle nefunguje:

<a n:href="Article:homepage#$presenter::PRICELIST_SECTION_ID, url: null">Ceník</a>

Vyhodí to výjimku Object of class App\Presenters\ArticlePresenter could not be converted to string

Myslím si, že chybu v syntaxi nedělám a že by latte mělo zvládnout přeložit v n:href makru výraz $presenter::PRICELIST_SECTION_ID, takže dávám podnět pro případnou opravu.

Polki
Člen | 553
+
0
-

V makru n:href je znak : brán jako oddělovač Modulů, Presenterů a Akcí.

Místo libovolného modulu/presenteru/akce můžeš dát string proměnnou, která se do názvu přeloží.
Ovšem jak by podle tebe měla tedy fungovat interpretace toho, co jsi napsal?

Editoval Polki (12. 12. 2021 0:14)

nightfish
Člen | 468
+
+2
-

@mbrecher

Obsah makra n:href se jako řetězec předává do metody link(), ve tvém případě by volání vypadalo následovně:

$this->global->uiControl->link("Article:homepage#$presenter::PRICELIST_SECTION_ID, url: null")

A protože PHP nepodporuje interpolaci konstant v rámci řetězců, ani když je uzavřeš do složených závorek (viz dokumentaci – část „Complex (curly) syntax“ a poznámku v této sekci), tak při zpracovávání argumentu metody link() vidí PHP proměnnou $presenter, pokusí se ji nahradit za řetězcovou reprezentaci a selže. Kdybys měl na presenteru implementovanou metodu __toString(), tak to sice neselže, ale výsledný odkaz by tě stejně neuspokojil, protože by obsahovat /clanky#text_z_metody_toString_presenteru::PRICELIST_SECTION_ID.

Obávám se, že uvedený problém není na úrovni Latte řešitelný, takže nezbývá než si pomoct uložením hashe do samostatné proměnné.

Kamil Valenta
Člen | 752
+
0
-

nightfish napsal(a):

…takže nezbývá než si pomoct uložením hashe do samostatné proměnné.

Nebo si v tom presenteru napsat getter té konstanty.

m.brecher
Generous Backer | 717
+
0
-

Dík za vysvětlení problematiky Latte. Pokud PHP nepodporuje statické konstanty v řetězcích, je logické že Latte také ne.

Navíc „injektovat“ konstanty z presenteru do šablony nebude best practice. V presenteru by takovéto konstanty být neměly a do šablony by se měly všechny data předávat ideálně vždy přes presenter/komponentu – pak je pořádek.

Přesunul jsem konstantu do třídy AppUtils, a v presenteru ji injektuji standardním způsobem do proměnné v šabloně latte:

a ) konstantu do třídy AppUtils:

class AppUtils
{
    public const PRICELIST_SECTION_ID = 'sekce-cenik';
	.......
}

b ) pomocnou třídu AppUtils předat jako závislost do presenteru
c ) v presenteru injektovat konstantu do šablony

abstract class FrontPresenter extends BasePresenter
{
    #[Inject] public AppUtils $appUtils;

    public function beforeRender()
    {
        parent::beforeRender();
        $this->template->pricelistSectionId = $this->appUtils::PRICELIST_SECTION_ID;
    }
}

d ) v latte použít obyčejnou proměnnou

<a n:href="Article:homepage#$pricelistSectionId, url: null">Ceník</a>

O malinko více kódu, ale zato estetičtější ;)

Kamil Valenta
Člen | 752
+
0
-

m.brecher napsal(a):

O malinko více kódu, ale zato estetičtější ;)

Zůstal presenter / model přenositelný, aniž by člověk musel extrahovat patřičné konstanty z AppUtils? Neklade to na člověka nároky vědět které konstanty k požadovanému presenteru / modelu patří a které ne?

m.brecher
Generous Backer | 717
+
0
-

Polki napsal(a):

V makru n:href je znak : brán jako oddělovač Modulů, Presenterů a Akcí.

Místo libovolného modulu/presenteru/akce můžeš dát string proměnnou, která se do názvu přeloží.
Ovšem jak by podle tebe měla tedy fungovat interpretace toho, co jsi napsal?

Ahoj

Ohledně interpretace dvojtečky v n makru by konflikt mezi voláním statické proměnné přes dvě dvojtečky, nebo označením modulu/presenteru jednou dvojtečkou být nemusel. Čistě intuitivně jsem předpokládal, že stejný výraz který píšu v makru {var …} můžu napsat i v makru n:href.

Jak ale napsal jeden z kolegů na můj příspěvěk – ani PHP nepodporuje statickou konstantu v řetězcích – i když si myslím, že pro to není důvod a že by to PHP podporovat mělo. Pak je celkem logické, že Latte, které z PHP ideově vychází to také nepodporuje.

On je to nakonec asi antipattern volat nějakou svoji konstantu někde uprostřed šablony – obchází se tím důležitý princip dependency injection.

Jak řešíš Ty integritu takovýchto pomocných dat – kdy máš nějakou konstantu, obvykle řetězec který použiješ na dvou/třech místech v kódu – např. jako zde html kotva pro odrolování a stejný řetězec použít v odkazu, nebo javascriptu?

m.brecher
Generous Backer | 717
+
0
-

Kamil Valenta napsal(a):

m.brecher napsal(a):

O malinko více kódu, ale zato estetičtější ;)

Zůstal presenter / model přenositelný, aniž by člověk musel extrahovat patřičné konstanty z AppUtils? Neklade to na člověka nároky vědět které konstanty k požadovanému presenteru / modelu patří a které ne?

Tato konstanta má jediný účel – zajistit integritu mezi kotvou v html elementu (id) a hashem v url, které na tu kotvu odroluje (popř. v javascriptu), dá se tam napsat řetězec, ale při překlepu se chybu nedozvím.

Hodnota té kotvy je libovolná, je to hodně málo důležitá konstanta. Řekl bych, že je to konstanta pro vykreslování – v odkazu a v příslušné sekci na kterou se roluje, popř. v javascriptu, do kterého se opět nainjektuje v latte. Takže do modelu určitě nepatří. Jako property v presenteru také nemá co dělat – nic neovlivňuje, nic neřídí.

Kamil Valenta
Člen | 752
+
0
-

Já to myslel obecně, že sesypávat konstanty na jedno místo není úplně šťastné.

V případě odkazu (než to cpát do každé šablony v beforeRender()) bych zvážil připravit si odkaz v @layout.latte v blocku a pak už jen dle potřeby vykreslovat.

Nebo pokud je to využíváno někdy jako odkaz, někdy jako něco v JS, zvážil bych umístění do komponenty.

m.brecher
Generous Backer | 717
+
0
-

Kamil Valenta napsal(a):

Já to myslel obecně, že sesypávat konstanty na jedno místo není úplně šťastné.

V případě odkazu (než to cpát do každé šablony v beforeRender()) bych zvážil připravit si odkaz v @layout.latte v blocku a pak už jen dle potřeby vykreslovat.

Nebo pokud je to využíváno někdy jako odkaz, někdy jako něco v JS, zvážil bych umístění do komponenty.

Já to cpu v beforeRender() v abstraktním presenteru jenom jednou.

Konstantu používám:

  • jako hodnotu id html elementu kam se má odrolovat stránka
  • jako hash v html odkazu
  • jako id html elementu který se javascriptem scroluje aby byl vidět htmlElement.scrollIntoView()

ve všech třech případech to vykresluje šablona – i javascript, takže se to používá v různých šablonách a ideální je injektovat to v abstraktním presenteru, který obsluhuje všechny šablony. Nejde o kus html kódu ale jen a jen o jeden string, který se vejde do jedné proměnné. Dát to do bloku v layout.latte by asi bylo komplikovanější na použití – do latte teprve pronikám, ale myslím, že proměnná vytvořená v jedné šabloně se automaticky do jiných šablon nepřenáší. Přenos proměnných mezi šablonami nějak jde, ale musí se ručně ty proměnné zapisovat.

Nakonec, je možné i to zapsat jednoduše jako string a dát si pozor, aby tam člověk neudělal chybu.

Editoval m.brecher (13. 12. 2021 0:16)