Route – deklarace parametru obsahující lomítka

Tento článek ukazuje, jak vytvořit routu, která akceptuje lomítka v url, například pro stahování souborů nebo hiarchickou navigaci. Využijeme k tomu třídu Nette\Application\Routers\Route.

Vychází z tohoto tématu na fóru. Také se snažím vysvětlit rozdíly mezi jednotlivými zápisy a vysvětlit trochu práci s metadaty parametrů třídy Route.

Cíl

Chceme, aby URL http://server.com/produkty/elektro/zarovky/ se přeložilo na Nette\Application\Request s parametry:

Presenter Page
action default
node produkty/elektro/zarovky/

Začínáme

Nastavíme router. Zkusíme toto:

$Ro[] = new Route("<node>", [
    "presenter" => "Page",
    "action" => "default",
]);

Jen připomenu část citátu : „but still voodoo“

Bohužel to nyní nejde. Pohledem do api Nette\Application\Routers\Route::$styles zjistíme, že výchozí nastavení (styl) pro parametry v cestě(kromě presenter, action a parametrů v querystringu) má metadata, která se nehodí pro náš parametr.

  • výchozí vzor=PATTERN neakceptuje lomítka. Na vhodném místě v kódu ho měníme ho tedy na .*
  • Ani tak to nebude fungovat – lomítka se totiž převedou na %2F – díky FILTER_OUT. Taktéž na vhodném místě změníme funkci: na funkci, která vrací řetězec, který dostane. Ovšem pokud místo funkce uvedeme null, tak dosáhneme stejného efektu.

Připomenu, co to jsou metadata. To jsou de facto vlastnosti daného PARAMETRu v Routě. Jsou to tyto

význam zápis hodnota konstanty datový typ
výchozí hodnota Route::VALUE value string
regulerní výraz Route::PATTERN pattern string
vstupní filtr Route::FILTER_IN filterIn funkce
výstupní filtr Route::FILTER_OUT filterOut funkce
filtrovací(překladová) tabulka Route::FILTER_TABLE filterTable pole
interní – nepoužívat není, fixity  

Ty se uvádějí těmito způsoby(pro parametry v query stringu platí jinačí pravidla):

  • v definici parametru v masce přímo v ostrých závorkách <PARAMETR[=VALUE] [PATTERN] [#class]> Class popíšu dále,
    • – tímto způsobem nelze přímo v masce určit filtry a překladovku.
  • v druhém parametru konstruktoru Route, což je pole(jmenuje se $metadata), kde klíče jsou názvy PARAMETRů. Dále se to liší, zda je hodnotou pole nebo string.
    • pole: ‚node‘=>Route::VALUE=>…,Route::FILTER_TABLE=>…. Danému parametru přiřazujeme metadata z tabulky výše.
      • jako podmožnost uvádím, kdy metadata se určí staticky pro daný parametr. Viz možnost 3.
    • string:pokud uvedeme 'node'=>"about-us", tak se to pokládá za výchozí hodnotu. Jinými slovy se to převede na 'node'=>[Route::VALUE=>"about-us"]
  • Pomocí class: class neboli styl jsou defacto připravená sada hodnot VALUE, PATTERN, FILTRů nebo překladové tabulky. Její ukázka bude v 4. možnosti.

Pozor: gramaticky se deklarace stylu liší jen o křížek, ale možnost bez křížku platí pro daný parametr zatímco s křížkem platí pro parametry, které označíme takto: <jmeno #style1>/<akce #style1>

Viz Nette\Application\Routers\Route::VALUE

Řešení

Vždy sledujeme, abychom nastavili dvě věci: PATTERN .* a FILTER_OUT.

1)

Uvedeme obojí v poli metadata.

$router[] = new Route("<node>", [
    "presenter" => "Page",
    "action" => "default",
    "node" => [
        Route::FILTER_OUT => function ($uri) { return $uri; },
        Route::PATTERN => ".*",
    ],
]);

1a)

Totéž, jen filtr změníme na null. Taky pattern .* je nahrazen .*?, takže zmizí poslední lomítko.

$router[] = new Route("<node>", [
    "presenter" => "Page",
    "action" => "default",
    "node" => [
        Route::FILTER_OUT => null, // to má stejný efekt: přebije se výchozí hodnota rawurlencode,
                                   // ale nevyhoví podmínce isset(), tudíž se parametr nezmění
        Route::PATTERN => ".*?",
    ],
]);

2)

PATTERN jsme přesunuli rovnou do deklarace masky. Stejná funkčnost.

$router[] = new Route("<node .*>", [
    "presenter" => "Page",
    "action" => "default",
    "node" => [
        Route::FILTER_OUT => null,
    ],
]);