Jak wrócić do wcześniejszej strony?

Co się stanie, jeśli użytkownik wypełnia formularz, a w międzyczasie wygaśnie mu sesja logowania? Żeby nie stracił danych, możemy przed przekierowaniem na stronę logowania zapisać bieżące żądanie (łącznie z danymi formularza) do sesji. W Nette jest to zaskakująco proste.

Bieżące żądanie zapiszemy do sesji metodą storeRequest(). Metoda zwraca unikalny identyfikator (krótki ciąg znaków) zapisanego żądania. Zapisuje nazwę bieżącego presentera, jego widok oraz parametry. Jeśli w ramach żądania został wysłany formularz, zapisywane są także wartości wpisane w polach (z wyjątkiem wysłanych plików).

Żądanie przywracamy metodą restoreRequest($key), której przekazujemy wcześniej otrzymany identyfikator. Metoda przekieruje użytkownika z powrotem do pierwotnego presentera i widoku. Jeśli jednak zapisane żądanie zawierało wysłanie formularza, restoreRequest() zamiast przekierowania użyje metody forward(). Wcześniej wypełnione wartości przekaże z powrotem do formularza i pozwoli go ponownie wyrenderować. Dzięki temu użytkownik może wysłać formularz jeszcze raz, nie tracąc żadnych wpisanych danych.

Co ważne, restoreRequest() sprawdza, czy nowo zalogowany użytkownik to ten sam, który pierwotnie wysłał formularz. Jeśli to ktoś inny, zapisane żądanie nie zostanie przywrócone, a metoda nic nie zrobi, co zwiększa bezpieczeństwo.

Pokażmy to na przykładzie. Mamy AdminPresenter, w którym edytuje się dane. Jego metoda startup() sprawdza, czy użytkownik jest zalogowany. Jeśli nie, przekierowuje go do SignPresenter. Jednocześnie zapisujemy bieżące żądanie metodą storeRequest() i przekazujemy jego klucz ($backlink) do SignPresenter.

class AdminPresenter extends Nette\Application\UI\Presenter
{
	protected function startup()
	{
		parent::startup();

		if (!$this->user->isLoggedIn()) {
			$this->redirect('Sign:in', ['backlink' => $this->storeRequest()]);
		}
	}
}

SignPresenter będzie zawierał oprócz formularza logowania także trwały parametr $backlink, w którym przechowywany jest klucz. Ponieważ parametr jest trwały, jego wartość zostanie zachowana także po wysłaniu formularza logowania.

use Nette\Application\Attributes\Persistent;

class SignPresenter extends Nette\Application\UI\Presenter
{
	#[Persistent]
	public string $backlink = '';

	protected function createComponentSignInForm()
	{
		$form = new Nette\Application\UI\Form;
		// ... dodajemy pola formularza ...
		$form->onSuccess[] = $this->signInFormSuceeded(...);
		return $form;
	}

	private function signInFormSuceeded($form)
	{
		// ... tutaj logujemy użytkownika ...

		$this->restoreRequest($this->backlink);
		$this->redirect('Admin:');
	}
}

Metodzie restoreRequest() przekazujemy klucz ($this->backlink) zapisanego żądania. Ta następnie przekieruje (lub przeforwarduje) użytkownika z powrotem do pierwotnego presentera i widoku.

Jeśli jednak klucz jest nieprawidłowy (np. wygasł już z sesji), metoda nic nie zrobi. Kolejne wywołanie $this->redirect('Admin:') działa więc jako zabezpieczenie i przekieruje na stronę domyślną, na przykład AdminPresenter.