$this->backlink() a ErrorPresenter
- DocX
- Člen | 154
Ahoj,
řeším následující problém: v šabloně layoutu mám několik odkazů,
které jen mění nějaké parametry a odkazují se zpět na současnou
stránku, jako například přepnutí do jiného jazyka
{link $backlink, lang=>en}
, nebo autentizační formulář.
$backlink do templatu nastavuji v BasePresenteru.
Problém nastává ve chvílí, kdy se z nějakého důvodu zobrazí
ErrorPresenter (například se 404kou). Aplikace (Application
)
v tuto chvili vytvoří vnitřne jakoby request na ErrorPresenter a spustí ho.
Ten si pak s sebou nese právě zmíněný request. To pak zbůsobí to, že se
zmíněné odkazy vygenerují ve tvaru např.
?presenter=Error&lang=en
, i když adresa byla např.
?presenter=Blabla
.
Působí to hned 2 potíže:
- na stránce je odkaz (a akce formuláře) na neexistující stránku
- zamezení přístupu ke stránkám, kde musí být uživatel přihlášen mám řešeno přes vyhození vyjímky a následné zpracování ErrorPresenterem. V tom okamžiku nefunguje přihlašovací formulář.
Otázka:
- Jak zjistit původní request (ten od klienta, ne ten co je v ErrorPresenteru při jeho běhu) a jeho backlink
- Jak backlink na ten původní request předat
AppForm
u, který si odkaz tvoří sám podle aktuálního presenteru. (když ho zadám přes->setAction()
tak se nevytvoří odkaz na signál).
EDIT: a nebo jak to řešit úplně jinak :)
Děkuji :)
Editoval DocX (20. 8. 2009 15:09)
- jasir
- Člen | 746
DocX napsal(a):
řeším následující problém: v šabloně layoutu mám několik odkazů, které jen mění nějaké parametry a odkazují se zpět na současnou stránku, jako například přepnutí do jiného jazyka
{link $backlink, lang=>en}
, nebo autentizační formulář. $backlink do templatu nastavuji v BasePresenteru.
Nemusíš přes backlink, mělo by to jít přes:
{plink this, lang=>en}
Jinak {plink}
je odkaz na presenter, {link}
je
odkaz na komponentu, v layoutu je to presenter.
- Jak backlink předat
AppForm
u, který si odkaz tvoří sám podle aktuálního presenteru. (když ho zadám přes->setAction()
tak se nevytvoří odkaz na signál).
Aktuální presenter v AppFormu
získáš pomocí
$this->getPresenter()
a linky tedy můžeš
tvořit $this->getPresenter()->link(...)
Editoval jasir (20. 8. 2009 11:50)
- DocX
- Člen | 154
jasir napsal(a):
Nemusíš přes backlink, mělo by to jít přes:
{plink this, lang=>en}
nj to jsem nevěděl :)
- Jak backlink předat
AppForm
u, který si odkaz tvoří sám podle aktuálního presenteru. (když ho zadám přes->setAction()
tak se nevytvoří odkaz na signál).Aktuální presenter v
AppFormu
získáš pomocí$this->getPresenter()
a linky tedy můžeš tvořit$this->getPresenter()->link(...)
Asi jsme se úplně nepochopili :( Já nepotřebuju měnit AppForm, a jak si on tvoří URL do action, je v pohodě.
Ale nejde tady ani tak o konkrétní případy jako jsem uvedl s odkazem a
formulářem. Problém prostě je v tom, že při chybě je spuštěn
ErrorHandler, který si myslí že na něj bylo přistoupeno přes
request Error:
. Na to se pak váží všechny linky, které
pracují s backlinkem nebo komponenty tvořící signály na aktuální
presenter. Vytvoří totiž odkazy s pořadavkem na presenter
Error
ale ten z pohledu klienta neexistuje –
v Application::run() je to speciálně ošetřeno – což je dobře. Jde mi
o to, jak donutit ErrorPresenter, aby měl v sobě původní request, který
vzešel od klienta/prohlížeče a tím by se všechny odkazy generovali na jeho
základě.
- DocX
- Člen | 154
Nechci být nevděčný, ale tohle mi přijde skoro jako bug.. Myslím, že globální linky (a jiné věci) umístěné v layoutu, které používají backlink, by neměly generovat odkazy na ErrorPresenter, když ten z pohledu uživatele neexistuje.
Co jsem koukal, tak backlink se generuje jednoduše tím, že se slepí název třídy a název action. Nešlo by to udělat tak, že by to nějak vzalo ten originální HttpRequest (který přišel od prohlížeče klienta) a ten to přepracovalo na adresu presenter:action?
Editoval DocX (20. 8. 2009 17:34)
- David Grudl
- Nette Core | 8228
Originální požadavek lze získat v error presenteru přes
$this->application->requests[0]
. Jako objekt PresenterRequest
a z něj lze vytáhnout jméno presenteru a akce.
Nicméně u formulářů je věc komplikovanější. Nenapadá mě, jak tohle čistě řešit.
- DocX
- Člen | 154
David Grudl napsal(a):
Originální požadavek lze získat v error presenteru přes
$this->application->requests[0]
. Jako objekt PresenterRequest a z něj lze vytáhnout jméno presenteru a akce.Nicméně u formulářů je věc komplikovanější. Nenapadá mě, jak tohle čistě řešit.
Když se dá takhle vytáhnout původní request, možná by stačilo
přepsat metodu backlink()
v ErrorPresenteru, tak aby vracela link
na původní presenter:action… Jdu to ozkoušet ;)
- DocX
- Člen | 154
Tak jak jsem říkal, že by to šlo úpravou
$this->backlink()
, tak jsem to zkoušel, ale Presenter tvoří
veškeré odkazy přimo pomocí $this->link()
(i linky ve
formulářích).
Nicméně, napadá mě, že by šlo udělat něco jako „nouzový
presenter“, který by se nastavil aplikaci stejně jako vlastnost
Application::errorPresenter
, na který by se právě odkazy bez
přesně zadaného presenteru vytvářely, když by byl spuštěn
ErrorPresenter. A podle toho patřičně upravit Presenter::link() nebo možná
Presenter::createRequest(), ještě nevím jak to půjde.
Zkusím se na to přes víkend kouknout :)
//EDIT: Proč vždycky píši „odkazi“, když jsou to „odkazy“? xD
Editoval DocX (21. 8. 2009 18:28)
- DocX
- Člen | 154
Tak to mám. Naučil jsem presenter změnit presenter, na který má odkazovat, když link neobsahuje kvalifikovaný název presenteru nebo když je to link na ‚this‘. Ovlivněje to jak klasické linky, tak i ty co se vytváří na AppFormu, což je paráda :)
V Nette jsem relativně začátečník a věcem co jsou v jeho jádru už vůbec moc nerozumím xD. Prosím proto, jestli by jste mi to nezkontrolovali, ale co jsem zkoušel, tak to fungovalo.
<?php
--- /Nette/Application/Presenter.php
+++ /Nette/Application/Presenter.php
@@ -131,6 +131,10 @@
/** @var array */
private $lastCreatedRequestFlag;
+ /**
+ * @var string Where link to, when link do not contain presenter name
+ */
+ private $defaultRequestPresenter = NULL;
@@ -463,6 +467,21 @@
}
+ /**
+ * Change presenter to which link links without defined presenter or links to 'this'
+ * @param string $presenter Presenter name
+ * @throws InvalidPresenterException if presenter not found
+ * @return void
+ */
+ public function setDefaultRequestPresenter($presenter)
+ {
+ if ($presenter !== NULL)
+ // try to get presenter
+ $this->getApplication()->getPresenterLoader()->getPresenterClass($presenter);
+
+ $this->defaultRequestPresenter = $presenter;
+ }
+
@@ -907,7 +926,7 @@
$a = strrpos($destination, ':');
if ($a === FALSE) {
$action = $destination === 'this' ? $this->action : $destination;
- $presenter = $this->getName();
+ $presenter = ($this->defaultRequestPresenter === NULL) ? $this->getName() : $this->defaultRequestPresenter;
$presenterClass = $this->getClass();
} else {
@@ -919,7 +938,7 @@
$presenter = substr($destination, 1, $a - 1);
} else { // relative
- $presenter = $this->getName();
+ $presenter = ($this->defaultRequestPresenter === NULL) ? $this->getName() : $this->defaultRequestPresenter;
$b = strrpos($presenter, ':');
if ($b === FALSE) { // no module
$presenter = substr($destination, 0, $a);
?>
Použít se to pak dá následovně:
<?php
class ErrorPresenter extends BasePresenter
{
function startup()
{
parent::startup();
$this->setDefaultRequestPresenter('Homepage');
}
}
?>
Potom, když se zobrazí ErrorPresenter a v @layout.phtml mám následující, nevznikne odkaz na neexistující stránku, ale naopak, kamkoli člověk klikne, dostane se minimálně na Homepage. Což myslím, že je nádhera ;)
<a href="{link this, lang => cs}">Czech</a>
<!-- odkaz bude např. /?presenter=Homepage&lang=cs (samozřejmě pokud je Homepage defaultní, nebude tam presenter vůbec ;) -->
Editoval DocX (21. 8. 2009 22:11)