);}}IndexController.phtml以下、ポイントです。Zend_Dbを使用するために、'Zend/Db.php'をrequireしているZend_Db_Adapterを取得するためにZend_Db::factoryスタティックメソッドを使用しているZend_Db_Adapter::fetchAll()メソッドでSQLステートメントを実行しているZend_Db::factoryは、Zend_Db_Adapter抽象クラスから派生した、DBMS固有のDBアダプタのインスタンスを生成するためのファクトリメソッドです。パラメータにはクラス名を示す文字列と、各アダプタクラスが必要とする初期化パラメータを示す連想配列を渡します。クラス名は暗黙で「Zend_Db_Adapter_」プレフィックスがつけられますので、今回の例の「PdoSqlite」はZend_Db_Adapter_Pdo_Sqlite」を作成することを意味しています。第二引数の初期化パラメータ配列ですが、SQLiteの場合は他のオプションがほとんどないのでキー'dbname'のみを指定していますが、他のDBMSの場合は「username」「password」などがあります。ローカルで動作しているMySQLのスキーマ「mydb」に接続する場合は以下のようになります。接続パスワード));Zend_Db_Adapter_Pdo_MySqlを初期化するサンプル標準で添付されているアダプタクラスや、接続パラメータなどはAPIドキュメントを参照してください。接続パラメータは各アダプタクラスの変数「$_config」で定義されています。index.phtmlです。Zend_Db_Adapter::fetchAll()が何を返すのかを単純に確認するため、以下のようにvar_dump()を使ったシンプルな実装をしてみましょう。?></pre></body></html>index.phtml(手抜き版)これでindex/indexへアクセスすると、以下のように表示されるはずです。"dara-jのtumblr。}}index/indexそう、Zend_Db_Adapter::fetchAll()は単純な連想配列を返すのです。これを単純なテーブル表示にするには、index.phtmlを以下のように変更します。foreach終わり}?></table></body></html>index.phtml(変更後)ちょっと(というかかなり)見づらいコードになってしまいますが、これは標準のZend_Viewを使っている限り、ですので、大変でしょうけど慣れるようにしてください(^^;実行結果は各自で確認してみてください。Zend_Db_Adapter::fetchAll参考までにですが、Zend_Db_Adapter::fetchAllについて少し解説します。Zend_Db_Adapter::fetchAllメソッドは以下のように定義されています。引数「$sql」はSQLステートメントの文字列かZend_Db_Selectを受け取ります。第二引数の「$bind」はパラメタライズドクエリを使用する場合のパラメータリストになります。肝心の処理内容は、以下のように記述されています。要するに、Zend_Db_Adapter_Abstract::query()でZend_Db_Statementを生成し、そのZend_Db_Statementの実行結果を返すというプロキシ動作になってるということです。あとがき&次回予告ともかくデータベースの内容を表示するところまでやってみましたが、いかがでしたでしょうか?このままでは面白くもなんともないので、次回はこれにデータを追加する機能を作成してみたいと思います。そのために「Zend_Db_Table」の解説をする予定です。Framework入門でデータベースを扱ううえで、ターゲットのDBMSとしてSQLiteを使うつもりなので、「番外編」として、SQLiteコンソールアプリケーションの導入方法と簡単な使い方を説明しておきます。ここではWindows環境での手順のみ示します。Linuxユーザの方は、ダウンロードするバイナリやパスを環境に合わせて読み替えてください。公式サイトのダウンロードページ(http://www.sqlite.org/download.html)から入手できます。Windows」セクションの「sqlite-3_4_2.zip」をダウンロードしてください。※:2007.9.4に3.5.0がリリースされていますが、これは以前のバージョンと互換性がないとアナウンスされています。PHP5に標準添付のバージョンとも互換性がないため、3.4.xを使用するようにしてください。3.5.0インストールダウンロードしたアーカイブを解凍すると、中身は単独の実行可能ファイルが1つあるだけです。これをパスがとおっている場所(たとえばC:\WINDOWS)、または任意の場所に設置してください。任意の場所に設置した場合は、環境変数でパスを通すようにしてください。動作確認コマンドプロンプトを起動します。-help」を入力します。Settings\dara-j>このように、アプリケーションの説明が表示されればOKです。コマンドが見つからない場合は環境変数をもう一度見直してください。※:環境変数を設定したら、コマンドプロンプトを起動しなおしてください。起動してみるコマンドプロンプトから「sqlite3」と入力すると以下のように起動して入力待ち状態になります。instructionssqlite>sqlite3.exeは、このようにコマンドラインベースの対話型アプリケーションで、このままSQLを発行して使用できます。SQLを発行する以外にユーティリティコマンドも実装されていて、これらはすべて「.」(ピリオド)から始まります。「.help」を入力すると、以下のようになります。modesqlite>各ユーティリティコマンドの使い方はこちらなどが参考になるでしょう。ところで、この状態では実はデータベースに接続していない(開いていない)状態なので、どんなクエリを発行してもまったく無意味です。Settings\dara-j>これでsqliteを終了しました。新しいデータベースを開く先の例では、コマンドライン引数をまったく与えずに起動しました。その結果、データベースを開いていない状態になりました。今度は新しいデータベースを開いて起動してみることにします。やり方は至極簡単、コマンドライン引数に存在しないファイル名を与えると、それをデータベースとして開きます。Settings\dara-j)に「test.db」というデータベースを作成して開いてみます。instructionssqlite>一見先ほどとなにも違っていないようですが、これでデータベースを開いていることになります。テスト用のテーブルを作成してみます。ピリオドで始まるユーティリティコマンド以外の入力時は、最後に「;」(セミコロン)がつくまでは入力モードのままなので、普通に複数行入力できます。コマンドを確定させる場合に末尾にセミコロンを打ってからEnterしてください。);sqlite>エラーが出ていなければテーブルが作成されているはずです。テーブル一覧は「.tables」コマンドで確認できます。TABLEした「t_test」が存在することが確認できました。TABLEに関して、以下2点補足です。INCREMENT列になります。「regist」列はDEFAULT属性で「CURRENT_TIMESTAMP」を指定しています。);のみで新しいレコードが挿入されます。INCREMENT列にするのは、SQLiteでは定番ですので、ぜひ覚えておいてください。外部SQLコマンドの実行サンプルコードは示しませんが、「.read」ユーティリティコマンドで外部のSQLファイルを読み込んで実行できます。tableが記述されたファイル>」といった具合に使います。関連リソース最後にSQLite関連の代表的なリソースへのリンクを示しておきます。Gearsが採用していることもあり、SQLiteに関する情報は以前に比べてよく見つかるようになっているので、適当に検索をしてもよいと思いますが、とりあえずの参考にはなると思います。SQLite本家のSQL言語リファレンス。上記の翻訳版だが、最終更新日が4年前といささか古い。06時02分12秒お詫びというか訂正というか訂正しないというか一週間もほったらかした上にいきなりお詫びからです。前々回、前回に扱った「zf2」のIndexController::dumpActionですが、前々回では「$this->getRequest()->getParams()」としていたところを、前回掲載のソースでは「$this->getRequest()->getPost()」とメソッドが変わっていました。どこかで変更した検証コードをそのまま確かめもせずに掲載してしまったようです。フォームのメソッドがPOSTなので機能上はほとんど違いがないのですが、なんの断りもなく違うメソッドになっていたので混乱された方もいらっしゃるかもしれませんのでここでお詫びいたします。申し訳ありませんでした。今回も引き続き「zf2」を流用しますが、あえて「getParams()」に戻す理由もないので、今回も「getPost()」のままにしますのでご了承ください。入力内容を検査し、動作を変えるさて、今回の内容です。前回まででフォームの内容をサーバに送信し、その内容を確認するところまで作りました。表示するといった感じにしてみましょう。この仕様変更に伴い、以下の処理を追加する必要があります。入力値をフォームへ反映させるこれらを順を追って実装していきましょう。入力内容をフォームへ反映させる準備まず、未入力項目があった場合への対応で、入力フォーム(=indexAction+index.phtml)へ、POSTされた内容を反映させる準備をします。いっても特別なことではなく、前回までのdumpActionで行っていたように、getPost()で取得した連想配列をviewへassignするだけです。$this->getRequest()->getPost()」をそのままindexActionの先頭に記述してもいいのですが、どのみち今回の仕様では未入力の有無にかかわらずビューへ入力データを渡す必要があるので、共通の処理としましょう。init()内で行ってしまうのです。実際のフォームフィールドへの反映ですが、これまた単純で、HTMLフォームの値として、ビュースクリプト内でechoするだけになります。ここまでのコードを掲載します。IndexController。}}IndexController.php基本的にdumpActionで行っていた'postData'への割り当てをinitに移しただけですが、'baseUrl'への割り当てでもZend_Requestを使用するため、先にローカル変数「$request」にZend_Requestを割り当てるようにしています。assignでメソッドチェーンを適用しています。postDataへ直接getPost()の値を割り当てているのではなく、array_merge()を使用しています。これは、フォーム送信ではなく、直接index/indexを呼び出した場合への対応で、「name」「mail」「sex」の3つのキーが常にpostDataに割り当てられた状態にするための下処理として行っています。index.phtmlは以下のようになります。</body></html>index.phtmlちょっと見にくい(醜い?)コードになっていますが、変更点は以下のとおりです。フォーム項目「mail」を追加しているPOST先をdumpActionからindexActionに変更postDataから値を取得し、value属性に設定しているまずPOST先の変更ですが、これはここまでの修正の動作確認のための一時変更です。dumpActionに飛ばしてしまうと、せっかくのフォーム項目に値を反映させるコードの動作確認が取れないからです。実際のフォーム項目への値の反映ですが、これは基本的に連想配列の対応する値をvalue属性に出力するだけですが、$this->escape()で出力をエスケープしています。関数がその正体となります。Zend_View::escapeメソッドはZend_View::setEscape()メソッドでのカスタマイズも可能になっていますが、ここでは扱いません。出力のエスケープ」を参照してください。入力値をチェックするここまでのコードで動作させてみてください。「送信」しても画面が一切変わり映えしない、つまらない結果になるでしょう。当初の予定どおり、入力値をチェックしてその結果による振り分け処理を実装してみましょう。チェック処理は以下のような考え方になります。indexActionからのPOST先はチェック処理を行うアクションになるチェックアクション内で、必須項目に対してempty()で空かどうかの判断を行う2つの必須項目のうち、1つでも空であればもう一度indexActionへ飛ばす必須項目に問題がなければ結果表示を行うこれらを行うため、IndexControllerに入力値チェック用のアクションメソッドを追加します。名前はpostActionとでもしましょう。postActionを追加したIndexControllerは以下のようになります。}}postActionを追加したIndexController.php処理の振り分けに前回登場した、Zend_Controller_Action::_forwardを使っている程度で、特に解説の必要はないと思います。postAction内で'errorMessage'にエラーメッセージを割り当てていますので、これを出力するコードをindex.phtmlに実装する必要があります。</body></html>エラーメッセージ出力に対応したindex.phtmlisset()でerrorMessageが割り当てられているかを判断している程度で、これまた特に解説の必要はないかと思います。Zend_Controller_Action::_redirectさて、ここまでで今回の予定の機能はすべて実装できました。前回の予告で「_redirectについても解説」といっていたのですが、うまい使い道が思いつかなかったので、簡単な解説だけにとどめさせていただきます。Zend_Controller_Action::_redirectは、_forwardと同様にZend_Controller_Actionのプロテクトメソッドで、目的のURLへリダイレクトするためのメソッドです。メソッドシグニチャは以下のようになっています。array()])使い方は_forwardに近いのですが、以下のような違いがあります。引数はアクションではなくURLを指定する_forwardと違い、実際に指定URLへのリダイレクトが発生する(ブラウザの表示URLが実際に変更する)_forwardとの違いを手っ取り早く見てみるには、今回のコードのpostActionで、indexActionに_forwardしているところを「_redirect('index/index')」に変更してみてください。init()内でpostDataを割り当て、それをビューに反映させているのに、入力内容が実際には反映されないと思います。これは、_forwardはリダイレクトが発生するわけではない(=同じリクエストを処理している)が、_redirectは実際にリダイレクトが発生するためです。_forwardは同じリクエストを処理しているため、今回のようにPOSTされたデータをinit内でビューに割り当てている限り、_forward前のアクションでも_forward後のアクションでも同じようにデータを扱えますが、_redirectはリダイレクトすることによってリクエストの内容が変化する、ということです。あとがき&次回予告さて、1週間も間があいた割には、大して新しい内容が出現しませんでした(^^;が、これで一通りページを作成してユーザの入力を受け取り処理をするための基礎に触れられたと思います。次回からは、いったんコントローラ関連の処理から離れ、これまたWebアプリケーションでは不可欠ともいえる、データベース関連の機能に移りたいと思います。DBMSはPHP5で標準的に扱えるため環境にあまり左右されない、SQLiteを使う予定です。Zend_Db関連をやるのではなく、1回くらいはSQLiteの使い方を解説するかもしれません(しないかもしれません^^;)。それでは次回を、気長にお待ちください。未実装のアクションを呼び出すさて、今回は例外処理からはじめたいと思います。いってもそう難しいことをやるわけではなく、Zend_Controllerが標準的に用意している仕組みの導入方法を説明するだけですが。例外を発生させるところからはじめましょう。した「zf2」アプリケーションで、存在しないアクションを呼び出すだけです。前回までの実装では、IndexControllerに実装したアクションメソッドは「index」アクションと「dump」アクションの2つのみでした。この実装状況のままで、存在しないアクションメソッド、そうたとえば「hoge」を呼び出してみましょう。アクセスしてみてください。error」が表示されるはずです(表示されない場合はdisplay_errorsがfalseになっていると思われるので、PHP.iniを見直すか、index.phpでini_setを行うようにしてください)。エラーハンドラを作成する次にこの例外をキャッチして、エラーの内容を表示するようにしてみます。やり方は簡単、専用のアクションコントローラ「ErrorController」にアクションメソッド「errorAction()」を実装し、対応するビュースクリプト「error.phtml」をviews/scripts/error/に設置するだけです。ErrorControllerを作成しましょう。内容は以下のように、結構シンプルなものになります。例外情報をビューへassignする$this->view->assign('errors',$this->getResponse()->getException());}}ErrorController.php「$this->getResponse()」はレスポンスオブジェクト「Zend_Controller_Response_Abstract」を取得するメソッドです。Zend_Controllerを使用している場合、処理中に発生したエラーはレスポンスオブジェクトに格納されるため、レスポンスオブジェクトを取得し、そのあとにgetException()メソッドで例外を取得します。それをビューへassignしています。エラーの内容を表示するこのエラーアクションを表示するerror.phtmlは以下のようにしてみましょう。</body></html>error.phtmlerrorAction内でassignされた「errros」を処理しているのですが、Zend_Controller_Response::getException()が例外の配列を返すためforeachで処理しています。配列の内容は例外クラス「Exception」およびその派生の例外クラスですので、getMessage()メソッドでエラーメッセージを取得することができます。例外(exceptions)」を参照してください。エラー処理を追加したフォルダツリーここまででフォルダツリーは以下のようになります。アクセスすると、今度は以下のような表示になるはずです。__call()index/hoge「hogeActionが存在しない」旨のメッセージが表示されたはずです。このように、発生したエラーはErrorController::errorActionで処理させるのがZend_Controllerの標準的な例外処理になります。Frameworkに標準で添付されている「エラーハンドラ」コントロールプラグインの機能により提供されています。標準の配布パッケージに含まれるプラグイン」を参照してください。未実装のアクションをデフォルトアクションに振り分けるさて、上の例では、未実装のアクションを呼び出すことで例外を発生させましたが、場合によっては未実装のアクションを例外にせず、他の動作に付け替えたい場合もでてくるかもしれません。このような場合は、PHP5の標準的な機能である「__call」マジックメソッドを利用できます。__callは、未定義のメソッドが呼び出された場合にオーバーロードとして呼び出されるメソッドです。(「オーバーロード」の意味合いが、たとえばC#のようなほかのプログラミング言語と違う点に注意してください)__callメソッドのシグニチャは以下のように定義されています。)第一引数の「$name」は呼び出された(存在しない)メソッドの名前、第二引数は呼び出しに使用された引数のリストになります。ここでは、「未定義のアクションが呼び出されたら、デフォルトアクション(=indexAction)を代わりに実行する」ようにしてみます。追加するコードはシンプルです。アクセスすると、先ほどはエラーが表示されていたのが、今度はindex/indexにアクセスした場合と同じ表示になります。付け替えたということです。プロテクトメソッドアクションコントローラ内で、あるメソッドから他のアクションメソッドへ処理を委譲する場合は「_forward」メソッドを使用します。「_forward」メソッドはZend_Controller_Actionに実装されたプロテクトメソッドで、シグニチャは以下のようになっています。null)第二引数でコントローラ名も指定できるのですが、通常は同じコントローラ内のほかのアクションメソッドを呼び出すと思われるためたいていは第一引数にターゲットのアクション名を指定するだけです。ここで注意が必要なのは、_forwardの呼び出し実行時は、呼び出されるアクションコントローラが再度初期化される点です。);}とした場合、その後呼び出されたfugaAction()内で「$this->hogeParam」を参照してもhogeAction内で設定した値は格納されていません。このあたりはZend_Controllerの内部における「ディスパッチ」処理の動作によるもので、いずれ解説をしたいと思いますが、ここでは「_forwardはメソッド呼び出しではなく、次のアクションの予約を入れている」ようなもの、と認識してください。まとめ今回の要点は以下のとおりです。ErrorController::errorActionが定義されている場合、それが標準のエラーハンドラになるエラー情報の取得はZend_Controller_Response::getException()で行う。戻り値はExceptionの配列である__callメソッドで未定義のアクション呼び出しをカバーできるZend_Controller_Action::_forwardメソッドで他のアクションメソッドへ処理を委譲できるあとがき&次回予告またも予想より記事が長くなってしまったので、今回はフォーム処理周りに触れられませんでした(タイトルに偽りあり、ですね^^;)。次回こそは前回のフォームを拡張し、入力内容によって処理を分岐させるようなサンプルを行いたいと思います。今回でてきた「_forward」の親戚筋にあたる「_redirect」についても解説してみたいと思います。吊ブックマークレットtumblrのキーボードショートカットが便利になっとる。Chrome編dataスキームの画像をブロックしてみるローカルストレージを確認したり消したりするブックマークレットそうそう、いまさらTwitter始めました。(9)このブログについてJavaScriptとかC#とかPHPとか。