前のページに戻るには?

ユーザーがフォームに入力している最中にログインのセッションが切れたら、どうなるでしょうか。データを失わないよう、ログインページにリダイレクトする前に現在のリクエスト(フォームのデータを含みます)をセッションに保存できます。Nette では、これが驚くほど簡単です。

現在のリクエストは storeRequest() メソッドでセッションに保存できます。このメソッドは、保存したリクエストの一意な識別子(短い文字列)を返します。現在のプレゼンターの名前、そのビュー、パラメータが保存されます。リクエストの一部としてフォームが送信されていた場合は、フィールドに入力された値(アップロードされたファイルを除きます)も保存されます。

リクエストは restoreRequest($key) メソッドで復元します。先ほど得た識別子を渡してください。このメソッドはユーザーをもとのプレゼンターとビューに戻します。ただし保存されたリクエストにフォームの送信が含まれていた場合、restoreRequest() はリダイレクトの代わりに forward() メソッドを使います。以前に入力された値をフォームに戻し、もう一度描画できるようにします。おかげでユーザーは、入力したデータを失わずにフォームを再送信できます。

重要なのは、restoreRequest() が、新しくログインしたユーザーがもとのフォームを送信したユーザーと同じかどうかを確認する点です。別のユーザーなら、保存されたリクエストは復元されず、メソッドは何もしません。安全性が高まります。

例で見てみましょう。データを編集する AdminPresenter があるとします。その startup() メソッドはユーザーがログインしているかを確かめます。していなければ SignPresenter にリダイレクトします。同時に storeRequest() で現在のリクエストを保存し、そのキー($backlink)を 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 にはログインフォームのほかに、キーを保持する永続パラメータ $backlink があります。パラメータが永続なので、ログインフォームを送信したあとも値が保たれます。

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;
		// ... フォームの項目を追加します ...
		$form->onSuccess[] = $this->signInFormSuceeded(...);
		return $form;
	}

	private function signInFormSuceeded($form)
	{
		// ... ここでユーザーをログインさせます ...

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

保存したリクエストのキー($this->backlink)を restoreRequest() メソッドに渡します。すると、ユーザーをもとのプレゼンターとビューにリダイレクト(または forward)します。

ただしキーが正しくない場合(たとえばセッションから失効している場合)、メソッドは何もしません。ですから、続く $this->redirect('Admin:') の呼び出しがフォールバックとして働き、AdminPresenter のような既定のページにリダイレクトします。