4日目です。

昨日までに作成した質問の一覧画面から質問の個別表示ページ

http://askeet/frontend_dev.php/question/show/id/1

にアクセスするとエラーになる。調べると show アクションもビューもない。

そこで actions.class.php に下記コードを追加

public function executeShow()
{
   $this->question = QuestionPeer::retrieveByPk($this->getRequestParameter('id'));
   $this->forward404Unless($this->question);
}

askeet/apps/frontend/modules/question/templates/showSuccess.php を作成する

<?php use_helper('Date') ?>

<div class="interested_block">
  <div class="interested_mark">
    <?php echo count($question->getInterests()) ?>
  </div>
</div>

<h2><?php echo $question->getTitle() ?></h2>

<div class="question_body">
  <?php echo $question->getBody() ?>
</div>

<div id="answers">
<?php foreach ($question->getAnswers() as $answer): ?>
  <div class="answer">
    posted by <?php echo $answer->getUser()->getFirstName().' '.$answer->getUser()->getLastName() ?>
    on <?php echo format_date($answer->getCreatedAt(), 'p') ?>
    <div>
      <?php echo $answer->getBody() ?>
    </div>
  </div>
<?php endforeach; ?>
</div>

再度 http://askeet/frontend_dev.php/question/show/id/1 にアクセスすると表示できました。

URL からのパラメータの受け取り方

URL が http://askeet/frontend_dev.php/question/show/id/1 の場合

$id = $this->getRequestParameter('id')

これで $id=1 になる。

http://askeet/frontend_dev.php/question/show/id/1/myparam/myvalue

$param = $this->getRequestParameter('myparam');

これで $param = ‘myvalue’ になる。

テストデータの追加

answer テーブルにデータを追加するために askeet/data/fixtures/test_data.yml にチュートリアルにあるデータを追加して symfony コマンドを実行

symfony propel-load-data frontend

データ追加後の画面表示

追加した回答データが表示されている。

注意点は symfony propel-load-data コマンドを実行するとDBから一度データを全て削除して insert しなおすので各データの ID が変わります。そのために URL の /show/id/x の x の部分もデータをロードするたびに変わります。

モデルの変更

ユーザ名をビューで組み立てるのではなくモデルで組み立てる
askeet/lib/model/User.php

public function __toString()
{
  return $this->getFirstName().' '.$this->getLastName();
}

askeet/frontend/modules/question/templates/showSuccess.php

posted by <?php echo $answer->getUser()->getFirstName().' '.$answer->getUser()->getLastName() ?>

という部分を下記に変更する

posted by <?php echo $answer->getUser() ?>

__toString というマジックメソッドにすることによりビューでは User クラスのインスタンスを echo するだけでフルネームが表示できるようになりました。

マジックメソッドに関しては過去のエントリを参照
PHP5 マジックメソッド

リファクタリング

ビューの showSuccess.php と listSuccess.php には重複している部分があります。

<div class="interested_block">
  <div class="interested_mark">
    <?php echo count($question->getInterests()) ?>
  </div>
</div>

上記コードを askeet/apps/frontend/modules/question/templates/_interested_user.php というファイル名で作成して、
showSuccess.php と listSuccess.php の該当部分を下記コードに修正します。

<?php include_partial('interested_user', array('question' => $question)) ?>

この _interested_user.php のようなファイルをパーシャルといい、ファイル名の先頭はアンダースコアにして、ビューからインクルードするときはアンダースコアを入れずに指定します。第2引数にパーシャルに渡す引数を指定できます。パーシャルは HTML の共通化をするときに用いられます。

モデルの変更(テーブルにカラムを追加)

schema.yml の ask_question テーブルに下記の行を追加

interested_users: { type: integer, default: '0' }

下記コマンドを実行してテーブルを再作成

symfony propel-build-all

データを再度挿入

symfony propel-load-data frontend

(このやり方でいいのかな?間違っていたらコメントで教えてください)

追加したカラムに Interest テーブルにレコードが追加される度に更新されるようにする
askeet/lib/model/Interest.php

public function save($con = null)
{
  $con = Propel::getConnection();
  try
  {
    $con->begin();

    $ret = parent::save($con);

    // update interested_users in question table
    $question = $this->getQuestion();
    $interested_users = $question->getInterestedUsers();
    $question->setInterestedUsers($interested_users + 1);
    $question->save($con);

    $con->commit();

    return $ret;
  }
  catch (Exception $e)
  {
    $con->rollback();
    throw $e;
  }
}

上記コードはトランザクションを使っています。

テンプレートの変更
_interested_user.php

<?php echo count($question->getInterests() ?>

<?php echo $question->getInterestedUsers() ?>

に変更する

このままで質問を再表示させると interested_users カラムには何も入っていないので関心数が表示されません。そこで再度データを挿入しなおします。

symfony propel-load-data frontend

回答モデルにも同じことをする

これは繰り返しなので省略

関連する投稿