ZendFramework入門・その5 フォームを取り扱う・その3 ― 2007年09月17日 06時02分12秒
お詫びというか訂正というか訂正しないというか
一週間もほったらかした上にいきなりお詫びからです。
前々回、前回に扱った「zf2」のIndexController::dumpActionですが、前々回では「$this->getRequest()->getParams()」としていたところを、前回掲載のソースでは「$this->getRequest()->getPost()」とメソッドが変わっていました。どこかで変更した検証コードをそのまま確かめもせずに掲載してしまったようです。
フォームのメソッドがPOSTなので機能上はほとんど違いがないのですが、なんの断りもなく違うメソッドになっていたので混乱された方もいらっしゃるかもしれませんのでここでお詫びいたします。申し訳ありませんでした。
今回も引き続き「zf2」を流用しますが、あえて「getParams()」に戻す理由もないので、今回も「getPost()」のままにしますのでご了承ください。
入力内容を検査し、動作を変える
さて、今回の内容です。
前回まででフォームの内容をサーバに送信し、その内容を確認するところまで作りました。今回はそれに少しだけ機能を足して、
- 送信する内容を「名前」「性別」に加えて「メールアドレス」を追加する
- 「名前」と「メールアドレス」はどちらも入力を必須とする
- 必須項目が未入力の場合は入力画面に戻り、再度入力させる
- すべて入力されていたら、入力内容確認画面を表示する
この仕様変更に伴い、以下の処理を追加する必要があります。
- 入力内容の検査(空かどうかのみ)
- 検査結果による表示内容の変更
- 入力値をフォームへ反映させる
入力内容をフォームへ反映させる準備
まず、未入力項目があった場合への対応で、入力フォーム(=indexAction+index.phtml)へ、POSTされた内容を反映させる準備をします。
といっても特別なことではなく、前回までのdumpActionで行っていたように、getPost()で取得した連想配列をviewへassignするだけです。
dumpActionでやっていた、「$this->veiw->assign('postData', $this->getRequest()->getPost()」をそのままindexActionの先頭に記述してもいいのですが、どのみち今回の仕様では未入力の有無にかかわらずビューへ入力データを渡す必要があるので、共通の処理としましょう。そう、init()内で行ってしまうのです。
そして、実際のフォームフィールドへの反映ですが、これまた単純で、HTMLフォームの値として、ビュースクリプト内でechoするだけになります。
ここまでのコードを掲載します。まずはIndexController。
<?php require_once 'Zend/Controller/Action.php'; class IndexController extends Zend_Controller_Action { // 初期化処理 public function init() { // リクエストオブジェクトの取得 $request = $this->getRequest(); // BASE要素向けのベースURL $this->view->assign( 'baseUrl', getApplicationUrl( $request ) )->assign( 'postData', array_merge( array( 'name' => '', 'mail' => '', 'sex' => 1 ),$request->getPost() ) ); } // indexアクション public function indexAction() { } // dumpアクション public function dumpAction() { // postDataへの割り当てをinit()に移動したため // ここではなにもしない } public function __call($name, $args) { $this->_forward( 'index' ); } }
また、postDataへ直接getPost()の値を割り当てているのではなく、array_merge()を使用しています。これは、フォーム送信ではなく、直接index/indexを呼び出した場合への対応で、「name」「mail」「sex」の3つのキーが常にpostDataに割り当てられた状態にするための下処理として行っています。
index.phtmlは以下のようになります。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <base href="<?php echo $this->baseUrl; ?>/"></base> <title>フォーム テスト</title> </head> <body> <h3>入力フォーム</h3> <form action="index/index" method="post"> <ul> <li> <label for="name">名前</label> <input type="text" name="name" id="name" size="20" value="<?php echo $this->escape( $this->postData['name'] ); ?>"> <li> <label for="mail">メールアドレス</label> <input type="text" name="mail" id="mail" size="40" value="<?php echo $this->escape( $this->postData['mail'] ); ?>"> <li> <label for="sex">性別</label> <select name="sex" id="sex" value="<?php echo $this->postData['sex']; ?>"> <option value="1"<?php if( $this->postData['sex'] == 1 ) echo ' selected'; ?>>男性 <option value="2"<?php if( $this->postData['sex'] == 2 ) echo ' selected'; ?>>女性 </select> </ul> <input type="submit" value="送信"> </form> </body> </html>
- フォーム項目「mail」を追加している
- POST先をdumpActionからindexActionに変更
- postDataから値を取得し、value属性に設定している
そして、実際のフォーム項目への値の反映ですが、これは基本的に連想配列の対応する値をvalue属性に出力するだけですが、$this->escape()で出力をエスケープしています。
出力のエスケープ処理
この「$this->escape()」(=Zend_Veiew::escapeメソッド)は、名前のとおり出力のエスケープ処理を行うZend_Viewのメソッドで、今のようにデフォルトのまま扱っている場合は、htmlspecialchars() 関数がその正体となります。
Zend_View::escapeメソッドはZend_View::setEscape()メソッドでのカスタマイズも可能になっていますが、ここでは扱いません。詳細はリファレンスガイドの「35.3.1. 出力のエスケープ」を参照してください。
入力値をチェックする
ここまでのコードで動作させてみてください。たぶん「送信」しても画面が一切変わり映えしない、つまらない結果になるでしょう。ですので、当初の予定どおり、入力値をチェックしてその結果による振り分け処理を実装してみましょう。
チェック処理は以下のような考え方になります。
- indexActionからのPOST先はチェック処理を行うアクションになる
- チェックアクション内で、必須項目に対してempty()で空かどうかの判断を行う
- 2つの必須項目のうち、1つでも空であればもう一度indexActionへ飛ばす
- 必須項目に問題がなければ結果表示を行う
postActionを追加したIndexControllerは以下のようになります。
<?php require_once 'Zend/Controller/Action.php'; class IndexController extends Zend_Controller_Action { // 初期化処理 public function init() { // リクエストオブジェクトの取得 $request = $this->getRequest(); // BASE要素向けのベースURL $this->view->assign( 'baseUrl', getApplicationUrl( $request ) )->assign( 'postData', array_merge( array( 'name' => '', 'mail' => '', 'sex' => 1 ),$request->getPost() ) ); } // indexアクション public function indexAction() { } // postアクション public function postAction() { $postData = $this->getRequest()->getPost(); // 未入力チェック $is_empty = empty( $postData['name'] ) || empty( $postData['mail'] ); if( $is_empty ) { // 未入力があったのでエラーメッセージをセットしてindexActionへforward $this->view->assign( 'errorMessage', '未入力項目があります' ); $this->_forward( 'index' ); return; } // 正常だったのでdumpへforward $this->_forward( 'dump' ); } // dumpアクション public function dumpAction() { } public function __call($name, $args) { $this->_forward( 'index' ); } }
そして、postAction内で'errorMessage'にエラーメッセージを割り当てていますので、これを出力するコードをindex.phtmlに実装する必要があります。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <base href="<?php echo $this->baseUrl; ?>/"></base> <title>フォーム テスト</title> </head> <body> <?php if( isset( $this->errorMessage ) ) { ?> <div style="color: red"><?php echo $this->escape( $this->errorMessage ); ?></div> <?php } ?> <h3>入力フォーム</h3> <form action="index/post" method="post"> <ul> <li> <label for="name">名前</label> <input type="text" name="name" id="name" size="20" value="<?php echo $this->escape( $this->postData['name'] ); ?>"> <li> <label for="mail">メールアドレス</label> <input type="text" name="mail" id="mail" size="40" value="<?php echo $this->escape( $this->postData['mail'] ); ?>"> <li> <label for="sex">性別</label> <select name="sex" id="sex" value="<?php echo $this->postData['sex']; ?>"> <option value="1"<?php if( $this->postData['sex'] == 1 ) echo ' selected'; ?>>男性 <option value="2"<?php if( $this->postData['sex'] == 2 ) echo ' selected'; ?>>女性 </select> </ul> <input type="submit" value="送信"> </form> </body> </html>
Zend_Controller_Action::_redirect
さて、ここまでで今回の予定の機能はすべて実装できました。
前回の予告で「_redirectについても解説」といっていたのですが、うまい使い道が思いつかなかったので、簡単な解説だけにとどめさせていただきます。
Zend_Controller_Action::_redirectは、_forwardと同様にZend_Controller_Actionのプロテクトメソッドで、目的のURLへリダイレクトするためのメソッドです。メソッドシグニチャは以下のようになっています。
void _redirect(string $url, [ $options = array()])使い方は_forwardに近いのですが、以下のような違いがあります。
- 第一引数はアクションではなくURLを指定する
- _forwardと違い、実際に指定URLへのリダイレクトが発生する(ブラウザの表示URLが実際に変更する)
これは、_forwardはリダイレクトが発生するわけではない(=同じリクエストを処理している)が、_redirectは実際にリダイレクトが発生するためです。
_forwardは同じリクエストを処理しているため、今回のようにPOSTされたデータをinit内でビューに割り当てている限り、_forward前のアクションでも_forward後のアクションでも同じようにデータを扱えますが、_redirectはリダイレクトすることによってリクエストの内容が変化する、ということです。
あとがき&次回予告
さて、1週間も間があいた割には、大して新しい内容が出現しませんでした(^^;が、これで一通りページを作成してユーザの入力を受け取り処理をするための基礎に触れられたと思います。
次回からは、いったんコントローラ関連の処理から離れ、これまたWebアプリケーションでは不可欠ともいえる、データベース関連の機能に移りたいと思います。
DBMSはPHP5で標準的に扱えるため環境にあまり左右されない、SQLiteを使う予定です。ですので、いきなりZend_Db関連をやるのではなく、1回くらいはSQLiteの使い方を解説するかもしれません(しないかもしれません^^;)。
それでは次回を、気長にお待ちください。
コメント
トラックバック
このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2007/09/17/1802351/tb
※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※なお、送られたコメントはブログの管理者が確認するまで公開されません。