掲示板作成:データベースとの連携(3/3)
各種機能の実装:返信機能
ここから、各種機能を実装していきます。今回は返信機能を追加します。
返信機能を実装する際、リスト画面で親記事の配下に、返信記事を昇順で表示するために、やや処理が多くなります。
返信用ボタン:listSuccess.php
親記事のID/TITLE/BODYフィールドの各値を、それぞれ「oya_id」「oya_title」「oya_body」としてフォームからcreateアクションへ送ります。これらを使用し、返信記事を作成します。「oya_id」には親記事のIDが渡されます(新規書き込み時は0でした)。
<div align="right"> <?php echo form_tag('bbsdata/create') ?> <?php echo input_hidden_tag('oya_id', $bbsdata->getId()) ?> <?php echo input_hidden_tag('oya_title', $bbsdata->getTitle()) ?> <?php echo input_hidden_tag('oya_body', $bbsdata->getBody()) ?> <?php echo submit_tag('返信') ?> </form> </div>
返信用フォーム:editSuccess.php
parent_idにはhiddenでoya_idが渡されています。さらにタイトルと書き込み本体に親記事の内容が反映されるようにします。
<tr> <th>タイトル:</th> <td> <?php if ($sf_params->get('oya_title')): ?> <?php echo input_tag('title', 'Re: '.$sf_params->get('oya_title'), array ( 'size' => 20, )) ?> <?php else: ?> <?php echo object_input_tag($bbsdata, 'getTitle', array ( 'size' => 20, )) ?> <?php endif; ?> </td> </tr> ... <tr> <th>内容:</th> <td> <?php if ($sf_params->get('oya_body')): ?> <?php echo textarea_tag('body', "> ".str_replace( "\n", "\n> ", $sf_params->get('oya_body')), array ( 'size' => '30x15', )) ?> <?php else: ?> <?php echo object_textarea_tag($bbsdata, 'getBody', array ( 'size' => '30x15', )) ?> <?php endif; ?> </td> </tr>
また、「oya_title」が存在すれば(つまり返信の場合)タイトルに「Re: 」を、「oya_body」が存在すれば書き込みの改行文字後に引用符を付加してフォームに表示させています。
返信記事表示準備:executeListアクション
当初決めたように、テーブルから特定の親記事ごとに関連づいた返信記事をまとめて持って来られるように、Criteriaオブジェクトを別個に設定しています。
public function executeList () { $c = new Criteria(); $c->add(BbsdataPeer::PARENT_ID, 0); $c->addDescendingOrderByColumn(BbsdataPeer::ID); $this->parent_bbsdatas = BbsdataPeer::doSelect($c); foreach($this->parent_bbsdatas as $parent) { $c_reply = new Criteria(); $c_reply->add(BbsdataPeer::PARENT_ID, $parent->getId()); $c_reply->addAscendingOrderByColumn(BbsdataPeer::ID); $no = 'threads'.$parent->getId(); $this->{$no} = BbsdataPeer::doSelect($c_reply); } }
親記事用の$cの他に、返信記事用に$c_replyを設定しています。$c_replyでは、foreachループ内で親記事のIDを「parent_id」に持つ記事を昇順に抽出しています。また、テンプレートに返信記事オブジェクト「threads<親記事ID>」を渡しています(このオブジェクト名を設定するため、いったん変数名として$noを定義し、可変変数$this->{$no}を使用しています)。いささか長めのコードになりましたが、本来これはMVCの中のモデルが担当する部分であり、コントローラーに過ぎないアクションクラス内にあるべきものではありません。今はそのままアクション内に記述しましたが、後でまとめてモデルクラス内に移動します。
Criteriaオブジェクトの詳細はPropelのマニュアルに記述されていますが、代表的なものを挙げておきます。
| メソッド | 意味 |
| ->add(<テーブル名>Peer::<大文字フィールド名>, 値, Criteria::<比較演算子記述(LIKE, EQUAL等)>) | データの抽出条件を設定 |
| ->addAnd(Criteriaオブジェクト) | 条件をandで追加 |
| ->addOr(Criteriaオブジェクト) | 条件をorで追加 |
| ->addAscendingOrder(<テーブル名>Peer::<大文字フィールド名>) | 対象となるフィールドで昇順にソート |
| ->addDescendingOrder(<テーブル名>Peer::<大文字フィールド名>) | 対象となるフィールドで降順にソート |
| ->addGroupByColumn(<テーブル名>Peer::<大文字フィールド名>) | 対象となるフィールドでグループ化 |
親記事と返信記事の表示:listSuccess.php
親記事オブジェクト「parent_bbsdatas」と返信記事オブジェクト「threads<親記事ID>」を受け取り、foreachの2重ループで返信記事を親記事の下にまとめて表示します。返信記事はインデントして表示しています。
<?php foreach ($parent_bbsdatas as $bbsdata): ?> … <p><?php echo simple_format_text($bbsdata->getBody()) ?></p> <br /><br /> <div align="right"> <?php echo form_tag('bbsdata/create') ?> <?php echo input_hidden_tag('oya_id', $bbsdata->getId()) ?> <?php echo input_hidden_tag('oya_title', $bbsdata->getTitle()) ?> <?php echo input_hidden_tag('oya_body', $bbsdata->getBody()) ?> <?php echo submit_tag('Reply') ?> </form> </div> <?php $th = 'threads'.$bbsdata->getId() ?> <div style='margin-left: 20px'> <?php foreach ($$th as $reply): ?> <table> <thead> <tr> <th>Id</th> … <p><?php echo simple_format_text($reply->getBody()) ?></p> <br /><br /> <?php endforeach; ?> </div> <hr> <?php endforeach; ?>
これで、リスト画面は下図のような感じになります。
今回のまとめ
ここまでで既に結構な量になってしまいましたが、今回はsymfonyとデータベースとの連携、scaffolding機能を紹介し、これを利用して掲示板アプリケーションをある程度の形まで整えました。次回は続けて掲示板にページャーや削除/検索機能を実装していき、また入力値の検証やセキュリティ対策、リファクタリング、不要な要素の整理、ビューの設定などを行う予定です。
参考文献(前回挙げたもの以外)
Propelガイドの、Criteriaオブジェクトや関連するメソッドについての部分です。SQLを直接記述する方法なども載っています。

