Persistentní parametry a kanonikalizace
- Filip Procházka
- Moderator | 4668
Zdravím,
jelikož můj pull leží na githubu od únoru netknutý, dovolím si
připomenout jeho účel.
https://github.com/…tte/pull/203
Souvislosti
Každý někdy použil persistentní parametr. Router se chová tak, že když má nějaký persistentní parametr a má v současném requestu výchozí hodnotu
/** @persistent */
public $page = 1;
a pokud není uvedeno jinak, do url ho nepředá. Proto je potřeba, pokud chcete, aby se zobrazovala i stránka č.1 ze stránkování, parametru výchozí hodnotu neudávat, nebo upravit router, aby s tím počítal
$router[] = new Route('/presenter/action/[!<page>]', ...
pomocí „vynucení přítomnosti parametru v URL“
Takováto URL pak vždy bude obsahovat alespoň tu jedničku. Pokud by byl router nastaven jako
$router[] = new Route('/presenter/action', ...
Pak budou cesty vypadat takto
'/homepage/default' # page bude 1
'/homepage/default?page=2' # page bude 2
Presenter se snaží automaticky kanonikalizovat URL (což jde vypnout), takže pokud se dostanu na stránku
'/homepage/default?page=1' # page bude 1
přesměruje mě na
'/homepage/default' # page bude 1
Hluboko
uvnitř frameworku, je metoda, která dokáže z komponenty (které dědí
od PresenterComponent
) vytáhnout persistentní parametry a jejich
výchozí hodnoty.
Tato metoda se také v důsledku stará o to, aby když máte 3 presentery
A
, B
, C
class A extends Nette\Application\UI\Presenter
{
/** @persistent */
public $page = 1;
}
class B extends A { }
class C extends A { }
Tak pokud přecházím mezi těmito třemi presentery, persistentní parametr
$page
se drží mezi jednotlivými požadavky a hodnota se
přenáší, protože byl definován v předku A
a tato podmínka
se uplatňuje při vyhodnocování, které parametry se mají předat.
Jak je možné si všimnout, v třídě PresenterComponentReflection, je několikrát TODO a je vcelku jasné, že David zamýšlí, až to bude na pořadí, se nad implementací zamyslet a trochu ji doladit, protože není ideální.
Konkrétní problém
Současná implementace totiž nepočítá se situací, kdy bych chtěl mít
v presenteru B
jinou výchozí hodnotu persistentního
parametru $page
class B extends A
{
/** @persistent */
public $page = 2;
}
Díky kanonikalizaci a skrývání parametru pomocí výchozí hodnoty, není možné dostat se na stranu 1.
Protože vždy, mám buď v url rozdílnou hodnotu (2) oproti presenteru,
který definuje výchozí hodnotu (A
= 1), nebo mám
zkanonikalizovanou, ale reálně opět obsahu hodnotu 2.
Protože kanonikalizace proběhla na hodnotu prvního definujícího (1), ale výchozí se bere z presenteru (2).
Rešení
Velice jednoduchou úpravou, která je otestována a funguje, se toto dá napravit.
Reflexe bude vracet reálnou výchozí hodnotu, ale pořád bude zachovávat informaci, který presenter definoval parametr jako první. Zachová se proto pravidlo přenášení persistentních parametrů a zároveň se odstraní chyba s kanonikalizací
- Ondřej Mirtes
- Člen | 1536
Uvítal bych, kdyby se tu pohly ledy, ale nejsem si jistý, zdali ten parametr v presenteru B nepovažovat za nový a tudíž ho z dalších potomků A nepřenášet.
- JakubJarabica
- Gold Partner | 184
dg merged 1 commit into nette:master from HosipLan:bug-persistent-params 20 days ago
…?
- Filip Procházka
- Moderator | 4668
To právě nedává smysl :) Zkoušel jsem to v praxi a lepší (přirozenější) je když se to chová takto. A navíc, už je to nějakej ten pátek merged :)