忍者ブログ

uthorofotus iruc

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

[25]  [24]  [23]  [22]  [21]  [20]  [19]  [18]  [17]  [16]  [15

[PR]

×

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

askeet day ten:Alter data with Ajax forms の解説

askeetチュートリアルの10日目『AJAXフォームからのデータ操作』です。フォームの送信処理部分でAJAXを積極的に使っていきます。

10日目チュートリアルの日本語版はありません。本家英語版はこちらです。

■これまでのsymfony(Previously on symfony)
まだまだ機能が足りません。認証ユーザは質問の投稿だできるようにし、どのユーザも回答ができるようにします。

■新しい質問の追加(Add a new question)
レイアウトのサイドバーには質問を追加するquestion/addリンクがすでにあります。これを作っていきます。

▽認証ユーザのアクセス制限(Restrict access to registered users)
まず、認証ユーザのみがquestion/addアクションにアクセスできるように設定します。questionモジュールのconfig/security.ymlに、addアクションのアクセス制限設定をします。認証してないユーザがこのアクションにアクセスした場合は、アプリケーションの設定ファイル app/frontend/config/settings.ymlの login_module login_action で設定されたアクションにアクセスをします。

▽addSuccess.phpテンプレート(The addSuccess.php template)
まずはquestionモジュールにaddアクションとエラーハンドルのメソッドを追加します。とりあえずメソッド内容は空です。これらのメソッドはどちらもaddSuccess.phpテンプレートをビューとします。Validationヘルパーを読み込ませるのを忘れないでください。

<?php use_helper('Validation') ?>

ビュー内のフォーム値が、同名キーのリクエストパラメータで初期化されています。これは、バリデートが失敗した場合にこのフォームに処理が戻ってくるからです。そうすれば、ユーザはバリデートに失敗した部分だけ修正して再度フォームを送信することができます。

▽フォームのバリデート(Form validation)
バリデートする内容をquestionモジュールの下にvalidateディレクトリを作成し、そこで設定します。設定内容については6日目で説明した内容とほぼ同じ形式です。

■送信されたフォームの処理(Handle the form submission)
question/addアクションに送信されたフォーム値の処理を追加します。QuestionモデルのsetTitleとsetBodyはどちらも前のチュートリアルでオーバーライドしましたので、自動的にstripped_titleとhtml_bodyにも値が入ります。

このアクションメソッドでは返し値にforwardではなくredirectを使用しています。これは、後のページでブラウザのリロードによってフォームが再送信されるのを防ぎます。また、ブラウザの戻るボタンが上手く動くようになります。フォームの送信処理の際、forwardは使用しない方が良いです。

isInterestedInという見慣れないメソッドがあります。これは、質問を投稿したユーザは、きっとその質問の動向には注意を払うだろうということで、興味宣言を自動的にしています。このメソッドを、lib/model/User.phpにあるUserモデルに追加します。


新しい質問の登録後

■新しい回答の追加(Add a new answer)
回答は違ったやり方で実装します。AJAXを使うことにより、ページ遷移無しで即座に新しい回答を表示させます。

▽AJAXフォームの追加(Add the AJAX form)
question/showのテンプレートshowSuccess.phpに回答フォーム表示のAJAX機能を付けます。
8日目の課題で回答リストの表示にページャーを付けたところがありましたが、今日の内容と整合性が取れなくなったのでそこも直していきます。なお、Subversionのソースもパーシャルの使い方などおかしいような気がするので、手直してしている部分があります。

question/showテンプレートでは、asnwer/listパーシャルとanswerページャーを外し、回答表示部分はanswer/answerパーシャル(_answer.php)を代わりに使います。回答フォームはquestion/showテンプレートにそのまま記述します。チュートリアルではlistパーシャルに入れていますが、listで回答フォームを使うことは無いと思うのでquestion/showに置きました。ここでform_remote_tagヘルパー関数を使っていますが、Javascriptヘルパーがありません。それは、UserヘルパーにはJavascriptヘルパーの読み込むも含むようにしますので省略出来ます。

<?php use_helper('Date','User') ?>
 
<div class="interested_block">
  <?php include_partial('interested_user', array('question' => $question)) ?>
</div>
 
<h2><?php echo $question->getTitle() ?></h2>
 
<div class="question_body">
  <div>
    asked by <?php echo link_to($question->getUser(), '@user_profile?nickname='.$question->getUser()->getNickname()) ?>
    on <?php echo format_date($question->getCreatedAt(), 'f') ?>
  </div>
  <?php echo $question->getHtmlBody() ?>
</div>

<div id="answers">
<?php foreach ($answers as $answer): ?>
  <div class="answer">
    <?php include_partial('answer/answer', array('answer' => $answer)) ?>
  </div>
<?php endforeach ?>

<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>

asnwer/listパーシャル(_list.php)を修正します。回答1件を表示する部分にはanswer/answerパーシャルを使用するようにします。

<div id="answers">
<?php foreach ($answer_pager->getResults() as $answer): ?>
  <div class="answer">
    <?php include_partial('answer/answer', array('answer' => $answer)) ?>
  </div>
<?php endforeach ?>

</div>

answer/answerパーシャル(_answer.php)は以下のようになります。

<?php use_helper('Date') ?>

<div class="vote_block" id="vote_<?php echo $answer->getId() ?>">
  <?php echo include_partial('answer/vote_user', array('answer' => $answer)) ?>
</div>
posted by <?php echo link_to($answer->getUser(), '@user_profile?nickname='.$answer->getUser()->getNickname()) ?>
on <?php echo format_date($answer->getCreatedAt(), 'p') ?>
<div>
  <?php echo $answer->getHtmlBody() ?>
</div>

▽ちょっとリファクタリング(A little refactoring)
Userヘルパーに関数を追加します。SubversionではGlobalヘルパーへ登録していますが、ユーザ認証関連の機能なのでUserヘルパーに入れるべきでしょう。

<?php

use_helper('Javascript');

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)));
  }
}

function link_to_user_interested($user, $question)
{
-----略-----
  }
  else
  {
    return link_to_login('interested?');
  }
}

Answerヘルパー関数のなかには、link_to_login関数で置き換えられる部分がいくつがありますので修正しておきます。

----前略----

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

  if ($user->isAuthenticated())
  {
----略----
  }
  else
  {
    return link_to_login($name);
  }
}

その他には、sidebar/defaultのテンプレートにあるリンクが@add_questionになっているか確認します。

▽送信されたフォームの処理(Handle the form submission)
8日目とはちょっと違った処理方法をとります。8日目はリンクをクリックしたら処理が始まりましたが、今回はフォーム送信をしたらAJAXが始動するようになっています。なので、AJAXの結果を表示するスペースには、フォーム自身を含んだdivを指定しています。

※他にもいろいろ書かれていますが、内容がよく理解できません。link_to_loginヘルパー関数をGloablに置く理由もあるみたいですが、わかりません。

▽answer/addアクション(The answer/add action)
AJAXで呼び出される処理を実装します。ルーティングを設定、answer/addアクションとテンプレートの追加、ビュー精製時のレイアウト不使用設定をします。

answer/addアクションは、アクションを実装したのが認証ユーザであればそのユーザを質問投稿者として登録します。もし非認証ユーザであれば、"anonymous"(匿名)というユーザにします。

AJAXが返す結果ビューは今回答した内容1件を返せばいいので、answer/asnwerパーシャルを使います。また、レイアウトは使わないので、設定をオフにしておきます。

▽動作テスト(Test it)
キャッシュをクリアして、動作テストをしましょう。回答を記入してフォームを送信すると、フォームが消え、その場に新しい回答が黄色く光りながら表示されます。
回答フォーム入力

フォーム送信後に新回答が表示される

■また明日(See you Tomorrow)
11日はaskeetをユーザがより使いやすくするために、RSSフィードを付けます。

Subversionとチュートリアルの指示に従わなかった部分が幾つかあるので、もしかしたら後日困るかもしれません。とりあえずこのまま進めてみます。

PR

この記事にコメントする

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

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

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

askeet day eleven:syndication feed の解説 HOME askeet day nine:local improvements の解説

プロフィール

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

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

Wassr

カレンダー

05 2017/06 07
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

最新コメント

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

バーコード

アクセス解析

忍者ブログ [PR]
Template by repe