Latte 3 {php malformed content

Čamo
Člen | 798
+
0
-

Ahoj,
vie mi niekto prosím vás poradiť prečo mi šablona vyhadzuje error keď chcem použiť {php} makro?
Error je
Latte\CompileException
Malformed tag contents in …\DevicesPlaylist\playlist_information.latte:78

Kód vyzerá takto

{php
    $accessCssClass = 'btn-danger';
    $accessText = '';

    if ( $last_access ) {
        $now = new \DateTime();
        $to_time = strtotime($last_access->format('d.m.Y H:i:s'));
        $from_time = strtotime($now->format('d.m.Y H:i:s'));
        $minute = round(abs($to_time - $from_time) / 60, 2);

        if ($minute <= 20) {
            $accessCssClass = 'btn-success';
            $accessText = $presenter->translate("device.online", "Online");
        }
        else {
            $accessCssClass = 'btn-warning';
            $accessText = $presenter->translate("device.offline", "Offline");
        }
    }
    else {
        $accessText = $presenter->translate("device.never_connected", "Never connected");
    }
}

Problém je až v tej vnútornej if else podmienke. Ale ja tam problém nevidím.

Editoval Čamo (26. 9. 14:15)

Pepino
Člen | 256
+
-1
-

{php}PHP KOD{/php}

Čamo
Člen | 798
+
0
-

Ja toto makro bežne používam týmto spôsobom a normálne to funguje. Aj pár riadkov nad týmto kódom.
Keď to použijem ako {php}{/php} tak mi to vyhodí error
Missing arguments in {php} in …\DevicesPlaylist\playlist_information.latte:78
Dokumentácia ku tomu nieje žiadna :(

Editoval Čamo (26. 9. 14:41)

Marek Bartoš
Nette Blogger | 1260
+
+3
-

To makro nikdy nepodporovalo syntaxi php neomezeně, stejně jako celé Latte. Nehodí se to pro velké bloky kódu

Čamo
Člen | 798
+
-1
-

Ja som to chcel dostať do šablony lebo celý ten kód sa týka zafarbenia buttonov. Nepáčilo sa mi že to bolo v presenteri. Tak som to zjednodušil a časť mám v presenteri a čast v šablone.

nightfish
Člen | 516
+
+1
-

@Čamo
Když už jdu kolem, dovolím si pár nesouvisejících komentářů k tvému kódu.

Část

$now = new \DateTime();
$to_time = strtotime($last_access->format('d.m.Y H:i:s'));
$from_time = strtotime($now->format('d.m.Y H:i:s'));
$minute = round(abs($to_time - $from_time) / 60, 2);

se dá napsat na jeden řádek třeba jako

$minute = round(abs((int) $last_access->format('U') - (int) (new \DateTimeImmutable())->format('U')) / 60, 2);

(aneb když máš DateTimeInterface, je zbytečné jej převádět na string v divném formátu a z něj zpětně vyrábět unixový timestamp).
A pokud to pak jen porovnáváš s číslem 20 (a nikde vypočtenou hodnotu nevypisuješ), tak ani to zaokrouhlení není potřeba.

Každopádně tohle je přesně typ kódu, který v šabloně nechceš řešit, protože v presenteru:

  • si (aktuální) čas získáš přes službu z DI kontejneru místo „netestovatelného“ new \DateTime()
  • hodnotu 20 uložíš do nějaké rozumně pojmenované konstanty (např. LAST_ACCESS_THRESHOLD_MINUTES, případně „po novu“ LastAccessThresholdMinutes) a nebudeš mít pak v kódu magické číslo 20
  • PHPStorm (či jiné IDE) ti pak snadno ukáže, že řádek $accessText = ''; je zcela zbytečný
Čamo
Člen | 798
+
+1
-

@nightfish Ano medzičasom som si to všimol aj ja a upravil som to získavanie timestampu. Ale to nieje môj kód…
PS Existuje metoda DateTime::getTimestamp() čo je ešte čitateľnejšie ako format(U).

m.brecher
Generous Backer | 863
+
+1
-

@Čamo

Když už @nightfish odbočil k tématu kvality kódu, tak já bych doplnil poznámku k architektuře kódu.

Problém který řešíš v šabloně v bloku makra {php} se vyskytuje často – převést nějaký stav business logiky do vizuální podoby. Já se v takovém případě snažím:

  • oddělit business logiku od konkrétní vizuální podoby
  • vizuální podobu (css třídy, textové popisky) mít v šabloně
  • business logiku mít reprezentovanou stavovými parametry – boolean/enum
  • business logiku mít v modelové třídě (domain model – pattern)
  • alternativně mít business logiku v presenteru (anemický model – antipattern) – malé weby

Makro {php} by se mělo používat jen vyjímečně a podobné případy jako řešíš Ty rozčlenit jak je popsáno výše a v šabloně nastavovat css/texty v tagu {var} který je pro to i navržen.

Tvoje tlačítka mají 3 stavy, které by mohl reprezentovat např. bool parametr $isDeviceOnline – true|false|null

V šabloně převedeš stavový parametr na vizuální podobu:

{var
    $buttonCss = match($isDeviceOnline){
		true => 'btn-success',
        false => 'btn-warning',
        null => '',
    },
    $buttonCaption = match($isDeviceOnline){
		true => 'device.online',
        false => 'device.offline',
        null => 'device.never_connected',
    }
}

A business logika, kterou máš v bloku {php} se zapouzdří do metody modelové třídy:

class DeviceModel
{
    public const int LastAccessThresholdMinutes = 20;

    public function isOnline(): bool|null
    {
	    //.....
	}
}

presenter už pak jenom předá business logiku do šablony:

$this->getTemplate->isDeviceOnline = $this->deviceModel->isOnline();

Je to nepatrně více kódu, ale správně strukturované a přehledné. Anemický model (model bez business logiky) se v Nette aplikacích používá celkem často a použít se samozřejmě dá – ideálně v úplně jednoduchých aplikacích. Jakmile jde složitost aplikace nahoru, tak se 100% vyplatí doménový model, kde je business logika v modelu.

Sám správně píšeš:

Ja som to chcel dostať do šablony lebo celý ten kód sa týka zafarbenia buttonov. Nepáčilo sa mi že to bolo v presenteri. Tak som to zjednodušil a časť mám v presenteri a čast v šablone.

Přesně tak. Vizuální stránka business logiky má být v šabloně, zatímco business logika samotná v modelu. Presenter je potom čistý a soustředí se na řízení – tj. podobně jako controller ve standardním MVC modelu.