Итак, приступим к продолжению нашей интеграции AJAX и Zend Framework. Начнём с того, что планы несколько изменились – изначально я планировал разбить статью на три части, во второй части рассказав про работу с Zend_Form применительно к AJAX’у. Начав писать статью я понял, что рассказывать там решительно нечего – работа с AJAX’ом применяя Zend_Form не имеет каких-либо серьёзных особенностей.
Сейчас вы узнаете про хэлпер AjaxContext, делающий нашу работу с AJAX’ом ещё удобнее и проще.
Первая часть статьи

Часть 2. Работа с хэлпером AjaxContext

Хэлпер (помощник, helper) – это интегрированный в один из компонентов фреймворка (в нашем случае, в Zend_Controller_Action) класс, помогающий нам выполнять какие-то определённые действия. Подробнее о них вы можете почитать в документации
Принцип действия хэлпера AjaxContext заключается в том, что он заменяет шаблон вида на нужный нам формат вывода. Подробности его работы вы можете узнать, опять же, в документации,
а мы будем знакомиться с основами его работы на конкретном примере.
Помните, в чём заключался основной принцип работы в первой части статьи? Мы отслеживали AJAX-запросы, отключали автоматический рендеринг скриптов вида, и вручную выводили JSON-кодированные данные.
В этот раз мы поступим умнее:

1
2
3
4
5
public function init() {
    //активируем хэлпер AjaxContext
    //и передаём туда имя action'а, который необходимо интегрировать с AJAX'ом
    $this->_helper->AjaxContext()->addActionContext('login', 'json')->initContext('json');
}

Что делает этот хэлпер. В первую очередь, он отслеживает ajax-запросы и отключает для них авторендеринг скриптов вида. Затем, после выполнения action’а, хэлпер кодирует все данные, переданные в наш view-класс, кодирует их в формат JSON и выводит на экран (т.е. передаёт браузеру). Таким образом, нам больше не нужно задумываться на стороне сервера о том, откуда поступил запрос и как его нужно обработать, это всё перекладывается на плечи разработчиков клиентской части скрипта.
Вот наш переработанный action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public function loginAction()
{
    //проверяем, были ли посланы логин и пароль
    if (($login = $this->_getParam('login')) && ($password = $this->_getParam('password')))
    {
        //наш воображаемый класс авторизации
        $loginClass = new loginClass($login, $password);
        //проверяем валидность
        $result = $loginClass->isValid() ? 'success' : 'error';
        //если авторизация прошла успешно - в errors записываем пустой массив
        //иначе - получаем сообщения ошибкок
        $errors = 'success' == $result ? array() : $loginClass->getErrors();

        if ('success' == $result && !$this->getRequest()->isXmlHttpRequest())
        {
            //авторизация успешна - делаем редирект
            //если аякс - редирект нам не нужен :)
            $this->_redirect('/');
        }
        //передаём результаты в шаблон
        $this->view->errors = $errors;
        $this->view->result = $result;
    }
}

Теперь в случае ajax-запроса мы получим JSON-кодированные данные, а если запрос будет обычным – будет выведен обыкновенный шаблон.

25 Comments

  1. Anton Shevchuk says:

    Для реализации AJAX’a в ZF использую бибилотеку jQuery-PHP, используя ее нет необходимости писать еще один хэлпер, достаточно использовать существующий Url (хотя с помощью хэлпера можно упростить синтаксис)…

  2. guest says:

    Спасибо большое за информацию. Как раз осваиваю зенд.

  3. Hinikato says:

    Полезно, спасибо за статью ;)
    Не пользовался этим хелпером, заюзаю, посмотрю.

  4. Berkut says:

    Прикольная штучка! Сейчас попробую=). Огромное спасибо!!!

  5. Alexander says:

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

  6. Сергей Митрошин says:

    Вообще-то ajaxContext должен автоматически отключать layout. Если это по каким-либо причинам не произошло, то надо вручную вызывать статичный метод Zend_Layout::disableLayout().

  7. Alexander says:

    Спасибо

  8. Сергей Митрошин says:

    Можно даже добавить callback-метод для AjaxContext, в котором и вызывать disableLayout().

  9. Alesksey says:

    Спасибо, как всегда полезная статья.
    А отключить layout можно еще так:
    Zend_Controller_Action_HelperBroker::getStaticHelper(‘layout’)->disableLayout();

  10. Baron says:

    Сори, но я уже просто вешаюсь. РАботаю в Zend Studio. Скачал библиотеку jquery. Открыл в студии и в ней куча ошибок, при подключении файла на старнице, сразу сыпиться куча ошибок. И это без написания кода js. я вообще без понятия что делать. достал этот маразм… и нигде никакой информации по такому случаю… вот пишу вам – вдруг поможете

  11. Baron says:

    нихера и ничего не работает….. супер примеры…. студия все что можно только перечеркнула и подчеркнула

  12. Atapin says:

    есть такой вопрос.

    есть три поля select

    при выборе первого id=library
    происходит загрузка naviAction

    $(“#library”).change(function() {
    $(“#book”).load(“navigation/navi”, { id: $(“#library”).val() });
    });

    если вывод делать в ISON тогда не ясно как имя переменной, которую потом декодировать,
    если вывод делать в html то дублируется объект (помещается один в один)

    если не трудно, посоветуйте

  13. Atapin says:

    ах да,
    вывод в json делаю так:
    public function init() {
    $this->_helper->AjaxContext()->addActionContext(‘navi’, ‘json’)->initContext(‘json’);
    }

  14. Atapin says:

    к тому же, измененный объект уже не отправляет данные по событию change
    хотя Firebug показывает его.

  15. Atapin says:

    вот тут можно посмотреть http://bq.igmission.net/

  16. Jully says:

    Все замечательно, только вот отрабатывает у меня как-то неправильно:
    вместо готового html-куска, посылается объект(структура) с данными запрашиваемого экшена.

    Если этот экшен вызываю напрямую (из строки браузера) – то он конечно же отрабатывает и отображается в соотвествии с заданным шаблоном…. :(

  17. Jully says:

    class ChecknameController extends Basic_Controller{
    public function preDispatch(){
    parent::preDispatch();
    $this->_helper->layout()->disableLayout();
    $this->_helper->AjaxContext()->addActionContext(‘index’, ‘json’)->initContext(‘json’);
    }

    public function indexAction(){

    ……
    $this->view->result = SOME_VAL;
    }

    где-то на странице вызываем такую js-ф-ию:

    function checkName(name, type){
    $.get(
    ‘/checkname’,
    { name: name, type: type },
    function(data) {
    var targetDiv = document.getElementById(“nameCheck”);
    targetDiv.innerHTML = data;
    }
    );

  18. Jully says:

    конструкция такого вида
    $(“#nameCheck”).load(‘/checkname’, { name: name, type: type });
    так же дает прежний результат.

    такое ощущение, что по каким-то соображениям до обработки view дело не доходит.

    а вижу я структур вида:

    {“project”:”__NONE__”,”controller”:”checkname”,”area”:”checkname”,”action”:”index”,”result”:false}

  19. Oleg says:

    Спасибо за мануал. Только вопрос. Для какой версии ZF это писалось?

  20. oleg says:

    Спасибо, помогло :)

  21. cmygeHm says:

    Если имя Action’а содержит два слова и второе начинается с большой буквы, то у меня вылетает ошибка что такой экшен не существует.
    Как быть?

    Например для экшена с именем generateReportAction.

  22. Bob says:

    Здравствуйте!
    Интересная статья, попробовал сделать, но не получается…

    основная проблемма
    —————————
    $this->getRequest()->isXmlHttpRequest() – ничего не возвращает
    —————————

    кусочек моего вида (пробовал по всякому)
    ……….

    function submitform(login, password)
    {
    //посылаем наш аякс-запрос
    $.ajax({
    url:’http://полный путь к скрипту (назвал его login2)’,
    type: ‘POST’,
    dataType: “json”,
    { login: login, password: password },
    success: function(response){
    alert(‘Данные отправлены! Сервер вернул ответ: ‘ + response);
    }
    error: function(response){ alert(‘Данные отправлены! Сервер вернул ответ: ‘ + response);}
    complete: function(response){ alert(‘Данные отправлены! Сервер вернул ответ: ‘ + response);}
    });
    }

    …………….
    тут без изменений

    помогите выяснить плиз, почему $this->getRequest()->isXmlHttpRequest() – ничего не возвращает

    спасибо, надеюсь решение поможет и другим, кто столкнулся с такой проблеммой

  23. cmygeHm says:

    Боб! добавь data:

    dataType: “json”,
    data: { ‘login’: login, ‘password’: password }

  24. Bob says:

    dataType: “json” – не работает,(переда)
    dataType: “html” – работает!
    хотел бы научится передавать “json”
    где здесь собака зарыта ?

  25. 123 says:

    $this->_helper->AjaxContext()->addActionContext(‘login’, ‘json’)->initContext(‘json’);
    а вид кто будет оключать?

    AjaxContext():

    Выключает макеты, если они включены.

    Устанавливает альтернативный суффикс вида, это позволяет эффективно разделять скрипты видов для различных контекстов.

    Отправляет HTTP-заголовки ответа, требуемые в данном контексте.

    Опционально вызывает предопределенные функции обратного вызова для установки контекста и/или пост-обработки.

Leave a Reply