$presenter->isLinkCurrent() a FILTER_OUT

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
petr.pavel
Člen | 535
+
0
-

Zdarec,
zdá se, že nastavení $current v Presenter::createRequest(), část zpracovávající $args, nespolupracuje s routerem a jeho filtry.

Řádka 945 ve \Nette-2.2.2\Nette\Application\UI\Presenter.php. (Na API prokliknout nemůžu, protože celý createRequest() chybí.)

Akci prezenteru předávám slug, který je vytvořen pomocí FILTER_OUT ze jména přes Strings::webalize().
Link se vyrobí správně, ale nenastaví se $current, takže isLinkCurrent() a ifCurrent nefungují.

Nebo mi něco uniklo?

Ochcat se to dá řím, že místo prostého $presenter->linkCurrent vyjmenuji jeho cíl i parametry, a parametr jméno nejdřív proženu webalize. To samé pak musím zopakovat u jiného parametru, který mi za určitých okolností FILTER_OUT NULLuje.

Kromě toho, že je výsledek dlouhý jak prase, duplikuju tím funkčnosti filtrů routeru, což je nesmysl.

Jak to děláte vy?

Už tady padly dva dotazy na stejné téma a bez odezvy. Doufám, že budu mít víc štěstí.
https://forum.nette.org/…icke-stranky
https://forum.nette.org/…stni-chovani

petr.pavel
Člen | 535
+
0
-

Tak co? Nikdo nepoužíváte isLinkCurrent() a filtry v routeru? To bych se divil… :-)

Tomáš Votruba
Moderator | 1114
+
0
-

Ahoj, mne by pomohl zadouci kod a nutny kod, abych to mohl snadno nasimulovat. Slovni kod me odrazuje.

petr.pavel
Člen | 535
+
0
-
<?php
  public function createRouter()
  {
    Route::addStyle('slug');
    Route::setStyleProperty('slug', Route::FILTER_OUT, function($text) {
      return Strings::webalize($text);
    });

    $router = new RouteList();
    $router[] = new Route('<presenter>/<action>/<slug>', 'Homepage:default');
}

class HomepagePresenter extends BasePresenter
{
	public function renderDefault($slug) {}
}
?>
{var $nazev = "Slovní kód odrazuje"}
<a n:href="Homepage:default $nazev" n:class="$presenter->linkCurrent ? funguje">odkaz jinam</a>
Toto {ifCurrent Homepage:default $nazev}je{else}není{/ifCurrent} aktuální stránka.

Vzniklý odkaz (/homepage/default/slovni-kod-odrazuje) nemá třídu funguje, přestože to je adresa aktuální stránky. Věta pod ním vyjde jako „Toto není aktuální stránka.“.

petr.pavel
Člen | 535
+
0
-

Mimochodem, to samé, pokud je routa definovaná bez masky:

<?php
    $router[] = new Route('<presenter>/<action>/<slug>', array(
      'presenter' => 'Homepage',
      'action' => 'default',
      'slug' => array(
        Route::VALUE => null,
        Route::FILTER_OUT => function($text) {
          return Strings::webalize($text);
        },
      )
    ));
?>
David Matějka
Moderator | 6445
+
0
-

budes si muset vymyslet alternativni zpusob kontroly, zda jsou linky stejne. Pri kontrole pomoci isLinkCurrent se to do routeru vubec nedostane

Editoval matej21 (25. 8. 2014 19:00)

petr.pavel
Člen | 535
+
0
-

matej21 napsal(a):

budes si muset vymyslet alternativni zpusob kontroly, zda jsou linky stejne. Pri kontrole pomoci isLinkCurrent se to do routeru vubec nedostane

createRequest() jsem studoval – relevantní je spíš řádka 948. Jen jsem doufal, že mi něco uniklo.

Za mě je tohle chyba a divím se, že to dosud nikomu nevadilo.

Tomáš Votruba
Moderator | 1114
+
0
-

@petr.pavel Jestli víš, jak ji odstranit, pošli PR.

Co je vlastně cílem? Zvíraznit aktivní stránku? U ní případně můžeš porovat ID/slug, pracovat tedy s $activePage/$activeCategory.

Jinak addStyle je deprecated, tak pozor na použití.

petr.pavel
Člen | 535
+
0
-

Ano, potřebuji zvýraznit aktuální stránku.

Nepochopil jsem, co přesně navrhuješ. Mohl bys nastřelit v pseudo-kódu, jak by vypadala tahle řádka?
<a n:href=„Homepage:default $nazev“ n:class=„$presenter->linkCurrent ? funguje“>odkaz jinam</a>

deprecated addStyle: No to je paráda. Netušíš, kde bych se dočetl, jak to dělat ponovu? Dokumentace mlčí, ve fóru to nikdo zatím neprobíral. Chtělo by to zavést pravidlo, že se do Nette nesmí nic přidat, pokud autor současně nedoplní dokumentaci.

enumag
Člen | 2118
+
+1
-

@petr.pavel: Chyba to není jen to používáš nesmyslně. Prostě už v šabloně když vytváříš odkaz předávej slug a ne name. Když používáš slug v URL tak podle něj pak tu entitu potřebuješ najít. Tzn. zřejmě už v db máš sloupec slug takže by to neměl být problém.

David Matějka
Moderator | 6445
+
0
-

deprecated addStyle: zatim je to deprecated jen v dev (a bude asi v pristi stable). Ja jsem to nikdy nepouzil – vzdy nastavuji filtry konkretni route

jinak imho to vyresit nepujde. Filtry by teoreticky mely byt obousmerne – tedy FILTER_OUT to predela do url podoby a FILTER_IN do toho, co chce aplikacni request, potazmo presenter. tak to resim i ja – v presenterech/sablonach vsude posilam entitu a routa si z toho vezme slug/id nebo co potrebuje. Pri matchovani requestu zas dle id/slugu vybere entitu.

petr.pavel
Člen | 535
+
0
-

@enumag: Slug vytvářím dynamicky, unikátnost je již u názvu. Mám špatné zkušenosti se samostatnou definicí slugu, uživatelé ji zapomínají aktualizovat. Na SEO kašlou. Mohl bych slug aktualizovat automaticky, ale současné řešení přes styly a routy mi přijde elegantnější. Jaký máš důvod pro tvrzení, že je moje použití nesmyslné?

David Matějka
Moderator | 6445
+
0
-

jak potom vybiras dle slugu, kdyz mas v databazi normalni verzi a pro where mas webalized verzi? jak resis unikatnost?

Editoval matej21 (26. 8. 2014 12:53)

petr.pavel
Člen | 535
+
0
-

@matej21: Měl jsem za to, že FILTER_OUT a FILTER_IN jsou sice párové, ale na sobě nezávislé. Tj. můj problém by přidání FILTER_IN nevyřešilo. Jestli jsem to špatně pochopil, můžeš mi to vysvětlit?

David Matějka
Moderator | 6445
+
0
-

ano, jsou na sobe nezavisle, ale z principu by presenter, sablony atd. nemely o konkretnich pravidlech routovani vedet (a tedy ze si routovani nejak prevadi vstupy/vystupy).

Kdyz bych tedy do constructUrl poslal nejakej request, to mi vratilo url a tu url poslal do match, mel bych dostat zpet stejny request.

Editoval matej21 (26. 8. 2014 13:02)

petr.pavel
Člen | 535
+
0
-

jak potom vybiras dle slugu:

Tabulka má čtyři řádky a vždycky potřebuji načíst všechny (z jiného důvodu). Takže vyhledávání dělám přes smyčku v PHP a webalize.

David Matějka
Moderator | 6445
+
0
-

@petr.pavel aha, trochu prasarnicka, no :) jako mas tam problem s tim, ze url nejsou persistentni (pri zmene nazvu je to na jine url) apod.

ale kdybys pridal filter_in a vstupni slug vymenil za ne-webalizovany nazev, tak by to melo vyresit tvuj problem s isLinkCurrent

petr.pavel
Člen | 535
+
0
-

Kdyz bych tedy do constructUrl poslal nejakej request, to mi vratilo url a tu url poslal do match, mel bych dostat zpet stejny request.

Proč by to tak mělo být?

Presenter ve createRequest() volá router->constructUrl(), ten se mu stará o routování. Bohužel ale až poté, co předtím presenter vyhodnotil, zda je request na aktuální stránku nebo ne. Podle mě je jen potřeba vyhodnocení provést až na základě url a ne nějakým jednotlivým porovnáváním napůl zpracovaných parametrů. Nechápu ale, proč to takhle autor už neudělal, nějaký důvod pro to mít musel.

Jediný nedostatek takového řešení vidím v případě, že různé requesty se stejným url budou všechny vyhodnocené jako „current“. Nevidím ale, proč by to mělo vadit.

petr.pavel
Člen | 535
+
0
-

ale kdybys pridal filter_in a vstupni slug vymenil za ne-webalizovany nazev, tak by to melo vyresit tvuj problem s isLinkCurrent

Kdybych tam neměl ještě ten další parametr, který ve FILTER_OUT zpracovávám, tak bys měl pravdu.
(Parametr sezóna, který za určitých okolností NULLuji.)

David Matějka
Moderator | 6445
+
0
-

Proč by to tak mělo být?

vzdyt to tam pisu, presenter by nemel vedet o pravidlech routovani.
V presenteru pracuju treba s entitou, kterou posilam routeru. Me by vubec nemelo zajimat, co s tim routovani dela.

Bohužel ale až poté, co předtím presenter vyhodnotil, zda je request na aktuální stránku nebo ne. Podle mě je jen potřeba vyhodnocení provést až na základě url a ne nějakým jednotlivým porovnáváním napůl zpracovaných parametrů

ty parametry jsou zcela zpracovane v ramci aplikacniho requestu. Kdyby ti router ve FILTER_IN vyhazoval stejny request, se kterym pracujes v presenteru, tak by nikde problem nebyl

petr.pavel
Člen | 535
+
0
-

Proč je „správné“ mít FILTER_IN i FILTER_OUT:
Asi jsme se nepochopili. Nepotřebuji, aby presenter něco věděl o routování. Nevidím ale důvod, proč by mělo platit, co říkáš o request1 → url → match → request2 == request1.

Kdyby ti router ve FILTER_IN vyhazoval stejny request, se kterym pracujes v presenteru, tak by nikde problem nebyl

Jednak si nejsem jistý, jestli máš pravdu, ale i kdyby: považuju to za workaround (vochcávku), ne za řešení.

Editoval petr.pavel (26. 8. 2014 13:36)

David Matějka
Moderator | 6445
+
0
-

Nevidím ale důvod, proč by mělo platit, co říkáš o request1 → url → match → request2 == request1.

mohlo by to zpusobit problemy s kanonizaci url a zpusobuje to tvuj problem. V tom druhem requestu by byly videt pravidla routeru, tedy webalizovana url apod. Tyhle upravy parametru jsou proste veci routeru a presenter by o nich nemel nic vedet.

btw, jak si rikal,

Takže vyhledávání dělám přes smyčku v PHP a webalize.

to znamena, ze presenter vi o routovani. Vi, ze ty sice do constructUrl posles „normalni“ nazev, ale router to webalizuje

porovnani url by asi nebylo resenim, ta soucasna kontrola, zda je link aktualni, probiha trochu volneji – kdyz neposles parametry, kontroluje se pouze presenter a akce, kdyz posles parametry, kontroluje se pouze shoda tech danych parametru

petr.pavel
Člen | 535
+
0
-

Máš recht, že to vyhledávání v PHP ve smyčce v presenteru není košér. Problém s porovnávání url chápu, máš pravdu, takhle by to nešlo.

Pojďme probrat ten druhý parametr.

<?php
    Route::addStyle('season');
    Route::setStyleProperty('season', Route::PATTERN, '(\d{4}|)');  // match a year or NULL
    Route::setStyleProperty('season', Route::FILTER_OUT, function($season) use ($seasonModel) {
      return $seasonModel->getCurrentSeason() == $season ? null : $season;
    });
    $router[] = new Route('[<season>/]events/<slug>', 'Tournament:detail');
?>

Tahle konstrukce mi zaručí, že se /2014/events/slug přesměruje na /events/slug a že parametr $season má hodnotu jen v případě, že se jedná o archiv. V tomhle použití filtru je taky nějaký problém?

David Matějka
Moderator | 6445
+
0
-

tohle by asi bylo lepsi resit defaultni hodnotou „season“, ktera by byla rovna $seasonModel->getCurrentSeason()

petr.pavel
Člen | 535
+
0
-

Jak zajistíš to přesměrovávání, aniž bys duplikoval routy? Je jich hodně, různé presentery.

Edit: Asi bych měl přesněji formulovat otázku:
Jak doplnit FILTER_IN, aby se splnilo tvoje pravidlo o zrcadlové funkci FILTER_IN a FILTER_OUT, a současně se pro aktuální sezónu rok v url neobjevil.

Editoval petr.pavel (27. 8. 2014 0:50)

David Matějka
Moderator | 6445
+
0
-

jaky presmerovani? jako ze po zadani /2014/events/slug to presmeruje na verzi bez roku? imho by to mela zvladnout kanonizace v presenteru…

petr.pavel
Člen | 535
+
0
-

Ano. Co to je kanonizace v prezenteru? Znám jen kanonizaci v routeru.

Považuji tohle za otázku routování, takže jak jsme se shodli :-), presenter by se o to starat neměl.

enumag
Člen | 2118
+
0
-

petr.pavel napsal(a):
@enumag: Jaký máš důvod pro tvrzení, že je moje použití nesmyslné?

Odpověděl sis sám:

petr.pavel napsal(a):
Takže vyhledávání dělám přes smyčku v PHP a webalize.

Slug je ideální aktualizovat při každé změně názvu automaticky a ukládat do samostatného sloupce. Ještě ideálnější je uchovávat i staré slugy pro one-way routu aby se staré url přesměrovaly na nové.

petr.pavel napsal(a):
Ano. Co to je kanonizace v prezenteru? Znám jen kanonizaci v routeru.

Kanonizace v presenteru je automatické přesměrování na kanonickou URL pro danou stránku. V podstatě jde o to že když na stejnou stránku vede více adres tak metoda canonicalize ti zajistí že se všechny přesměrují na jednu.

Mimochodem co je kanonizace v routeru zůstává záhadou pro změnu mně takže mne pouč. ;-)

Editoval enumag (27. 8. 2014 1:11)

petr.pavel
Člen | 535
+
0
-

přesměrování na kanonickou url:
Tak to mluvíme o tom samém. Sice to vykonává metoda presenteru ale podle definic v routeru. Jen jsem si chtěl být jistý, že @matej21 nenavrhoval něco jako if ($season == $default) $this->redirect().

Takže pořád zůstává otázka, jak řešit přesměrovávání při aktuální sezóně, aby mi fungoval $isCurrentLink a aniž bych něco musel prasit v presenterech.

Aby bylo jasno: mě to přesměrování funguje (díky nullování ve FILTER_OUT), jen nefunguje ten $isCurrentLink (tj. nastavení $current v $presenter->createRequest()).

OT: Měli bychom spíš měli říkat kanonikace (canonicalization) než kanonizace (canonization). Aby si to někdo nepletl se svatořečením.

Edit: Koukám, že pár lidí používá kanonikalizace, což dává větší smysl než kanonizace. Kdyby tak existovalo něco pěkně českého.

Editoval petr.pavel (27. 8. 2014 14:26)

David Matějka
Moderator | 6445
+
0
-

ne, pouzij defaultni hodnotu, treba takhle:

$router[] = new Route('[<season>/]events/<slug>', array(
	'presenter' => 'Tournament',
	'action' => 'detail',
	'season' => ziskej_defaultni_season(),
));

OT: Měli bychom spíš měli říkat kanonikace (canonicalization) než kanonizace (canonization). Aby si to někdo nepletl se svatořečením.

lol :))

David Matějka
Moderator | 6445
+
0
-

@petr.pavel no i kdyz.. wiki mluvi o kanonizaci: https://cs.wikipedia.org/wiki/Kanonizace_(informatika)

Editoval matej21 (27. 8. 2014 14:41)

petr.pavel
Člen | 535
+
0
-

Kanonizace v tomto významu je široce používaný pojem, což ale nemusí vypovídat o jeho správnosti.
Kanonikaci nikdo nepoužívá (Google nic nenajde), pár lidí (i tady na fóru) používá kanonikalizace.
Zítra zavolám do Ústavu pro jazyk český a dám vědět.

Jinak díky, pánové, za asistenci a trpělivost.

Tomáš Votruba
Moderator | 1114
+
+1
-

Škoda, že už to není otázka, ale táhlá diskuse. Teď pro nově příchozí není jasné, jak situaci řešit a budou základát nová témata.

Jestli jste k něčemu došli, mohl bys to Petře nějak zvýraznit (editovat první příspěvek/ztučnit…)?

Aurielle
Člen | 1281
+
+3
-

Co tak vidím, tak to stále nefunguje a @petr.pavel si nenechá poradit správné řešení s ukládáním slugu do databáze a FILTER_IN.

petr.pavel
Člen | 535
+
0
-

Ano, stále nefunguje, ale aspoň už pouze kvůli slugu. Výchozí hodnota pro sezónu funguje a zdá se mi čistší než moje původní úprava ve filtru.

Těžko se mi vyhodnocuje, co je osobní zvyk, dojem programátora, a co záměr autorů frameworku. V dokumentaci se nepíše, že by musely být filtry vždy zrcadlové.
Chápu, že to působí pěkně vyrovnaně, což někoho může vést k dojmu, že to je jediný správný způsob použití. Jestli to tak ale opravdu je, to nevím.

Souhlasím, že můj způsob řešení slugu v případě, který jsem uvedl, není nejčistší. Mám ale i jiné slugy, třeba profil uživatele:

<?php
    $router[] = new Route('players/<id [0-9]+>/<firstNameSlug>-<lastNameSlug>', 'Player:profile');
?>

V presenteru vyhledávám pouze podle id, slugy tam jsou kvůli lidem a SEO. A je pohodlné vyrábět odkaz pomocí křestního a příjmení v původní podobě a nestarat se, do čeho jsou převáděny kvůli adrese.
Netvrďte mi, že „správné řešení“ ™ je zde extra položka v databázi, kterou aktualizuji při přejmenování uživatele, a FILTER_IN, který podle slugů vrací křestní a příjmení, které nepotřebuji.

V tomto případě naštěstí nepotřebuji zvýrazňovat aktuální stránku, takže debata je čistě akademická.

Editoval petr.pavel (29. 8. 2014 11:25)

petr.pavel
Člen | 535
+
0
-

Ač je teď už debata akademická, kdybyste měl někdo chuť poradit, jak „správně“ řešit to url se slugy, které nepotřebuji, tak dejte vědět.

enumag
Člen | 2118
+
+2
-

Ono v těchto případech je lepší nepředávat do presenteru ani ID ani slug ale rovnou celou entitu. Tzn. celé to <id [0-9]+>/<firstNameSlug>-<lastNameSlug> by byl jeden parametr. Ve FILTER_IN by sis z toho vyříznul ty čísla na začátku a vytáhl z db entitu. Ve FILTER_OUT bys pak z té entity ty slugy snadno poskládal.

EDIT: A ano, reálně to používám jen to nedělám přes ty filtry v routeru ale trochu jinde (což není až tak podstatné).

Editoval enumag (1. 9. 2014 16:11)

petr.pavel
Člen | 535
+
0
-

To zní rozumně, díky.

petr.pavel
Člen | 535
+
0
-

petr.pavel napsal(a):

Kanonizace v tomto významu je široce používaný pojem, což ale nemusí vypovídat o jeho správnosti.
Kanonikaci nikdo nepoužívá (Google nic nenajde), pár lidí (i tady na fóru) používá kanonikalizace.
Zítra zavolám do Ústavu pro jazyk český a dám vědět.

Jinak díky, pánové, za asistenci a trpělivost.

Volal jsem, výsledek najdete v diskusi ke stránce na Wikipedii. Tímto vás tam zvu a těším se na připomínky.

Mimochodem, dřív se tu angažoval i náš David, tak můžete kráčet v jeho šlépějích.