Persistentní parametry a kanonikalizace

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Filip Procházka
Moderator | 4668
+
0
-

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, BC

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
+
0
-

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
+
0
-

dg merged 1 commit into nette:master from HosipLan:bug-persistent-params 20 days ago

…?

Filip Procházka
Moderator | 4668
+
0
-

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 :)