忍者ブログ

uthorofotus iruc

プログラムを組むために考えたり憶えたりした、いろいろなことを記録していきます。タイトルの読みは「ウソロフォトス イルーク」

[23]  [22]  [21]  [20]  [19]  [18]  [17]  [16]  [15]  [14]  [13

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

askeet day eight:AJAX interactions の課題

チュートリアル8日目の最後に課題が出ていました。その課題もやっておくことにしましょう。

チュートリアルテキストなどはありません。Subversionにあるのソースは課題が終わった状態になっていますので、それを参考にしながら進めていきます。tracからはソースをまとめてzipで取得出来ますので、Subversionが見にくい人はそちらを利用すると楽です。
askeet trac上のSubversionコードビューワ

■作業内容の確認
まずは課題の内容を再確認して、どんな作業をすればいいのか考えます。8日目に提示された課題は、ログインフォームをAJAXで実装したのと同じ要領で、回答が質問に関連した良い内容であったどうか評価する仕組みを実装します。だいたい、こんな順番での作業を考えました。

  1. 回答を表示する部分のリファクタリング
  2. ビューを修正して、AJAX呼び出しを結果スペースを用意
  3. サーバで処理するアクションの作成

■回答への投票機能
▽リファクタリング
回答を表示している部分が幾つかありましたので、それらのコードをまとめて一つにします。それと同時に、1つの質問に回答が大量にされた場合に備えて質問と同じようなページャー機能を付けます。

まずはquestion/showアクションを修正します。apps/frontend/modules/question/actions/actions.class.php を以下のように修正します。

  public function executeShow()
  {
    $this->question = QuestionPeer::getQuestionFromTitle($this->getRequestParameter('stripped_title'));
    $this->forward404Unless($this->question);
    $this->answer_pager = AnswerPeer::getPager($this->question->getId(), $this->getRequestParameter('page', 1));
  }

ページャーのコードはPeerクラスに置いた方がよいので、lib/model/AnswerPeer.phpにメソッドを追加します。

  public static function getPager($question_id, $page)
  {
    $pager = new sfPropelPager('Answer',  sfConfig::get('app_pager_homepage_max'));
    $c = new Criteria();
    $c->add(self::QUESTION_ID, $question_id);
    $c->addDescendingOrderByColumn(self::RELEVANCY_UP);
    $c->addDescendingOrderByColumn(self::CREATED_AT);
    $pager->setCriteria($c);
    $pager->setPage($page);
    $pager->init();

    return $pager;
  }

回答1つをパーシャルファイルにします。 apps/frontend/modules/answer/templates/_list.php を作成します。

<?php use_helper('Date') ?>

<div id="answers">
<?php foreach ($answer_pager->getResults() as $answer): ?>
  <div>
    <?php echo $answer->getRelevancyUpPercent() ?>% UP <?php echo $answer->getRelevancyDownPercent() ?> % DOWN
    posted by <?php echo link_to($answer->getUser(), 'user/show?id='.$answer->getUser()->getId()) ?>
    on <?php echo format_date($answer->getCreatedAt(), 'p') ?>
    <div>
      <?php echo $answer->getBody() ?>
    </div>
  </div>
<?php endforeach ?>
</div>

apps/frontend/modules/answer/templates/recentSuccess.php もパーシャル_list.phpを使ったかたちで修正します。

<h1>recent questions</h1>

<?php include_partial('list', array('question_pager' => $question_pager)) ?>

▽呼び出しと結果スペース
AJAXを呼び出すリンクをビューに設定します。実行が可能となる条件が認証ユーザであり、その回答に対してまだ評価を下していない場合と煩雑になります。よってビューではなくヘルパーで記述することにします。新たにAnswerヘルパーをapps/frontend/lib/helper/AnswerHelper.php に作成します。

<?php

function link_to_user_relevancy_up($user, $answer)
{
  return link_to_user_relevancy('up', $user, $answer);
}

function link_to_user_relevancy_down($user, $answer)
{
  return link_to_user_relevancy('down', $user, $answer);
}

function link_to_user_relevancy($name, $user, $answer)
{
  use_helper('Javascript');

  if ($user->isAuthenticated())
  {
    $has_already_voted = RelevancyPeer::retrieveByPk($answer->getId(), $user->getSubscriberId());
    if ($has_already_voted)
    {
      // already interested
      return $name;
    }
    else
    {
      // didn't declare interest yet
      return link_to_remote($name, array(
        'url'      => 'user/vote?id='.$answer->getId().'&score='.($name == 'up' ? 1 : -1),
        'update'   => array('success' => 'vote_'.$answer->getId()),
        'loading'  => "Element.show('indicator')",
        'complete' => "Element.hide('indicator');".visual_effect('highlight', 'vote_'.$name.'_'.$answer->getId()),
      ));
    }
  }
  else
  {
    return link_to_function($name, visual_effect('blind_down', 'login', array('duration' => 0.5)));
  }
}

apps/frontend/modules/answer/templates/_vote_user.php を作成し、先ほどのヘルパー関数を使ってAJAX呼び出し部分にします。

<?php use_helper('Answer') ?>

<span class="vote_up_mark" id="vote_up_<?php echo $answer->getId() ?>">
  <?php echo $answer->getRelevancyUpPercent() ?>%
</span> <?php echo link_to_user_relevancy_up($sf_user, $answer) ?>

<span class="vote_down_mark" id="vote_down_<?php echo $answer->getId() ?>">
  <?php echo $answer->getRelevancyDownPercent() ?>%
</span> <?php echo link_to_user_relevancy_down($sf_user, $answer) ?>

先ほどのapps/frontend/modules/answer/templates/_list.php で以下の部分を置き換えます。

    <?php echo $answer->getRelevancyUpPercent() ?>% UP <?php echo $answer->getRelevancyDownPercent() ?> % DOWN

ここを結果スペースとなるdivタグで囲み、ヘルパー_vote_user.phpを読み込ませるように置き換えます。

    <div class="vote_block" id="vote_<?php echo $answer->getId() ?>">
      <?php echo include_partial('answer/vote_user', array('answer' => $answer)) ?>
    </div>

▽サーバ処理
最後にAJAXが呼び出すuser/voteアクションを作成します。apps/frontend/modules/user/actions/actions.class.php にexecuteVoteメソッドを追加します。

  public function executeVote()
  {
    $this->answer = AnswerPeer::retrieveByPk($this->getRequestParameter('id'));
    $this->forward404Unless($this->answer);

    $user = $this->getUser()->getSubscriber();

    $relevancy = new Relevancy();
    $relevancy->setAnswer($this->answer);
    $relevancy->setUser($user);
    $relevancy->setScore($this->getRequestParameter('score') == 1 ? 1 : -1);
    $relevancy->save();
  }

アクションがAJAXに返す結果ビューapps/frontend/modules/user/templates/voteSuccess.php は以下のようになります。

<?php echo include_partial('answer/vote_user', array('answer' => $answer)) ?>

最後に、AJAXに渡す結果にはレイアウトは不要なので、apps/frontend/modules/user/config/view.yml に以下の内容を追加しておきます。

voteSuccess:
  has_layout: off

■課題終わり
以上で完成です。"symfony cc"でキャッシュをクリアした後、動作を確認してみてください。
回答への評価機能実装完了

PR

この記事にコメントする

お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード   Vodafone絵文字 i-mode絵文字 Ezweb絵文字

この記事へのトラックバック

この記事にトラックバックする:

askeet day nine:local improvements の解説 HOME askeet day eight:AJAX interactions の解説

プロフィール

HN:
flyfront
性別:
非公開
自己紹介:
PHPプログラマ。東京でsymfonyな仕事してます。

HNはflyfrontですが、
仕事関係ではr_koike名義を使ってる場合もあります。

Wassr

カレンダー

11 2017/12 01
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

最新コメント

[01/02 通りすがり]
[10/18 flyfront]

バーコード

アクセス解析

忍者ブログ [PR]
Template by repe