jQuery-PHP, AJAX и Zend Framework

jQuery-PHP, Ajax and Zend Framework

Как-то я уже рассказывал о библиотеке jQuery-PHP, и вот совсем недавно обнаружил, что она идеально сочетается с Zend Framework’ом.

Дабы сильно не закапываться, будет лучше всего привести пример реализации, начну с сервер-сайда, а именно со связки контроллера и экшена:

require_once 'Zend/Controller/Action.php';
/**
 * Ajax Controller
 */
class AjaxController extends Zend_Controller_Action
{
    /**
     * index Action
     * @return void
     */
    public function indexAction()
    {
        // check is AJAX request or not
        if (!$this->getRequest() -> isXmlHttpRequest()) {
             $this->getResponse()-> setHttpResponseCode(404)
                                 -> sendHeaders();
            $this->renderScript('empty.phtml');
            return false;
        }
        // requery php library
        require_once 'jQuery.php';
        // assign to div with id = 'test' current time
        jQuery('div#test')->html(date('H:i:s'));
    }
}

Чуть-чуть поясню – в первом условии проверяется действительно ли запрос осуществлен посредством AJAX’a, далее подключаем библиотеку jQuery и юзаем её.

Шаблон index.phtml для описанного выше экшена будет выглядеть следующим образом:

    require_once 'jQuery.php';
    // only jQuery response, nothing more
    jQuery::getResponse();

Еще нам понадобиться внести изменения в клиентскую часть, а именно подключить библиотеку в контроллере который нуждается в AJAX’е, к примеру так:

$this->view->headScript()->appendFile('/public/js/jquery.js');
$this->view->headScript()->appendFile('/public/js/jquery.php.js');

И непосредственно добавить вызов функции $.php({},{}) для какого-либо события:

<a href="#" onclick="javascript:$.php('<?php echo $this->Url(array('controller'=>'ajax', 'action'=>'index'));?>',{});return false;">click me</a>;

Как видите, можно перенаправить запрос на любой модуль, контроллер и экшен (см. описание хэлпера Url), а так же передать данные через GET или POST (второй параметр функции $.php как раз для этого и предназначен).

44 thoughts on “jQuery-PHP, AJAX и Zend Framework”

  1. Посмотрел на эту библиотеку (поверхностно), сложилось впечатление что это очень похоже на XAjax, который я не рекомендую. Дело в том что хотя это и удобно в контроллере динамически напрямую влиять на отображение через ajax-запросы, это усложняет и смешивает логику. Помоему всё-таки вся работа с DOM’ом если она ведётся в js, то это должно быть явно видно в js-файлах, иначе возникают проблемы с переносимостью (интеграцией) – эта библиотека напрямую завязывает не только js-обработчик, но и php’библиотеку.
    Кроме того связка php и js через такую библиотеку как правило ограничена коммандами, и их увеличение – просто изобретение колеса но уже в php. Вобщем не советую начинать писать серъёзные вещи так – после вас возможно кто-то будет в этом разбираться :)

  2. Да, согласен, данная библиотека похожа во многом на Xajax, по крайней мере своим поведением – но jQuery-PHP более универсальна, и нет необходимости наращивать код PHP для реализации новых функций в javascript’е (по крайней мере так планировалось).

    Могу конечно поспорить насчет смешивания логики и отображения – но единственный аргумент который я могу привести – это то, что AJAX сам по себе приводит к этому “ассорти”, и для разделения логики и отображения приходиться попотеть – передавать данные для построения DOMа, а не цельными кусками HTMLа (чем грешат многие разработчики)…

  3. да связка этой либы и ZF это самое то. вот я использую Zend Framework и могу сказать фактически логика приложения(ajax) разбиваеся на 2 составляющие:
    1. js-костыль который на клиенте обрабатывает запросы юзера
    2. действие в ZF

    по идее будущее такой либы как раз в обьединении логики в действии ZF и отказ от js-костылей. я думаю это следует подчернуть, и наштамповать практических примеров.

    пример:
    есть таблица, по нажатию на кнопку нужно перезаписать тело таблицы новыми данными полученными из действия через ajax, вот js-костыль для этого

    function OnForm(data) {
    if(data.error!=””) {
    $(“#message”).html(data.error);
    $(‘#message’).fadeIn(‘slow’);
    } else {
    $(“#message”).html(“Данные обновлены”);
    $(‘#message’).fadeIn(‘slow’);
    str = ”;
    $.each(data.log,function(i,n) {
    str += “<tr><td>”+n.num+”</td><td>”+n.date+”</td><td>”+n.name+”</td><td>”+n.type+”</td><td>”+n.message+”</td></tr>”;
    });
    $(‘table#logger tbody’).html(str);
    }
    $(‘#load2’).fadeOut(‘slow’);
    $(‘#submit’).attr(“disabled”,””);
    }

    $(document).ready(function(){
    $(‘#controlForm’).ajaxForm({
    dataType: ‘json’,
    beforeSubmit: function() {
    $(‘#submit’).attr(“disabled”,”disabled”);
    $(‘#load2’).fadeIn(‘slow’);
    $(‘#message’).fadeOut(‘slow’);
    return true;
    },
    success: OnForm
    });
    });

    что может предложить в этом случае jQuery-PHP, фактически либа может заменить js функцию OnForm, тоесть браузер получает не только сами данные с сервера, но и директивы что с этими данными делать, сорри примера того как бы выглядела замена на либе предоставить не могу, потому что еще не работал с ней даже.

    Спасибо автору, и вдохновения на развитие проекта!

  4. блин, это то единственное глупое, что закопалось в твоем неплохом блоге, вытри – дрянь полная. Мухи отдельно – котлеты отдельно, в чем прикол гененрировать код jQuery на стороне сервера и в её же синтаксисе(почти родном), CSS же ты так не генеришь?
    Автор этого класса просто повернулся на ООП и написал эту ахинею, смысла в нем не вижу вообще.

  5. не пойму зачем в скрипте вида делать:
    require_once ‘jQuery.php’;
    jQuery::getResponse();

    Такого еще не встречал, это что-то новое в MVC.
    А вот это обычно делается в скрипте вида:
    $this->view->headScript()->appendFile(‘/public/js/jquery.js’);
    $this->view->headScript()->appendFile(‘/public/js/jquery.php.js’);

    Только так:
    $this->headScript()…

    Нет это все конечно работать будет но логика мне непривычная

  6. Ну jQuery::getResponse() и должен быть в скрипте вида – т.к. данный метод отвечает за вывод JSON’a, перед тем он рекварится дабы не было ошибки, не пойму чем это не отвечает MVC?

    По поводу JS – это лишь пример подключения, который не претендует на подражание…

  7. ВЫ ИЗВИНИТЕ! Я не хотел обидеть, я не знаком с классом jQuery и не знаю всех тонкостей его работы, в моем понимании скрипты вида это шаблоны которые парсятся на основе данных установленных в объект вида в контроллере. А что нельзя
    require_once ‘jQuery.php’;
    jQuery::getResponse();
    вызвать из контроллера? на мой взгляд в данном случае скрипт вида вообще не нужен потому что он не выполняет своей функции, вы же ничего не парсируете. И рендеринг скрипта вида правильнее отключить. И на мой взгляд правильнее сформировать ответ из контроллера вызвав
    jQuery::getResponse();
    именно в контроллере, это конечно мое личное мнение, но в моем понимании так было бы правильнее.

  8. Все правильно – jQuery::getResponse() – лучше закинуть в контроллер, я так поначалу и сделал, но потом решил следовать модели MVC принятой в ZF – т.е. в скрипте вида должен формироваться ответ для браузера – вот он и был туда помещен, но похоже таким образом еще сильней всё запутал :)

  9. вывод вообще-то формируется в процессе диспетчеризации, путем добавления в объект ответа данных в указанные именованные сегменты. Думаю вы это и так знаете, а шаблоны вида нужны именно для разделения логики от дизайна, в данном случае ответ генерируется без использования видов потому нет смысла их использовать. Правильнее всего было бы направить результат jQuery::getResponse() в объект ответа что-то вроде:

    $this->getResponse()->appendBody(jQuery::getResponse([установить флаг возврата, содержимого]))

    Это если вообще делать правильно :) Рад что пришли к согласию.

  10. Почему-то так работает
    jQuery(‘div#test)->html(“word”);
    а вот так нет
    jQuery(‘div#test)->html(“слово”);
    в чем проблема ?

    вот эта строчка тоже кстати не работала
    jQuery::jQuery(‘div#test’)->html(date(‘H:i:s’));
    пришлось исправить на
    jQuery(‘div#test’)->html(date(‘H:i:s’));

  11. @Coffin:
    1. UTF-8? Или нет?
    2. В новой версии действительно “jQuery::jQuery()” уже не используется, в топике пофиксил.

  12. Ну так что ? Известно решение проблемы ?

  13. На выходных было не до программирования, какую ошибку хоть выдает? (посмотри FireBug’ом)

  14. Хотя чего смотреть-то json_encode не поддерживает windows-1251, в этом то и проблема…

  15. у меня огромнейшая прозьба выложить простой проектик jQuery + ZF я не ленивый просто все мои попытки нечего толком не дают. спасибо!

  16. Здравствуйте. ИМХО, для правильной реализации модели MVC, Вам нужно было написать хелпер, который бы выводил Вам JSON в скриптах вида. И вдобавок еще использовать Zend_JSON…

  17. @illusive:
    Изначально не предполагалось использовать jQuery-PHP для нужд только ZF’a, по этой причине я не использую Zend_JSON (который является лишь оберткой для zend_encode).

    Help’ер в ближайшее время напишу и выложу на суд общественности…

  18. 2 metallord
    Вообще-то по замыслу в шаблоне MVC, вид должен иметь доступ к данным модели, но использовать их только для отображения, вся работа по изменению, валидации и т.п. проходит в контроллере, который, в общем-то и выбирает, какое дейстие с моделью выполнить и какой вид рендерить. А если вид – это просто шабонный файл, который тупо парсится с использовнием данных из модели, но которые в виде передаются посредством View->Assign() в контроллере, то это уже другой шаблон.
    Смотрим сюда: http://www.garfieldtech.com/blog/mvc-vs-pac

  19. Подскажите плз решение проблемы, использую jQuery-PHP
    все как в приведенном примере, только вместо ссылки, инициализирующей действия, использую select

    при действии onChange в браузер выводиться код из экшена, но я не могу получить значение (value) для тега select..

    т.е. конструкции типа
    jQuery(‘#sh_type’)->value()
    jQuery(‘#sh_type’)->attr(‘value’)

    не работают…
    помогите разобраться с этим вопросом

  20. Подскажите плз решение проблемы, использую jQuery-PHP
    все как в приведенном примере, только вместо ссылки, инициализирующей действия, использую select

    <select id=”sh_type”
    onChange=”javascript:$.php(‘url(array(‘action’ =>’shdisplay’,’id’ => ‘as’),’ajax’)?>’,{});return false;”>

    ежедневно
    еженедельно
    ежемесячно

    при действии onChange в браузер выводиться код сформированный в экшене, но я не могу получить значение (value) из выбранного option’a для тега select в том же экшене

    т.е. конструкции типа
    jQuery(’#sh_type’)->value()
    jQuery(’#sh_type’)->attr(’value’)

    не работают…
    помогите разобраться с этим вопросом

  21. Варианты:
    $(“#sh_type option:selected”).val()
    jQuery(“#sh_type option:selected”).val()
    Ошибка:
    Call to undefined function val()

    $(“#sh_type option:selected”)->val()
    Ошибка:
    yntax error, unexpected ‘(‘, expecting T_VARIABLE or ‘$’

    jQuery(‘#sh_type option:selected’)->val()
    Ошибка
    Object of class jQuery_Element could not be converted to string

    последний вариант ближе к правде, как результат в строку отконвертить..

    1. Я написал JavaScript, т.е. полностью должно быть как-то так:


      И уже в PHP коде нуно ловить переменную sel

      Возможно я не совсем понимаю задачу…

  22. рабочий код, мож кому пригодится:


    class AjaxController extends Zend_Controller_Action
    {

    public function shdisplayAction()
    {
    // check is AJAX request or not
    if (!$this->getRequest() -> isXmlHttpRequest()) {
    $this->getResponse()-> setHttpResponseCode(404)
    -> sendHeaders();
    $this->renderScript('empty.phtml');
    return false;
    }

    jQuery('div#sh_container')->html($html_code);
    jQuery::getResponse();
    }
    }

    routes.php

    $router->addRoute('ajax',
    new Zend_Controller_Router_Route('ajax/:action', array('module' => 'default', 'controller' => 'ajax', 'action' => 'index'))
    );

    Огромное спс ,Anton Shevchuk, за помощь!

  23. поправка

    public function shdisplayAction()
    {
    // check is AJAX request or not
    if (!$this->getRequest() -> isXmlHttpRequest()) {
    $this->getResponse()-> setHttpResponseCode(404)
    -> sendHeaders();
    $this->renderScript('empty.phtml');
    return false;
    }

    switch($this->_getParam('type')){
    case "w":..break;
    case "m":..break;
    };

    jQuery('div#sh_container')->html($html_code);
    jQuery::getResponse();
    }
    }

  24. вопрос немного не по теме.
    а как указывать урл бэкэнда в аяксе?
    просто url=”controller/action” ?

      1. я использую JsHttpRequest…
        req.open(‘GET’, ‘Url(array(‘controller’=>’ajax’, ‘action’=>’index’));?>’, true); – так это будет выглядеть?

      1. но и обычный вид типа
        req.open(’GET’, ‘controller/action’, true); тоже должен работать?

  25. Обычный будет работать если вы не будете изменять дефолтный роут…

  26. Спасибо за разработку, Антон. Интеграция jQuery-PHP в ZendFramework оказалась лёгкой и элегантной. Однако она не может быть полной без поддержки скриптов вида. Вы уже обещали, что в ближайшее время выложите хелпер… стоит ли ждать?

    1. В архиве с бибилотекой есть хелпер для вида и экшен-хелпер, или какие-то еще нужны?

      1. Этот хэлпер лишь облегчает вывод javascript ссылки в скрипте вида. А как определить переменные вида, чтобы потом подставить их в каком нибудь шаблоне а-ля ajax.tpl
        Обычно в ZF контроллер передаёт переменные в скрипт вида так:

        $this->view->ajax = $ajax;

        Приведённом примере вывод делается так:

        $this->_helper->getHelper('Jquery')->sendResponse();

        Получается, что генерировать каркас html приходится в контроллере… поправьте, если можно по другому (хочется переменные отдельно, html отдельно)

  27. может я чего-то не допонимаю, но мне кажется, что лучше отключить редер страницы в аякс контроллере, примерно так

        public function init()
        {
            if($this->getRequest()->isXmlHttpRequest()) {
                Zend_Controller_Action_HelperBroker::removeHelper('viewRenderer');
            }
        }
  28. да и использовать вместо хелпера url(), лучше все же ajaxlink()
    если я не прав, поправьте
    а в целом пост очень неплохой, мне очень пригодился

Comments are closed.