SymfonyのAdminGeneratorのdefault themeでは以下のように、 編集用のフォームでデータをサブミットすると、すぐフォームに戻るような画面設計になっています。
フォーム -> (submit:データベースアップデート) -> フォーム
これを、以下のように確認画面を挟むサンプルを作ってみました。
フォーム-> 確認 -> (submit:データベースアップデート) -> フォーム
確認画面でhiddenタグを利用してフォームからの値を引き継ぐ事をよくやりますが、今回はSymfonyで導入されたFlashスコープ変数を使って実装してみたいと思います。
Flash変数について
Flash変数は、セッション(User)で保持される変数です。通常のセッションとの違いは、 次のリクエストで確実に消去されるという事です。これにより、確認画面や、処理後の結果表示画面の構築、汎用メッセージ画面の構築が簡単になります。
サンプルの構築環境
サンプルの為に適当なスキーマを用意しました。
<?xml version="1.0" encoding="utf-8"?> <database name="symfony"> <table name="content" idMethod="native"> <column name="id" type="integer" required="true" primaryKey="true" autoincrement="true" /> <column name="name" type="varchar" size="255" required="true"/> <unique> <unique-column name="name" /> </unique> <column name="type" type="varchar" size="255" required="true"/> <column name="source" type="longvarchar" size="4096"/> <column name="html" type="longvarchar" size="4096"/> <column name="description" type="longvarchar" size="4096"/> </table> </database>
これをつかって、adminアプリケーションにcontentモジュールを作成します。
symfony propel-init-admin admin content Content
アクションの上書き
足場の作成で、project/apps/admin/modules/content/actions.class.phpに空のアクションが生成されます。実際には、project/cache/admin/dev/…以下にあるアクションを継承しています。既に親クラスでAdminGeneratorにより生成実装されているeditアクションを、以下のように上書きします。確認画面への値の受け渡しはFlashに入れます。
project/apps/admin/modules/content/actions.class.php
public function executeEdit () { /** * 確認画面から戻ったときに値が消えないように * フラッシュ変数を優先する */ $this->content = $this->getFlash('content'); if(!$this->content){ $this->content = $this->getContentOrCreate(); } if ($this->getRequest()->getMethod() == sfRequest::POST) { $this->updateContentFromRequest(); /** * content / save_and_addをフラッシュ変数に入れる */ $this->setFlash('content',$this->content); $this->setFlash('save_and_add' ,$this->getRequestParameter('save_and_add')); return $this->redirect('content/confirm'); } else { // add javascripts $this->getResponse()->addJavascript('/sf/js/prototype/prototype'); $this->getResponse()->addJavascript('/sf/js/sf_admin/collapse'); } }
同時に確認画面用の、comfirmアクションも作成します。
Confirmアクション
public function executeConfirm () { $this->save_and_add = $this->getFlash('save_and_add'); /** * 確認ページがリロードされたときに保持している値が消えないよう * Flashスコープの削除リストから外す */ $context = $this->getContext(); $userAttributeHolder = $context->getUser()->getAttributeHolder(); $userAttributeHolder->remove('content','symfony/flash/remove'); $userAttributeHolder->remove('save_and_add','symfony/flash/remove'); $this->content = $this->getFlash('content'); if(!$this->content){ return $this->redirect('content/edit'); } if($this->getRequestParameter("confirmed",false)){ $this->content->save(); /** * 使用を終えたFlashスコープを破棄する */ $this->setFlash('content',null,false); $this->setFlash('save_and_add',null,false); if($this->getRequestParameter('save_and_add')){ return $this->redirect('content/create'); } return $this->redirect('content/edit?id='.$this->content->getId()); } return sfView::SUCCESS; }
確認画面のテンプレート
確認画面のテンプレートも以下のように作成します。 templetes/confirmSuccess.php
<dl> <dt>name :</dt> <dd><?php echo $content->getName() ?></dd> <dt>type :</dt> <dd><?php echo $content->getType() ?></dd> etc... </dl> <?php echo form_tag("content/confirm") ?> <?php echo input_hidden_tag('confirmed', "1" ) ?> <?php echo input_hidden_tag('save_and_add', $save_and_add ) ?> <?php echo submit_tag('confirmed'); ?> </form>
以上でうまく行くはずですだと思っていますが、酔っぱらいながら書いたコードなので不具合があるかもしれません。ご指摘いただけると幸いです。
Flash変数を使う方法は、formにhiddenで大量のインプットデータを引き継ぐよりもデータトラフィックが少なく、また確認画面でのデータ改ざんができないので少しスマートかとおもいます。

