symfonyの威力を断片的に紹介。ご意見ご感想はこちらから。
5. 商品モデルでpropel-generate-crudで作ったプログラムを写経しようと思います。
写経とは経文を書写することのことなんですが、ソフトウェア開発の世界ではサンプルプログラム等、
既に存在しているソースコードを実際に自分の手で打ち込んでみることを言います。
弊社にも写経信者は1人いるんですが(笑)、私も入会、と言うわけではなく、
自動で出来たコードを追っていき、実際に自分の手でコーディングすることで
symfonyの理解を深める、と言う目的で写経したいと思います。
写経用のモジュールを作成しましょう。商品モデルの写経なので item_transcript でどうでしょうか。
¥ symfony init-module index item_transcript
エクスプローラで確認してみましょう。
/symfuldaze/apps/index/modules
内に item_transcript と言うディレクトリが出来ていることが確認できると思います。
ここがここから先の主な溜り場ですので迷ったらここに戻ってきてください(笑)。
item_transcript 内のディレクトリの数は propel-generate-crud の時より多いのですが、
この違いの理由は私にはわかりません。実際に actions と templates があればシステムは動きますし、
必要であれば自分でディレクトリを作ればいいので propel-generate-crud は
生成時は必要最低限のディレクトリ/ファイルしか作らないのかもしれません(2007年8月現在)。
propel-generate-crud で生成した item/actions の actions.class.php と
item_transcript/action の actions.class.php を開いてみましょう。
itemActions では5. 商品モデルでpropel-generate-crudの最後でお伝えしたように
executeIndexアクションはitemモジュールのlistアクションを呼び出していることがわかります。
forwardメソッドは別のアクションを呼び出すメソッドです。
気付かれたかもしれませんが、最初の引数がモジュール名、その次がアクション名です。
http://localhost/symfuldaze/web/item
で表示しようとするとexecuteIndexアクションが呼び出されます。そして、executeIndexアクションは
そのままitemモジュールの listアクションを内部的に呼び出しているのです。
ちなみにredirectメソッドと異なりforwardメソッドではリクエストされたURLが書き換えられることはありません。
itemモジュールと言えば自分自身ですね、では listアクションを見てみましょう。
1行のみしかありません。Criteriaの使用例で自分なりに
色々頑張って説明していますので参考にしていただければと思います(笑)。
まず、symfonyではモデルを作成すると /symfony/lib/model/ 直下に
モデル名.phpというファイルとモデル名+Peer.phpと言うファイルが出来ます。
商品モデルの場合、Item.phpとItemPeer.phpです。
Itemオブジェクトは1つの商品データを操作するオブジェクトクラス、
ItemPeerオブジェクトは商品の集合体を操作するオブジェクトクラスです。
Peer(ピア)は英語で仲間とか同僚を意味し、symfonyでは
データベースオブジェクトの集合体を意味しています。
ディレクトリ構造を見ればわかるかと思いますが、データベース接続設定と同様、
これらモデルファイルは1プロジェクト内全てのアプリケーションで共有されます。
ここでは商品群のクラス、ItemPeerのdoSelectメソッド、SQLで言うSelect文を実行し、
$this->itemsに結果Peerオブジェクトを割り当てています。引数には抽出条件を渡すのですが、
ここでは条件無しで全てを抽出するので、抽出条件の集合体オブジェクト、Criteria を
new しただけの状態で渡します。つまり、条件無し、と言うことですね。
それでは item_transcript/action/actions.class.phpを同じように編集しましょう。
新たに書き加えるところは item モジュールの内容と殆ど同じですが、一箇所だけ、
forward先のモジュール名を item ではなく、item_transcript にしなければいけないのでご注意ください。
続いて item_transcript/templates に移り、listSuccess.php と言うファイルを作成します。
文字コードを UTF-8 にするように気をつけてください。
既にある indexSuccess.php と言うファイルが本来ならindexアクションで呼び出されるのですが、
indexアクションからlistアクションにforwardされるため、同様にlistSuccess.phpがテンプレートとして呼び出されます。
これも英語表示のところを日本語にするのと、モジュール名をやりかえるだけで
殆どはitem/templates/listSuccess.phpと一緒です。foreach文が普段慣れている書き方と
違うのですが、これはsymfony特有と言うわけではなく、PHPの書き方の1つです。
写経ですのでその書き方をそのまま写経します。
アクションファイルで $this->items と定義して商品群オブジェクトが渡した変数は
こちらでは $items と、直接変数名を使ってアクセスできます。
商品群オブジェクト $items を foreach文で各商品データ、 $item として処理します。
各商品データ、$item の各プロパティは get+テーブルのカラム目の1文字目を大文字にしたメソッドで取得できます。
アンダーバー(_)が含まれている場合は切り取り、次の文字を大文字にします。
見た方が早いでしょう。
id ~ $item->getId()
name ~ $item->getName()
code ~ $item->getCode()
price ~ $item->getPrice()
description ~ $item->getDescription()
updated_at ~ $item->getUpdatedAt()
created_at ~ $item->getCreatedAt()
セッター(setプロパティ名(値))の時も同じような命名規約を従います。
また、link_toと言うメソッドが使われています。1つ目の引数は表示名で、
2つ目はリンク先のURL。そうです、ハイパーリンクを作成するメソッドです。
link_toメソッドの2つ目の引数のURLはフルパスでも構いませんが、
symfonyプロジェクト内では モジュール名/アクション で渡すことが可能です。
又、引数はアクション名の後に?変数名=値 と、普通にGET変数を渡す方法で記述します。
尚、ページのヘッダーとフッター部分は
/symfuldaze/apps/index/templates/layout.php
で生成されています。layout.phpは1つのアプリケーション内で全てのモジュール、
及び全てのテンプレートを持つアクションで共有されているのがおわかりになるかと思います。
それでは表示出来るか見てみましょう。
http://localhost/symfuldaze/web/item_transcript
静的サンプルはこちらです。
また、同時にlistアクションも作成されたことにお気づきになりましたでしょうか?
http://localhost/symfuldaze/web/item_transcript/list
静的サンプルはこちらです(さっきと同じですが;)。
引き続き item モジュールの create アクションを見てみましょう。
Item オブジェクトを new して、$this->setTemplate メソッドで edit と言うテンプレートを使うようにセットされています。
item_transcript モジュールの actions.class.php にも同じように記述します。
今回は全く同じ内容なのでここでの記載は省略します。
executeCreateアクションが成功し、edit と言うテンプレートがセットされているのであれば
symfony はeditSuccess.php と言うビューファイルを探します。itemモジュールを参考にしながら
item_transcript の templates にて editSuccess.php をUTF-8で作成しましょう。
基本写経ですが、一字一句と言うわけではなく、ところどころ小さな変更を入れてます。
尚、モジュール名は item ではなく item_transcript ですのでご注意を。
1行目の use_helper('Object') ではオブジェクトフォームヘルパーと言う、
オブジェクト用のフォームヘルパーを使用するように設定しています。
symfonyではHTMLのフォームの利用を簡単にするために標準で
フォームヘルパーと言うのが用意されています。フォームヘルパーについては
symfony book 日本語ドキュメント 実際のテンプレート作成:フォームヘルパーを参照ください。
上記スクリプトで言うと「object_」の後の部分が通常のフォームヘルパーのメソッド名です。
HTMLフォームのどのinputタグを意味するのか、大体予想がつきますね。
とか
とかはフォームヘルパーです。大体意味はわかりますね。
オブジェクトフォームヘルパーはHTMLフォームの要素と値をオブジェクトの
該当するセッター&ゲッターにひも付けてくれる強力な機能です。引数はフォームヘルパーと
若干異なり(まだフォームヘルパーを紹介していないのでわからないかもしれませんが)
1つ目の引数にオブジェクトのインスタンスを渡します。
2つ目の引数にオブジェクトクラスのゲッターメソッド名を記述します。これにより
HTMLフォーム上の要素名もセットされ、インスタンスが値を持っていれば
その値がフォームのinput値に割り当てられます。3つ目の引数はオプションですが、
ここでは説明を割愛します(かなり長くなってきて、まだ終わりは先なので・・・)。
お忘れにならないように、オブジェクトフォームヘルパーはuse_helper('Object')と明記しないと有効にはなりません。
とりあえず表示されているかどうかを見てみましょう。
http://localhost/symfuldaze/web/item_transcript/create
静的サンプルはこちらです。
長くなってきました。巻きましょう(笑;)。
createアクションなのにゲッターがあることに疑問に思われますか?
新規作成であれば値を取得する必要はありませんね。思い出してみましょう。
createアクションにはeditテンプレートがセットされています。
つまり、そうです、createアクションはeditアクションとテンプレートを共有しているのです。
editアクションは既存のデータの更新なのでゲッターで値を取得する必要があります。
新規作成の場合もゲッターはしますが、newされたばかりのインスタンスなのでNULLが返されるだけです。
ついでにeditアクションもitem_transcriptのactions.class.phpに記述しましょう。
これもitemモジュールのと内容は同じです。
パラメータで渡されたidを元に商品群のクラス、ItemPeerのretrieveByPkメソッドを
呼び出しています。retrieveByPkは主キーを抽出条件にデータを取得するメソッドです。
2行目はデータ取得失敗したら404エラーにして、と言う意味です。写経なのでそのまま
入れてますが通常は私なら別の処理をすると思いますがここでは割愛します。
$this->getRequestParameter('id')はHTTP/HTTPSリクエストで渡された引数の値を取得するメソッドです。
symfonyではPOSTデータもGETデータも区別されないようです。ここではGETで渡されたidを
取得していますが、下記、別の例では全く同じメソッドと引数でPOSTデータを取得しています。
ちょっと強引にIDを割り当ててですが、
http://localhost/symfuldaze/web/item_transcript/edit/id/1
このようなURLで表示してみましょう。表示されますか?
静的サンプルはこちらです。
editテンプレートにもう一度戻ってみましょう。下記に注目です。
フォームヘルパーの説明をしなくても予想できると思いますが、その通り、
HTMLフォームのACTION先をitem_transcriptモジュールのupdateアクションにする、と言う設定です。
ではupdateアクションを写経しましょう。
最後のモジュール名以外は一緒ですね。後、今までで一番長いアクションですが、
殆どのメソッドが既に説明済み、もしくは言葉の意味で充分予測できる
内容ではないかと思います。(巻いてる感マンセー?;)
最初にリクエストパラメータにidが無ければ$itemにItemオブジェクトをnewし(新規作成)、
あればidを元にデータベースからデータを取得して$itemにインスタンスを割り当てます。
引き続き各リクエストデータをインスタンスにセットし、最後にsaveメソッドで保存
(insertかupdateかは自動で判別されます)、idを引数にしてshowメソッドにリダイレクトされます。
updated_atとcreated_atはセットする必要が無いことに注目してください。
saveメソッドは自動でこれらの値をセットしてくれます(更新時はもちろんupdated_atのみ)。
この状態でPOSTすればまだ作成していないshowメソッドにリダイレクトされるので
実行する前にshowメソッドを作成する必要があります。
ここまで来たらshowメソッドはご自身でも作れるでしょうw。
showメソッドは宿題です。後、deleteメソッドも宿題にしましょう。ヽ( ´ー`)ノ~~
静的サンプルはこちらです。
<<<5. 商品モデルでpropel-generate-crud