SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

symfony入門

symfony入門(2):掲示板アプリケーション作成でsymfonyを理解しよう(前篇)

symfonyによる実践的なPHPアプリケーション開発


掲示板作成:データベースとの連携(2/3)

掲示板への整形:テンプレートとアクションの編集

 今後は自動生成されたモジュールをベースに、掲示板としての形を整えていきます。

ルーティングの設定

 まずはルートディレクトリにアクセスした際にlistアクションを直接呼び出すよう、ルーティングを設定します。「mysite/apps/keijiban/config/routing.yml」のhomepageの部分を次のように編集します。

routing.yml
homepage:
  url:   /
  param: { module: bbsdata, action: index }

 設定を反映するために、プロジェクトディレクトリに戻ってキャッシュクリアを行いましょう。

symfony cc

 これで「http://localhost/」にアクセスするだけでリスト画面が表示されるようになります。action部分はindexのままですが、「actions.class.php」を見て頂くとindexアクションはlistアクションにフォワードされていることが分かります。

actions.class.php(抜粋)
public function executeIndex ()
{
  return $this->forward('bbsdata', 'list');
}

 「$this->forward('モジュール名', 'アクション名')」で、指定されたモジュールのアクションへフォワードされます。

レコード抽出条件の設定による掲示板書き込み表示順の設定:Criteriaオブジェクト

 デフォルトでレコードはidの昇順で取り出されるようになっていますが、通常掲示板では書き込みは降順、すなわち新しい書き込みほど、上位に表示されるようになっています。「actions.class.php」内のexecuteListアクションで、レコードを降順に出力するよう編集しましょう。executeListアクションを次のように書き換えます。

actions.class.php(抜粋)
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->bbsdatasdoSelect()の出力を格納することにより、テンプレート「listSuccess.php」へ$bbsdatasとして引き渡しています。

書き込みの改行文字を統一する:executeUpdate

 executeUpdateアクションでは、データミューテーターである「->set」メソッドでデータの更新を行っています(下記参照)。ここでは書き込み本文の改行文字を「\n」で統一してレコードに記録しておくために、executeUpdateアクション内でフォームの要素「body」内の改行文字をあらかじめ変換しておきます。

 なお、フォーム要素の変換にも関連しますが、現在の状態では出力時HTMLタグなどをそのままブラウザに送ってしまうため、クロスサイトスクリプティング(XSS)などの攻撃に対して脆弱性があります。本来ならばhtmlspecialchars関数などで対処することになりますが、symfonyではこれに対し既に内部で対策がなされていて、一部設定ファイルの書き換えで対処できるようになっています。次回セキュリティの項で触れる予定です。

actions.class.php(抜粋)
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と共にリダイレクトしています。

「created_at」「updated_at」というフィールド名について
 テーブルのフィールド名として「created_at」「updated_at」を指定しておくと、レコードを生成/更新する際に、明示的に何もせずとも自動的にこれらの値は生成/更新時の時刻に設定されます。上記のupdateアクションでも、「created_at」フィールドに対する操作は特に記述されていません。
 

掲示板画面を作る:listSuccess.php

 掲示板画面にはリスト画面を使用します。テンプレート「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」編集してより掲示板らしい外観にしていきます。次のように書き換えてみます。

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') ?>

 を次のようにフォームで書き換えます。

listSuccess.php(抜粋)
<?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のフォームがありますが、後で修正します)。

 これまでのファイル編集で図のような外観となりましたが、少しは掲示板の雰囲気が出てきたでしょうか。

listSuccess.phpを編集した後の画面
listSuccess.phpを編集した後の画面

ヘルパー使用のための設定

 これから、テキスト整形のために使われるヘルパーであるテキストヘルパーを使用する予定ですが、テキストヘルパーをはじめ、いくつかのヘルパーはデフォルトでは使用できません。実際に使用したい場合は「apps/keijiban/config/settings.yml」内で使用するヘルパーを定義することが可能ですので、「apps/keijiban/config/settings.yml」の以下の3つの行をすべてコメントインし、「standard_helpers:」の項の最後には「Text」を追加します。

settings.yml(抜粋)
all:
...
  .settings:
...
    standard_helpers:    [Partial, Cache, Form, Text]

 また「settings.yml」で指定していなくても、個々のファイル内で

<?php echo use_helper('ヘルパー名') ?>

 として呼び出すことも可能です。

 その他利用可能なヘルパーを表にまとめておきます(詳細については、本連載第4回で扱います)。

その他利用可能なヘルパー
ヘルパー 内容
Date 日付の各国用フォーマット用ヘルパー
Number 各国の通貨フォーマット用のヘルパーなど
I18N 国名や言語名のフォーマット用ヘルパー
Object オブジェクトを扱うためのヘルパー
Javascript Javascript用のヘルパー

テキストヘルパーの使用した、書き込み時の改行の反映

 さて、今のままでは、書き込み時の改行が表示に反映されていません。「listSuccess.php」内のBodyフィールド(本文)表示部分を次のように書き換えます。

listSuccess.php(抜粋)
<p><?php echo simple_format_text($bbsdata->getBody()) ?></p>

 simple_format_textヘルパーを使用することで、入力時の改行を表示に反映させます。このテキストヘルパーは、文字列中の改行文字を<br />タグに変換したり、2つ続いた改行を段落とみなして<p>タグに変換したりするなど、入力フォームの文字列を表示に反映させたい時に有用なヘルパーです。

 その他のテキストヘルパーも表でまとめておきます。

テキストヘルパー($text=”Welcome to my website!!”とする)
ヘルパー 内容 生成されるテキスト
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」を利用するよう、編集します(フォームの整形と表示の日本語化も行っておきます)。

editSuccess.php
…
<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アクションにリダイレクトする予定ですが、すべてのフィールドを参照でき、開発時はそれなりに便利なので今はそのままにしておきます。これの本文表示部分にも先程のテキストヘルパーを利用し、改行が反映されるようにします(同時に項目ラベルの日本語化と右寄せも行っておきます)。

showSuccess.php(抜粋)
<tr>
<th align="right">内容:  </th>
<td><?php echo simple_format_text($bbsdata->getBody()) ?></td>
</tr>

次のページ
掲示板作成:データベースとの連携(3/3)

修正履歴

この記事は参考になりましたか?

symfony入門連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 川北 季(カワキタ ミノル)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/837 2008/08/19 20:47

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー