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 в действии (action)

Тестирование 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 Russian for the 1.2 version - Propel 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 (Propel edition)
Support symfony!
Buy this book
or donate.
Buy Practical symfony (Propel edition) from amazon.com

Вчера мы внедрили очень мощный поисковый движок для Jobeet, благодаря библиотеке Zend Lucene.

Сегодня мы улучшим отклик поискового движка, мы используем преимущества AJAX для конвертации поискового движка в живой поиск.

Поскольку форма должна работать с включенным и выключенным JavaScript, функциональность живого поиска будет внедрена с помощью ненавязчивого JavaScript. Ненавязчивый JavaScript также дает лучшее разделение задач клиентского кода между HTML, CSS и JavaScript поведением.

Установка jQuery

Вместо изобретения колеса и управления множеством отличий между браузерами, мы будем использовать библиотеку JavaScript, jQuery. Фреймворк Symfony сам по себе не использует JavaScript и может работать с любой библиотекой.

Идем на сайт jQuery, скачиваем последнюю версию и кладем файл .js в папку web/js/.

Включение jQuery

Поскольку jQuery нам нужен на всех страницах, обновляем макет для включения ее в <head>. Будьте осторожны вставляя функцию use_javascript() перед вызовом include_javascripts():

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

Мы могли бы прямо включить файл jQuery с помощью тега <script>, но использование помощника (helper) use_javascript() гарантирует, что один и тот же файл JavaScript не будет включен дважды.

В целях производительности, вы можете поместить помощник include_javascripts() прямо перед конечным тегом </body>.

Добавление поведений

Внедрение живого поиска означает, что каждый раз, когда пользователь набирает букву в поле поиска, нужно послать запрос серверу; после этого сервер вернет требуемую информацию для обновления некоторых частей страницы без перезагрузки всей страницы.

Вместо добавления поведения с помощью HTML атрибутов on*(), основной принцип jQuery это добавить поведения в DOM-модель после того как страница будет полностью загружена. В этом случае если вы выключите поддержку JavaScript в вашем браузере, поведения не будут зарегистрированы, и форма будет продолжать работать так же как и раньше.

Первый шаг - это перехват ввода пользователя в поле поиска:

$('#search_keywords').keyup(function(key)
{
  if (this.value.length >= 3 || this.value == '')
  {
    // что-то сделать
  }
});

Пока что не добавляйте код, поскольку мы будем его сильно менять. Конечный код JavaScript будет добавлен в макет в следующей секции.

Каждый раз, когда пользователь нажимает кнопку, jQuery выполняет анонимную функцию определенную в коде выше, но только если пользователь набрал не менее 3 символов или удалил все из поля ввода.

Выполнение AJAX-запроса к серверу так же просто как использование метода load() для элемента DOM:

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

Для управления AJAX-запросом, будет вызвано тоже самое действие (action) как и для "нормального" запроса. Нужные изменения для действия будут закончены в следующей секции.

Последнее, но не менее важное, если 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 заработал, создайте файл search.js содержащий JavaScript, который мы написали ниже:

// 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 в действии (action)

Если JavaScript включен, jQuery будет перехватывать все нажатые кнопки в поле поиска и вызывать действие search. Если выключен, тоже самое действие search будет так же вызываться когда пользователь отошлет форму нажав на кнопку "enter" или кликнув по кнопке "search".

Теперь действие search должно определить был ли этот вызов сделан с помощью AJAX или нет. Если запрос был сделан с помощью AJAX, метод isXmlHttpRequest() объекта запроса вернет true.

Метод isXmlHttpRequest() работает со всеми большими библиотеками JavaScript как Prototype, Mootools, или jQuery.

// 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 = JobeetJobPeer::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 = JobeetJobPeer::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-запросов. Это в основном означает, что Вы должны вручную добавить заголовок, который 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 интернациональным.

День 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.