symfony askeet Day 10

  • Day 10に入る前に。
  • 新しい質問を追加できるようにする
  • 答え投稿フォームを作る

Day 7でやり忘れていたことをやる

Day 7のほうにちっちゃく

コードは少なくとも2つの場所で使われているので、私達はリファクタリングして、
qestion/showとanswer/recentの両方を使用されている_answer.phpの一部分を作成します。

http://www.symfony-project.org/askeet/1_0/ja/7

(※原文のまま)
とか書いてあるのをてっきり流してしまったのですが、ここで現実を見てやることにします。
なぜ、やるか。Day 10で転けるからです。
(メモをするのを忘れたが、そのままやると_answer.phpがねぇよと怒られる><)
場所: askeet/apps/frontend/modules/question/templates/showSuccess.php
askeet/apps/frontend/modules/answer/templates/recentSuccess.php
共通してどちらにもある↓を_answer.phpとして切り出す。
場所: askeet/apps/frontend/modules/answer/_answer.php

    <?php echo $answer->getRelevancyUpPercent() ?>% UP <?php echo $answer->getRelevancyDownPercent() ?> % DOWN
    posted by <?php echo $answer->getUser()->getFirstName().' '.$answer->getUser()->getLastName() ?> 
    on <?php echo format_date($answer->getCreatedAt(), 'p') ?>
    <div>
      <?php echo $answer->getBody() ?>
    </div>

切り出したら↑を切り出した部分に
showSuccess.php

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

recentSuccess.php

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

参考: http://develop.ddo.jp/new-tech/php/framework/symfony/memo/view/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E9%83%A8%E5%93%81%E5%8C%96%E3%81%A3%E3%81%A6
よし、できた><
Day 4は読み直す必要があるな…
ja:4日目: リファクタリング (1_0) - Symfony
en:Day 04: refactoring (1_0) - Symfony

新しい質問を追加できるようにする

ということで、仕切り直してDay 10を始めます。

ということでまず、登録ユーザー以外が登録できないようにしたい。

Day 6で作ったsecurity.ymlの確認をして
問題がなければaskeet/apps/frontend/config/setting.ymlの修正

all:
  .actions:
#    default_module:         default   # Default module and action to be called when
#    default_action:         index     # A routing rule doesn't set it
#
#    error_404_module:       default   # To be called when a 404 error is raised
#    error_404_action:       error404  # Or when the requested URL doesn't match any route
#
    login_module:           user      # To be called when a non-authenticated user
    login_action:           login     # Tries to access a secure page
そういえば、テンプレートがない。

ということで実装する。
まずはアクションの設定。
場所: askeet/apps/frontend/modules/question/actions/actions.class.php
に↓を書き足す。

  public function executeAdd()
  {
  }

  public function handleErrorAdd()
  {
    return sfView::SUCCESS;
  }

で、テンプレートを書く。
場所: askeet/apps/frontend/modules/question/templates/addSuccess.php

<?php use_helper('Validation') ?>
 
<?php echo form_tag('@add_question') ?>
 
  <fieldset>
 
  <div class="form-row">
    <?php echo form_error('title') ?>
    <label for="title">Question title:</label>
    <?php echo input_tag('title', $sf_params->get('title')) ?>
  </div>
 
  <div class="form-row">
    <?php echo form_error('body') ?>
    <label for="label">Your question in details:</label>
    <?php echo textarea_tag('body', $sf_params->get('body')) ?>
  </div>
 
  </fieldset>
 
  <div class="submit-row">
    <?php echo submit_tag('ask it') ?>
  </div>
</form>

保存する場所を間違いやすいので注意した方がいいですね。
自分はさっきanswerに保存していて気づかなくてどうして動かないんだと悩んでました。

次はバリデーション

場所: askeet/apps/frontend/modules/question/validate/add.yml

methods:
  post:              [title, body]

names:
  title:
    required:        Yes
    required_msg:    You must give a title to your question
  body:
    required:        Yes
    required_msg:    Your must provide a brief context for your question

bodyValidator:
    class:           sfStringValidator
    param:
      min:           10
      min_error:     Please, give some more details


バリデーションが出るようになった><

実際の投稿を受け付ける

投稿データを受け付けられるように編集する。
場所: askeet/apps/frontend/modules/question/actions/actions.class.php
さっきは空だったexecuteAdd()の中に書く。

  public function executeAdd()
  {

    if($this->getRequest()->getMethod() == sfRequest::POST)
      {
        // create question (質問を作る)
        $user = $this->getUser()->getSubscriber();

        $question = new Question();
        $question->setTitle($this->getRequestParameter('title'));
        $question->setBody($this->getRequestParameter('body'));
        $question->setUser($user);
        $question->save();

        $user->isInterestedIn($question);

        return $this->redirect('@question?stripped_title='.$question->getStrippedTitle());
      }

  }

$user->isInterestedInを用意する。
場所: askeet/apps/frontend/modules/user/actions/actions.class.php

  public function isInterestedIn($question)
  {
    $interest = new Interest();
    $interest->setQuestion($question);
    $interest->setUserId($this->getId());
    $interest->save();
  }
答え投稿フォームを作ろう。

質問は投稿できるようになったけど答えが投稿できないので作りましょう。
場所: askeet/apps/frontend/modules/question/templates/showSuccess.php

<div id="answers">
<?php foreach ($question->getAnswers() as $answer): ?>
  <div class="answer">
  <?php include_partial('answer/answer', array('answer' => $answer)) ?>
  </div>
<?php endforeach; ?>
 
<?php echo use_helper('User') ?>
 
<div class="answer" id="add_answer">
  <?php echo form_remote_tag(array(
    'url'      => '@add_answer',
    'update'   => array('success' => 'add_answer'),
    'loading'  => "Element.show('indicator')",
    'complete' => "Element.hide('indicator');".visual_effect('highlight', 'add_answer'),
  )) ?>
 
    <div class="form-row">
      <?php if ($sf_user->isAuthenticated()): ?>
        <?php echo $sf_user->getNickname() ?>
      <?php else: ?>
        <?php echo 'Anonymous Coward' ?>
        <?php echo link_to_login('login') ?>
      <?php endif; ?>
    </div>
 
    <div class="form-row">
      <label for="label">Your answer:</label>
      <?php echo textarea_tag('body', $sf_params->get('body')) ?>
    </div>
 
    <div class="submit-row">
      <?php echo input_hidden_tag('question_id', $question->getId()) ?>
      <?php echo submit_tag('answer it') ?>
    </div>
  </form>
</div>
 
</div>

link_to_login()を追加する。
場所: askeet/apps/frontend/lib/helper/UserHelper.php

  function link_to_login($name,$uri = null)
  {
    if($uri && sfContext::getInstance()->getUser()->isAuthenticated())
      {
        return link_to($name,$uri);
      }
      else
      {
        return link_to_function($name, visual_effect('blind_down','login',array('duration' => 0.5)));
      }
  }
つぎはアクションを書く。

その前にadd_answerをrouting.ymlに追加する。
場所: askeet/apps/frontend/config/routing.yml

add_answer:
  url:   /add_answer
  param: { module: answer, action: add }

できたら、アクションを書く。
場所: askeet/apps/frontend/modules/answer/actions/actions.class.php

  public function executeAdd()
  {
    if($this->getRequest()->getMethod() == sfRequest::POST)
      {
        if(!$this->getRequestParameter('body'))
          {
            return sfView::NONE;
          }

        $question = QuestionPeer::retrieveByPk($this->getRequestParameter('question_id'));
        $this->forward404Unless($question);

        // normal user or anonymous user (ふつーのユーザーか匿名ユーザー)
        $user = $this->getUser()->isAuthenticated() ? $this->getUser()->getSubscriber() : UserPeer::retriveByNickname('anonymous');

        // answer
        $this->answer = new Answer();
        $this->answer->setQuestion($question);
        $this->answer->setBody($this->getRequestParameter('body'));
        $this->answer->setUser($user);
        $this->answer->save();

        return sfView::SUCCESS;
      }

    $this->forward404();
  }


答えも投稿できました><