AdminGeneratorに確認画面を追加する

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で大量のインプットデータを引き継ぐよりもデータトラフィックが少なく、また確認画面でのデータ改ざんができないので少しスマートかとおもいます。

Leave a Reply

You must be logged in to post a comment.