Jak napsat vlastní Latte filtr v Nette?

22. 8. 2015 | #tutorial #php #nette

Někdy je vhodné si v Nette nadefinovat vlastní filtr, když nám výchozí filtry nestačí, i když se jedná o širokou nabídku rozmanitých funkcí, které v základu skutečně stačí. Dnes bych chtěl ukázat, jak si takový vlastní filtr, který zpravidla slouží k úpravě vstupu do nějaké cílové podoby, napsat.

Filtry se registrují do šablony a vždy lze registrovat anonymní funkci nebo callback. Níže následuje ukázka registrace jednoduchého filtru, který vrátí absolutní hodnotu čísla. Filtr je zpravidla vhodné registrovat v metodě beforeRenderBasePresenteru nebo v nějaké továrničce šablony.

...
    protected function beforeRender()
    {
        $this->template->addFilter('abs', function ($number) {
            return abs($number);
        });
    }
...

Filtr pak použijeme tak, jak jsme zvyklí:

{$number|abs}

Myslím, že použití je dost přímočaré a můžeme pokročit.

Na základě komentáře z diskuse od Aurielle (díky) si dovolím ještě doplnit jeho ukázku registrace filtru přímo v configu, která je také dost šikovná:

services:
    nette.latteFactory:
        setup:
            - addFilter(abs, @petrjirasek\Latte\AbsFilter)

    - petrjirasek\Latte\AbsFilter

Oddělený filtr ve vlastní třídě

Osobně mám rád ve věcech pořádek, proto není od věci si filtry psát odděleně a moci je pak snadněji přenášet. Jednoduchý filtr absolutní hodnoty by tedy mohl odděleně vypadat takto:

<?php

namespace petrjirasek\Latte;

use Nette\Object;


class AbsFilter extends Object
{

    /**
     * @param int $number
     * @return int
     */
    public function __invoke($number)
    {
        return abs($number);
    }
}

Můžeme si všimnout, že byla použita magická metoda __invoke, která nám umožní volat objekt jako funkci. Při registraci pak stačí inicializovat třídu filtru.

use petrjirasek\Latte\AbsFilter;
...
    protected function beforeRender()
    {
        $this->template->addFilter('abs', new AbsFilter);
    }
...

Filtr se závislostmi

Někdy může filtr disponovat závislostmi a vyžadovat některé služby v jeho konstruktoru. V praxi se může jednat o situaci, kdy nějaký filtr potřebuje svůj výstup cachovat nebo používá službu, která daný vstup převádí na požadovány výstup. Jelikož se asi nikomu nechce předávat závislosti ručně při inicializaci, je vhodné použít automatické dosazování závislosti v kombinaci s anotací @inject. Řešení pak bude vypadat takto:

use petrjirasek\Latte\AbsFilter;
...
    /** @var AbsFilter @inject */
    public $absFilter;
...
    protected function beforeRender()
    {
        $this->template->addFilter('abs', $this->absFilter);
    }
...

Také je nezbytné, aby filtr byl zaregistrován jako služba v config.neon.

services:
    - petrjirasek\Latte\AbsFilter

Při tomto řešení jsou závislosti automaticky při inicializaci předány a filtr je v pořádku zaregistrován. Jen doplním, že AbsFilter aktuálně žádnou závislost nemá, ale kdyby měl nebo kdyby jsme měli jiný filtr se závislostmi, tak by byly skutečně předány.

Tipy na filtry

Pokud vás stále nenapadá, kdy by jste mohli vlastní Latte filtr uplatnit, tak zkusím naznačit pár případu užití.

Jedním z typických příkladů je třeba konverze data do tvaru vydáno před X hodinami, před 5 dny atd. Můžete si napsat tak vlastní filtr, jehož vstupem bude instance DateTime označující například datum vydání článku a filtr při aplikací vrátí relativní vyjádření času k aktuálnímu okamžiku.

Dalším příkladem může být použití Texy. Buď dost nehezky předáte do šablony instanci Texy, zpracujete text a ještě to obalíte makrem pro cachování nebo můžete hezky vše zapouzdřit do Latte filtru, kde jednou ze závislostí bude jak Texy, tak nějaká cache, kam budete výstup pravděpodobně ukládat.

A do třetice mě napadá případ, kdy máte vícejazyčný web a datumy v nějakém vámi definovaném výchozím českém formátu. Pro každý jazyk ale může být výchozí podoba formátu různá a tak se nabízí situace, kdy filtru předáte informaci o jazyku a filtr pak bude aplikovat formát data dle daného jazyka.

A jak pracujete s filtry vy? Co se vám osvědčilo?

Diskuse

comments powered by Disqus

Tento web používá k poskytování služeb, personalizaci reklam a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte. Další informace