Practical symfony

18日目: AJAX

You are currently browsing
the website for symfony 1

Visit the Symfony2 website


About

You are currently reading "Practical symfony" which is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.

Jobeet Links

Master symfony

Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).
trainings.sensiolabs.com

Books on symfony

Learn more about symfony with the official guides.
books.sensiolabs.com

L'audit Qualité par SensioLabs

200 points de contrôle de votre applicatif web.
audit.sensiolabs.com

Chapter Content

jQueryをインストールする

jQueryをインクルードする

ふるまいを追加する

ユーザーのフィードバック

アクションにおけるAJAX

AJAXをテストする

また明日

symfony training
Be trained by symfony experts
Feb 21: Köln (Getting Started with Symfony2 - English)
Feb 27: Köln (Mastering Symfony2 - English)
Mar 05: Köln (Web Development with Symfony2 - Deutsch)
Mar 05: Montreal (Web Development with Symfony2 - English)
Mar 05: Montreal (Getting Started with Symfony2 - English)
and more...

Search


powered by google
You are currently browsing "Practical symfony" in Japanese for the 1.2 version - Doctrine edition - Switch to version: - Switch to ORM: - Switch to language:
Creative Commons License This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
This version of symfony is not maintained anymore.
If some of your projects still use this version, consider upgrading as soon as possible.
Practical symfony (Doctrine edition)
Support symfony!
Buy this book
or donate.
Buy Practical symfony (Doctrine edition) from amazon.com

昨日は、Zend Luceneライブラリのおかげで、Jobeet用のとても強力な検索エンジンを実装しました。

今日は、検索エンジンのレスポンスを強化するために、検索エンジンをライブ検索エンジンに変換するAJAXを利用します。

JavaScriptの有無に関わらずフォームは動作するので、ライブ検索機能は控えめなJavaScriptを利用して実装します。 控えめなJavaScriptを利用することでHTML、CSSとJavaScriptのふるまいの間のコードの関心の分離も可能になります。

jQueryをインストールする

車輪の再発明とブラウザーの間の多くの違いを管理するのを避けて、JavaScriptライブラリのjQueryを使います。 symfonyフレームワーク自身は任意のJavaScriptライブラリで動作します。

jQueryの公式サイトに移動し、最新バージョンをダウンロードし、.jsファイルをweb/js/に設置します。

jQueryをインクルードする

すべてのページでjQueryが必要なので、<head>の前でこれをインクルードするためにレイアウトを更新します。 include_javascripts()呼び出しの前にuse_javascript()関数を差し込んでいることに注目してください:

<!-- apps/frontend/templates/layout.php -->
 
  <?php use_javascript('jquery-1.2.6.min.js') ?>
  <?php include_javascripts() ?>
</head>

<script>タグでjQueryファイルを直接インクルードできますが、use_javascript()ヘルパーを使うことで同じJavaScriptファイルが2回インクルードされないことが保証されます。

パフォーマンス上の理由から、include_javascripts()ヘルパーの呼び出しを</body>閉じタグの直前に移動させるとよいでしょう。

ふるまいを追加する

ライブ検索を実装することは、検索ボックスでユーザーが文字を入力するたびに、サーバーの呼び出しが必要であるを意味します; サーバーはページ全体をリフレッシュせずページの一部を更新するために必要な情報を返します。

jQueryの背景にある主要な原則はon*()HTML属性でふるまいを追加する代わりに、ページが完全にロードされた後でDOMにふるまいを追加することです。 この方法によって、ブラウザーでJavaScriptのサポートを無効にする場合、ふるまいは何も登録されず、フォームは以前のとおりに動作します。

最初のステップは検索ボックスでユーザーがキーを入力するときにこれを傍受することです:

$('#search_keywords').keyup(function(key)
{
  if (this.value.length >= 3 || this.value == '')
  {
    // 何かを行う
  }
});

後で大きく修正するので、今はコードを追加しないでください。 次のセクションで最終的なJavaScriptコードはレイアウトに追加されます。

ユーザーがキーを入力するたびに、jQueryは上記のコードで定義される匿名関数を定義しますが、ユーザーが3文字以上を入力した場合、もしくはinputタグからすべてを削除した場合のみです。

サーバーでAJAX呼び出しを行うにはDOM要素でload()メソッドを使うだけなのでシンプルです:

$('#search_keywords').keyup(function(key)
{
  if (this.value.length >= 3 || this.value == '')
  {
    $('#jobs').load(
      $(this).parents('form').attr('action'), { query: this.value + '*' }
    );
  }
});

AJAX呼び出しを管理するために、"普通"のものとして同じアクションが呼び出されます。 アクションの必要な変更は次のセクションで行われます。

最後に大事なことですが、JavaScriptが有効な場合、検索ボタンを削除したい場合は次のとおりです:

$('.search input[type="submit"]').hide();

ユーザーのフィードバック

AJAX呼び出しを行うとき、ページはすぐに更新されません。 ブラウザーはページを更新する前に戻ってくるサーバーのレスポンスを待ちます。 一方で、何が起きているのか知らせるためにユーザーに視覚的なフィードバックを提供する必要があります。

慣習としてAJAX呼び出しの間にローダーのアイコンが表示されます。 ローダーの画像を追加してデフォルトでこれを隠すためにレイアウトを更新します:

<!-- apps/frontend/templates/layout.php -->
<div class="search">
  <h2>Ask for a job</h2>
  <form action="<?php echo url_for('@job_search') ?>" method="get">
    <input type="text" name="query" value="<?php echo $sf_request->getParameter('query') ?>" id="search_keywords" />
    <input type="submit" value="search" />
    <img id="loader" src="/images/loader.gif" style="vertical-align: middle; display: none" />
    <div class="help">
      Enter some keywords (city, country, position, ...)
    </div>
  </form>
</div>

デフォルトのローダーはJobeetの現在のレイアウトに最適化されます。 独自のものを作りたければ、http://www.ajaxload.info/ のようなフリーのオンラインサービスがたくさん見つかります。

これでHTMLを動作させるために必要なすべてのピースが用意されたので、これまで書いてきたJavaScriptを含むsearch.jsファイルを作ります:

// web/js/search.js
$(document).ready(function()
{
  $('.search input[type="submit"]').hide();
 
  $('#search_keywords').keyup(function(key)
  {
    if (this.value.length >= 3 || this.value == '')
    {
      $('#loader').show();
      $('#jobs').load(
        $(this).parents('form').attr('action'),
        { query: this.value + '*' },
        function() { $('#loader').hide(); }
      );
    }
  });
});

この新しいファイルをインクルードするためにレイアウトも更新する必要があります。

<!-- apps/frontend/templates/layout.php -->
<?php use_javascript('search.js') ?>

アクションにおけるAJAX

JavaScriptが有効な場合、jQueryは検索ボックスに入力されたすべてのキーを傍受し、searchアクションを呼び出します。 そうではない場合、ユーザーがフォームを投稿するときに"enter"キーを押すもしくは"search"ボタンをクリックすることで同じsearchアクションも呼び出されます。 ですので、searchアクションは呼び出しがAJAX経由か否かを決定する必要があります。 AJAX呼び出しによってリクエストが行われるときは、リクエストオブジェクトのisXmlHttpRequest()メソッドはtrueを返します。

isXmlHttpRequest()メソッドはPrototype、MooToolsもしくはjQueryのような主要なJavaScriptライブラリすべて動作します。

// apps/frontend/modules/job/actions/actions.class.php
public function executeSearch(sfWebRequest $request)
{
  if (!$query = $request->getParameter('query'))
  {
    return $this->forward('job', 'index');
  }
 
  $this->jobs = Doctrine::getTable('JobeetJob')->getForLuceneQuery($query);
 
  if ($request->isXmlHttpRequest())
  {
    return $this->renderPartial('job/list', array('jobs' => $this->jobs));
  }
}

jQueryはページをリロードしませんが、DOM要素の#jobsをレスポンスの内容に置き換えることだけを行うので、ページはレイアウトによってデコレートされません。 これは共通のニーズなので、AJAXリクエストがやってくるときレイアウトはデフォルトで無効です。

さらに、完全なテンプレートを返す代わりに、job/listパーシャルの内容を返すことだけが必要です。 アクションで使われるrenderPartial()メソッドはレスポンスとして完全なテンプレートの代わりにパーシャルを返します。

ユーザーが検索ボックスのすべての文字を削除する場合、もしくは検索が結果を返さない場合、空白ページの代わりにメッセージを表示する必要があります。

シンプルなテキストをレンダリングするにはrenderText()メソッドを使います:

// apps/frontend/modules/job/actions/actions.class.php
public function executeSearch(sfWebRequest $request)
{
  if (!$query = $request->getParameter('query'))
  {
    return $this->forward('job', 'index');
  }
 
  $this->jobs = Doctrine::getTable('JobeetJob')->getForLuceneQuery($query);
 
  if ($request->isXmlHttpRequest())
  {
    if ('*' == $query || !$this->jobs)
    {
      return $this->renderText('No results.');
    }
    else
    {
      return $this->renderPartial('job/list', array('jobs' => $this->jobs));
    }
  }
}

renderComponent()メソッドを使うことでアクションにコンポーネントを返すこともできます。

AJAXをテストする

symfonyブラウザーはJavaScriptをシミュレートできないので、AJAX呼び出しをテストする際にsymfonyを手助けすることが必要です。 これはjQueryと他の主要なJavaScriptライブラリはリクエストで送信するヘッダーを手動で追加する必要があることを意味します:

// test/functional/frontend/jobActionsTest.php
$browser->setHttpHeader('X_REQUESTED_WITH', 'XMLHttpRequest');
$browser->
  info('5 - Live search')->
 
  get('/search?query=sens*')->
  with('response')->begin()->
    checkElement('table tr', 2)->
  end()
;

setHttpHeader()メソッドはブラウザーで行われるすぐ次のリクエストに対してHTTPヘッダーを設定します。

また明日

昨日は、検索エンジンを実装するためにZend Luceneライブラリを使いました。 今日は、よりレスポンスを強化するためにjQueryを使いました。 symfonyフレームワークは簡単にMVCアプリケーションを開発して他のコンポーネントと連携するための すべての基本的なツールを提供します。 いつものように、求人用のベストなツールを使うことを心がけてください。

明日は、JobeetのWebサイトを国際化する方法を見ます。

19日目: 国際化とローカライゼーション »
« 17日目: 検索

Questions & Feedback

If you find a typo or an error, please register and open a ticket.

If you need support or have a technical question, please post to the official user mailing-list.