Nemohu zprovoznit (re)storeRequest

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

Ahoj,
chci zprovoznit restorování requestu – např. pro případ, že uživatel není přihlášený, vleze, kam guest nemá přístup, tak mu to nastaví flashMessage, že se má přihlásit, zavolá se storeRequest a přesměruje ho to na přihlašovací formulář. Při úspěšném přihlášení se zavolá restoreRequest($this->backlink()). Jenže se mi to nepřesměruje na stránku, ze které ho to vyhodilo, ale proběhne redirect, který je pod tím restoreRequest – pro případ, že není co restorovat.

Ani se mi při storeRequest nic nepřidává URL, jak by asi mělo.

Kusy kódu:

BasePresenter:

protected function startup() {
  parent::startup();
  $application = $this->getApplication();
  if (!in_array($this->getName(), array($application->errorPresenter, 'Login', 'Registration')) &&
      !Environment::getUser()->isAllowed($this->getName(), $this->getAction())) {
          if (Environment::getUser()->isAuthenticated()) throw new BadRequestException('Permission denied', 403);
          else {
		//sem se kód dostane, flashMessage se nastaví a přesměrování proběhne
              $application->storeRequest();
              $this->flashMessage('Přístup zakázán. Možná jste se zapomněli přihlásit.','error');
              $this->redirect('Login:');
          }
  }
}

LoginPresenter:

public function loginFormSubmitted(AppForm $form) {
    try {
        $values = $form->getValues();

        $user = Environment::getUser();
        $user->setExpiration($values['permanentLogin'] ? Environment::getConfig('expiration')->userPermanent : Environment::getConfig('expiration')->user,
                             !$values['permanentLogin']);
        $user->authenticate($values['login'], $values['password']);

        $this->flashMessage('Byli jste úspěšně přihlášeni!');
        $this->getApplication()->restoreRequest($this->backlink());
        $this->redirect('Default:');
    } catch (AuthenticationException $e) {
        if ($e->getCode() == IAuthenticator::IDENTITY_NOT_FOUND)
          $form->addError($e->getMessage());
        else {
          $this->flashMessage($e->getMessage(),'warning');
          $this->redirect('this');
        }
    }
}

Napadá někoho, v čem je chyba?

Revizi Nette mám nejnovější, 460.

Díky.

jasir
Člen | 746
+
0
-

Myslím, že storeRequest ti vrátí key, který si musíš poslat jako parametr do LoginPresenteru. Tam ho pak po úspěšném přihlášení použiješ při restoreRequest (ta už vyhodí ForwardingException).

Editoval jasir (24. 7. 2009 15:27)

Panda
Člen | 569
+
0
-

S ukládáním requestu se pracuje trochu jinak…

Při jeho ukládání se Ti vrátí jeho unikátní ID – když si člověk otevře několik tabů a pak zjistí, že není přihlášen, tak nechce, aby ho 5 tabů přesměrovalo na stejnou stránku, ale aby ho každý tab přesměroval tam, kam má. Takže ukládání by mělo vypadat nějak takto:

<?php
	$key = $application->storeRequest();
	$this->flashMessage('...', 'error');
	$this->redirect('Login:', $key);
?>

A v LoginPresenter:

<?php
public function renderDefault($key = NULL) {

	// ...

	if ($key) {
		$this->getComponent('loginForm')->setDefaults(array('key' => $key));
	}
}

protected function createComponentLoginForm()
{
	// ...
	$form->addHidden('key');
	// ...
}

public function loginFormSubmitted(AppForm $form) {
	// ...

	$this->flashMessage('Byli jste úspěšně přihlášeni!');
	if ($values['key']) {
        	$this->getApplication()->restoreRequest($values['key']);
	else
        	$this->redirect('Default:');

	// ...
}
?>

Pokud chceš, můžeš ještě přidat následující metodu, která uživatele přesměruje, pokud už je přihlášený (aby se nemusel přihlašovat ve všech tabech, ale jen v jednom a ostatní jen refreshnout):

<?php
public function actionDefault($key)
{
	if (Environment::getUser()->isAuthenticated()) {
		if ($key) {
        		$this->getApplication()->restoreRequest($key);
		else
        		$this->redirect('Default:');
	}
}
?>
Ondřej Brejla
Člen | 746
+
0
-

To by se mělo šoupnout do dokumentace, nebo to tu zapadne…což by byla veliká škoda…

jasir
Člen | 746
+
0
-

Panda napsal(a):

S ukládáním requestu se pracuje trochu jinak…

Proč key přidávat jako hidden form control a nenechat ho jen jako persistentní parametr LoginPresenteru?

Editoval jasir (24. 7. 2009 15:43)

Panda
Člen | 569
+
0
-

jasir napsal(a):

Proč key přidávat jako hidden form control a nenechat ho jen jako persistentní parametr LoginPresenteru?

Mno ono není ani potřeba ho dávat persistentní, stačí, když je jako parametr u action a pak ho jde kdekoliv v presenteru vytáhnout pomocí $this->getParam('key'). Osobně to do formuláře cpu jen kvůli vnitřnímu nutkání, které mi říká, že by ten key měl být k dispozici i v případě, že callback pro onSubmit vytáhnu někam mimo presenter. :-)

jasir
Člen | 746
+
0
-

Panda napsal(a):

jasir napsal(a):

Proč key přidávat jako hidden form control a nenechat ho jen jako persistentní parametr LoginPresenteru?

Mno ono není ani potřeba ho dávat persistentní, stačí, když je jako parametr u action a pak ho jde kdekoliv v presenteru vytáhnout pomocí $this->getParam('key'). Osobně to do formuláře cpu jen kvůli vnitřnímu nutkání, které mi říká, že by ten key měl být k dispozici i v případě, že callback pro onSubmit vytáhnu někam mimo presenter. :-)

Ok, dík, já si říkal jestli mi něco neuniká. S tou perzistencí máš pravdu. Ono mimochodem nejlepší je podívat se do příkladu Cd-Collection.

Editoval jasir (24. 7. 2009 16:02)

Ondřej Mirtes
Člen | 1536
+
0
-

Díky moc všem. Je pravda, že jsem tuto funkčnost neměl kde vyčíst a v akrabatu jsem tomu nějak nerozuměl, resp. mi to nefungovalo :)

jasir
Člen | 746
+
0
-

Panda napsal:
Pokud chceš, můžeš ještě přidat následující metodu, která uživatele přesměruje, pokud už je přihlášený (aby se nemusel přihlašovat ve všech tabech, ale jen v jednom a ostatní jen refreshnout):

Takhle by to asi bylo lepší, kdyby náhodou ten restoreRequest neproběhl (co já vím, schnilá session…), aby se to někam redirectovalo

<?php
 public function actionDefault($key)
 {
 	if (Environment::getUser()->isAuthenticated()) {
 		if ($key)
         		$this->getApplication()->restoreRequest($key);
		}
      		$this->redirect('Default:');
 	}
 }
?>

Editoval jasir (24. 7. 2009 16:29)

kravčo
Člen | 721
+
0
-

Podobnú situáciu riešim hodnú chvíľu aj ja. Najprv vlastný storeRequest() potom ohýbanie Application::storeRequest()… A stále s tým nie som spokojný…

Situácia je rovnaká ako opisoval LastHunter. Motivácia trochu iná, o tom viac nižšie…

  • príde požiadavka na akciu, ktorá vyžaduje autentifikáciu
  • presmerovanie na prihlasovací formulár (storeRequest+redirect)
  • odoslanie prihlasovacieho formulára (redirect)
  • obnovenie pôvodnej požiadavky (restoreRequest)

Použil som perzistentný parameter _bid :). Problém mi robili flash správy – po obnovení požiadavky som chcel oznámiť úspešné prihlásenie, no flashKey sa stratil, ak som to správne pochopil, tak kvôli kanonikalizácii.

Motiváciou mi bola vlastná skúsenosť – po odoslaní asi hodinu písaného formulára (dlhý text) mi to po odoslaní vynadalo, že nie som prihlásený – a dáta v ťahu… Po novom request uložím prihlásim sa a po jeho obnovení dáta pohodlne uložím… Pričom chcem, aby sa mi zobrazili všetky flash správy, ktoré vznikli – teda typicky správa o opätovnom prihlásení (AuthPresenter) a aj správa o úspešnom uložení dát (EditPresenter) – obe akcie sa totiž vykonali v jednom kroku (z hľadiska používateľa).

Momentálne mi to síce funguje, no musím čachrovať s flash správami a to sa mi nepáči… Vyriešil to niekto elegantnejšie?