PRGパターン
PRG (POST-REDIRECT-GET) パターンの擬似コード書いてみました。各メソッドは名前から推察できるとおりHTTPの同名のメソッドに対応して呼び出されることを想定しています。
たとえば、ブラウザからPOSTした場合は以下のような感じ。(簡単のために厳密性に欠ける表現ですがあしからず)
- ブラウザからサーバ
- http://example.com/ に情報を POST するよ。
- サーバからブラウザ
- Webページを返すよ。
- cookieにPOSTの結果を 'result' として記しておいたよ(ちなみに失敗だったら 'code' としてエラーコードも記してあるよ)
- リダイレクト先の URL も 'Location' ヘッダに記しておいたのでよろしく。
- ブラウザからサーバ
- 2.で指示された URL から情報を GET するよ。(つまり2.で指示された URL にリダイレクトするってこと)
- この際に2.で食べた cookie の内容も当然サーバに送るよ。
- サーバからブラウザ
- Webページを返すよ。
- 2.でセットした cookie を消してね。
PRGパターンの効能としてよく語られる「再送信の弊害の回避」は、上記における1.(=POST)ではなく3.(=GET)が再送信の対象となることによる効能、ということすね。
<?php class Controller() { public function get() { $result = $this->cookie('result'); if ($result !== '') { $this->view->set(array('result' => ($result === 'success'))); $this->cookie('result')->delete(); $code = $this->cookie('code'); if ($code !== '') { $this->view->set(array('code' => (int)$code)); $this->cookie('code')->delete(); } } $this->view->set('resource' => $this->resource); $this->view->render(); } public function post() { $this->_process('create'); } public function put() { $this->_process('update'); } public function delete() { $this->_process('delete'); } private function _process($process) { $result = true; try { $this->resource->$process(); } catch (Exception $e) { $result = false; $this->cookie('result')->set('failure'); $this->cookie('code')->set($e->getCode()); } $result && $this->cookie('result')->set('success'); $this->redirect($this->resource->link); } }