掲示板作成:データベースとの連携(2/3)
掲示板への整形:テンプレートとアクションの編集
今後は自動生成されたモジュールをベースに、掲示板としての形を整えていきます。
ルーティングの設定
まずはルートディレクトリにアクセスした際にlistアクションを直接呼び出すよう、ルーティングを設定します。「mysite/apps/keijiban/config/routing.yml」のhomepageの部分を次のように編集します。
homepage:
url: /
param: { module: bbsdata, action: index }
設定を反映するために、プロジェクトディレクトリに戻ってキャッシュクリアを行いましょう。
symfony cc
これで「http://localhost/」にアクセスするだけでリスト画面が表示されるようになります。action部分はindexのままですが、「actions.class.php」を見て頂くとindexアクションはlistアクションにフォワードされていることが分かります。
public function executeIndex () { return $this->forward('bbsdata', 'list'); }
「$this->forward('モジュール名', 'アクション名')」で、指定されたモジュールのアクションへフォワードされます。
レコード抽出条件の設定による掲示板書き込み表示順の設定:Criteriaオブジェクト
デフォルトでレコードはidの昇順で取り出されるようになっていますが、通常掲示板では書き込みは降順、すなわち新しい書き込みほど、上位に表示されるようになっています。「actions.class.php」内のexecuteListアクションで、レコードを降順に出力するよう編集しましょう。executeListアクションを次のように書き換えます。
public function executeList () { $c = new Criteria(); $c->addDescendingOrderByColumn(BbsdataPeer::ID); $this->bbsdatas = BbsdataPeer::doSelect($c); }
ここでCriteriaオブジェクトに注目してください。Propelによるこのオブジェクトはレコード抽出基準を設定するためのもので、このオブジェクトを操作することによりさまざまなレコード抽出が可能になります。今回はCriteriaオブジェクト$cに「addDescendingOrderByColumn(BbsdataPeer::ID)」とすることでIDの降順という条件が追加され、doSelect()メソッドでテーブル内のデータがすべて(他に抽出条件を設定していないので)IDの降順に出力されます。これにより直接SQLを書くことなく、データベースの操作が可能になっています。Criteriaオブジェクトや関連するメソッドについては、返信機能の項で改めて後述します。
symfonyでは、アクションで得られた値をテンプレートに引き渡すために、その値をアクションオブジェクトのメンバ変数としなくてはなりません。ここではメンバ変数$this->bbsdatasにdoSelect()の出力を格納することにより、テンプレート「listSuccess.php」へ$bbsdatasとして引き渡しています。
書き込みの改行文字を統一する:executeUpdate
executeUpdateアクションでは、データミューテーターである「->set」メソッドでデータの更新を行っています(下記参照)。ここでは書き込み本文の改行文字を「\n」で統一してレコードに記録しておくために、executeUpdateアクション内でフォームの要素「body」内の改行文字をあらかじめ変換しておきます。
なお、フォーム要素の変換にも関連しますが、現在の状態では出力時HTMLタグなどをそのままブラウザに送ってしまうため、クロスサイトスクリプティング(XSS)などの攻撃に対して脆弱性があります。本来ならばhtmlspecialchars関数などで対処することになりますが、symfonyではこれに対し既に内部で対策がなされていて、一部設定ファイルの書き換えで対処できるようになっています。次回セキュリティの項で触れる予定です。
public function executeUpdate () { … $bbsdata->setId($this->getRequestParameter('id')); $bbsdata->setTitle($this->getRequestParameter('title')); $bbsdata->setAuthor($this->getRequestParameter('author')); $bbsdata->setMail($this->getRequestParameter('mail')); $bbsdata->setUrl($this->getRequestParameter('url')); $body = str_replace("\r\n", "\n", $this->getRequestParameter('body')); $body = str_replace("\r", "\n", $body); $bbsdata->setBody($body); $bbsdata->setPasswd($this->getRequestParameter('passwd')); $bbsdata->setParentId($this->getRequestParameter('parent_id')); $bbsdata->save(); return $this->redirect('bbsdata/show?id='.$bbsdata->getId()); }
ここでアクセサメソッドである「->set」や実際の保存を行う「save()」が出てきましたので、「->get()」「->delete()」も合わせ、以下に簡単にまとめておきます。
| メソッド名 | 役割 |
| ->getTitle() | Titleフィールドの値を得る |
| ->setTitle($a) | Titleフィールドの値を$aに設定する |
| ->save() | ->setメソッドによる設定を、実際にデータベースに保存する |
| ->delete() | レコードの削除を行う |
また、ここで最後に出てきている$this->redirect(<リダイレクト先URL>)メソッドは、アクションを完了した際に別のアクションやサイトにリダイレクトするというものです。ここではbbsdataモジュールのshowアクションに、クエリ情報idと共にリダイレクトしています。
掲示板画面を作る:listSuccess.php
掲示板画面にはリスト画面を使用します。テンプレート「listSuccess.php」は次のようになっています。
<?php // auto-generated by sfPropelCrud // date: 2006/12/07 00:14:58 ?> <h1>bbsdata</h1> <table> <thead> <tr> <th>Id</th> <th>Title</th> ... <th>Created_at</th> </tr> </thead> <tbody> <?php foreach ($bbsdatas as $bbsdata): <tr> <td><?php echo link_to($bbsdata->getId(),'bbsdata/show?id='.$bbsdata->getId()) ?></td> <td><?php echo $bbsdata->getTitle() ?></td> ... <td><?php echo $bbsdata->getCreatedAt() ?></td> </tr> <?php endforeach; ?> </tbody> </table> <?php echo link_to ('create', 'bbsdata/create') ?>
executeListアクションでテーブルから抽出し、生成されたメンバ変数$this->bbsdatasは同名の変数$bbsdatasとして「listSuccess.php」で受け取り、foreachループで繰り返し表示しています。ループ内の$bbsdata->get***()メソッドは、先程オブジェクトモデル生成時に作成されたデータアクセサメソッドで、レコード上の各フィールドの値を得る事ができます。
これから、この「listSuccess.php」編集してより掲示板らしい外観にしていきます。次のように書き換えてみます。
<?php // auto-generated by sfPropelCrud // date: 2006/12/07 00:14:58 ?> <h1>My BBS</h1> <hr> <?php foreach ($bbsdatas as $bbsdata): ?> <table> <thead> <tr> <th>Id</th> <th> タイトル</th> <th> お名前</th> <th> Date</th> </tr> </thead> <tbody> <tr> <td><?php echo link_to($bbsdata->getId(),'bbsdata/show?id='.$bbsdata->getId()) ?></td> <td> <big><?php echo $bbsdata->getTitle() ?></big></td> <td> <?php echo mail_to($bbsdata->getMail(),
$bbsdata->getAuthor()) ?></td> <td> <small>[<?php echo $bbsdata->getCreatedAt() ?>]</small></td> <td> <?php echo link_to('Url', $bbsdata->getUrl()) ?></td> </tr> </tbody> </table> <br /> <p><?php echo $bbsdata->getBody() ?></p> <br /><br /> <hr> <?php endforeach; ?> <?php echo link_to ('create', 'bbsdata/create') ?>
オリジナルの「listSuccess.php」にもありましたが、link_toやmail_toなど特定のリンクのためのリンクヘルパーと呼ばれるヘルパーがあります。下表に概要をまとめておきますが、オプションなど詳細はsymfony bookを参照してください。
| ヘルパー | 内容 | 同等のHTML |
| url_for('bbsdata/show?id=2') | URLの生成 | http://mysite.com/index.php/bbsdata/show/id/2 |
| link_to('2番目の記事を表示','bbsdata/show?id=2') | ハイパーリンク | <a href="http://mysite.com/index.php/bbsdata/show/id/2" title="2番目の記事を表示">2番目の記事を表示</a> |
| button_to('2番目の記事を表示','bbsdata/show?id=2') | ハイパーリンク用ボタン | <input value="2番目の記事を表示" type="button" onclick="document.location.href='/index.php/bbsdata/show/id/2';" /> |
| mail_to('admin@mysite.com', 'メールする') | メール送信リンク | <a href="mailto:admin@mysite.com">メールする</a> |
| image_tag('sample1.jpg') | 画像表示 | <img href="/images/sample1.jpg" alt="Sample1" /> |
| javascript_include_tag('myscript') | JavaScriptファイルへのリンク | <script language="javascript" type="text/javascript" src="/js/myscript.js"> |
また、今後実装する返信機能のために、listSuccess最後の書き込みリンク
<?php echo link_to ('create', 'bbsdata/create') ?>
を次のようにフォームで書き換えます。
<?php echo form_tag('bbsdata/create') ?> <?php echo input_hidden_tag('oya_id', 0) ?> <?php echo submit_tag('投稿する') ?> </form>
parent_id設定のために隠しフィールド「oya_id」を利用しています。ここでは新規書き込みのparent_id=0として記録するために、oya_id=0をcreateアクションに引き渡しています(テンプレートに「editSuccess.php」を使用しています。parent_idのフォームがありますが、後で修正します)。
これまでのファイル編集で図のような外観となりましたが、少しは掲示板の雰囲気が出てきたでしょうか。
ヘルパー使用のための設定
これから、テキスト整形のために使われるヘルパーであるテキストヘルパーを使用する予定ですが、テキストヘルパーをはじめ、いくつかのヘルパーはデフォルトでは使用できません。実際に使用したい場合は「apps/keijiban/config/settings.yml」内で使用するヘルパーを定義することが可能ですので、「apps/keijiban/config/settings.yml」の以下の3つの行をすべてコメントインし、「standard_helpers:」の項の最後には「Text」を追加します。
all:
...
.settings:
...
standard_helpers: [Partial, Cache, Form, Text]
また「settings.yml」で指定していなくても、個々のファイル内で
<?php echo use_helper('ヘルパー名') ?>
として呼び出すことも可能です。
その他利用可能なヘルパーを表にまとめておきます(詳細については、本連載第4回で扱います)。
| ヘルパー | 内容 |
| Date | 日付の各国用フォーマット用ヘルパー |
| Number | 各国の通貨フォーマット用のヘルパーなど |
| I18N | 国名や言語名のフォーマット用ヘルパー |
| Object | オブジェクトを扱うためのヘルパー |
| Javascript | Javascript用のヘルパー |
テキストヘルパーの使用した、書き込み時の改行の反映
さて、今のままでは、書き込み時の改行が表示に反映されていません。「listSuccess.php」内のBodyフィールド(本文)表示部分を次のように書き換えます。
<p><?php echo simple_format_text($bbsdata->getBody()) ?></p>
simple_format_textヘルパーを使用することで、入力時の改行を表示に反映させます。このテキストヘルパーは、文字列中の改行文字を<br />タグに変換したり、2つ続いた改行を段落とみなして<p>タグに変換したりするなど、入力フォームの文字列を表示に反映させたい時に有用なヘルパーです。
その他のテキストヘルパーも表でまとめておきます。
| ヘルパー | 内容 | 生成されるテキスト |
| truncate_text($text, 5) | 後略ヘルパー。冒頭から指定された文字数(スペース含む)のみ表示 | "Welco..." |
| excerpt_text($text, 'my', 3) | 当該テキストをその前後指定された文字数と共に切り取って表示(この場合「my」の周囲3文字) | "...to my we..." |
| highlight_text($text, 'Welcome') | 当該テキストをハイライト表示 | "<span class="highlight"> Welcome</span> to my website!!" |
| auto_link_text('The site is www.myexample.com') | テキスト中のURLをハイパーリンク化 | "The site is <a href="http://www.myexample.com"> www.myexample.com</a>" |
書き込み入力フォーム:editSuccess.php
書き込み入力フォームを編集します。テンプレート「editSuccess.php」において、「parent_id」入力フォームを直接入力するのではなく「listSuccess.php」から受け取った「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' => 30, )) ?> <?php else: ?> <?php echo object_input_tag($bbsdata, 'getTitle', array ( 'size' => 30, )) ?> <?php endif; ?> </td> </tr> <tr> <th>お名前:</th> <td><?php echo object_input_tag($bbsdata, 'getAuthor', array ( 'size' => 20, )) ?></td> </tr> <tr> <th>メールアドレス:</th> <td><?php echo object_input_tag($bbsdata, 'getMail', array ( 'size' => '30', )) ?></td> </tr> <tr> <th>Url:</th> <td><?php echo object_input_tag($bbsdata, 'getUrl', array ( 'size' => '30', )) ?></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> <tr> <th>削除用パスワード:</th> <td><?php echo object_input_tag($bbsdata, 'getPasswd', array ( 'size' => 20, )) ?></td> </tr> </tbody> </table> <hr /> <?php echo input_hidden_tag('parent_id', $sf_params->get('oya_id')) ?> <?php echo submit_tag('この内容で投稿する') ?> …
ここでフォームヘルパーがたくさん出てきましたので、簡単な例と共に表にまとめておきましょう(例は前回とsymfony bookから引用)。
| ヘルパー | 記述例 | 同等のHTML |
| フォームタグ | form_tag('helloworld/youkoso') | <form method="post" action="http://localhost/index.php/helloworld/youkoso"> |
| テキストフィールド | input_tag('anatano_onamae', 'your name') | <input type="text" name="anatano_oname" id="anatano_oname" value="your name" /> |
| テキスト入力(複数行) | textarea_tag('name', 'default content', 'size=10x20') | <textarea name="name" id="name" rows="20" cols="10">default content</textarea> |
| チェックボックス | checkbox_tag('married', '1', true) | <input type="checkbox" name="married" id="married" value="1" checked="checked" /> |
| checkbox_tag('driverslicence', 'B', false) | <input type="checkbox" name="driverslicence" id="driverslicence" value="B" /> | |
| ラジオボタン | radiobutton_tag('status', 'value1', true) | <input type="radio" name="status" value="value1" checked="checked" /> |
| radiobutton_tag('status', 'value2', false) | <input type="radio" name="status" value="value2" /> | |
| 値の選択 | select_tag('name', options_for_select(Array('0' => 'Steve', '1' => 'Bob', '2' => 'Albert', '3' => 'Ian', '4' => 'Buck'), 3)) | <select name="name" id="name"><option value="0">Steve</option><option value="1">Bob</option><option value="2">Albert</option><option value="3" selected="selected">Ian</option><option value="4">Buck</option></select> |
| ファイルアップロード | input_file_tag('name') | <input type="file" name="name" id="name" value="" /> |
| パスワード入力 | input_password_tag('name', 'value') | <input type="password" name="name" id="name" value="value" /> |
| hiddenで値を送る | input_hidden_tag('name', 'value') | <input type="hidden" name="name" id="name" value="value" /> |
| サブミットボタン | submit_tag('Save') | <input type="submit" name="submit" value="Save" /> |
| サブミット(画像をクリックして) | submit_image_tag('submit_img') | <input type="image" name="submit" src="/images/submit_img.png" /> |
| 日付(カレンダーウィジェットも) | input_date_tag('test', '2006-04-01', 'rich=true') | (カレンダーウィジェット付きのテキストフィールドを表示。'rich=false'なら(デフォルト)単に年月日用の3つのテキストフィールドを表示) |
| 国選択 | select_country_tag('country', 'Albania') | <select name="country" id="country"><option>Afghanistan</option><option selected="selected">Albania</option><option>Algeria</option><option>American Samoa</option><option>Andorra</option>... |
| オブジェクト用フォームヘルパー(オブジェクトヘルパー) | object_<helper名>(object, method, options), object_input_tag($customer, 'getTelephone') | <input type="text" name="getTelephone" id="getTelephone" value="0123456789" /> ここで$customer->getTelephone() = '0123456789'. |
parent_idはリスト画面上でのユーザーの操作により決まる値ですので、hiddenタグに置き換えています。また、$sf_params->get()を使用することで、リスト画面から送られたリクエストをそのままフォームの再構築に利用しています。$sf_paramsはsymfonyであらかじめ定義された変数である「ショートカット」の一つで、テンプレート上でリクエストパラメーターを呼び出すことができます。ショートカットには、次のようなものがあります(詳細については、本連載第4回で扱います)。
| ショートカット | 役割 |
| $sf_context | contextオブジェクト全体 |
| $sf_request | オリジナルのリクエスト |
| $sf_params | オリジナルのリクエストパラメーター |
| $sf_user | 現在のsfUserオブジェクト |
| $sf_view | 呼び出しているsfViewオブジェクト |
| $sf_first_module | 最初に呼び出されたモジュール |
| $sf_last_module | 最後に呼び出されたモジュール |
| $sf_first_action | 最初に呼び出されたアクション |
| $sf_last_action | 最後に呼び出されたアクション |
レコード詳細表示画面:showSuccess.php
ここで、「editSuccess.php」はupdateアクションを呼び出していますが、デフォルトでupdateアクションはレコードを更新後、showアクションにリダイレクトされます。仕様上の理由から、今後は直接listアクションにリダイレクトする予定ですが、すべてのフィールドを参照でき、開発時はそれなりに便利なので今はそのままにしておきます。これの本文表示部分にも先程のテキストヘルパーを利用し、改行が反映されるようにします(同時に項目ラベルの日本語化と右寄せも行っておきます)。
<tr> <th align="right">内容: </th> <td><?php echo simple_format_text($bbsdata->getBody()) ?></td> </tr>

