Понимание Zend Framework, Часть 9: Добавление интерактивности с помощью Ajax и JSON

В серии статей "Понимание Zend Framework" мы используем PHP Zend Framework для создания онлайновой программы для чтения лент (feed reader), Chomp, и сейчас самое время сделать заключительный штрих, чтобы программа стала удобнее. Эта статья показывает, как использовать Ajax для добавления информации на страницу без перезагрузки всей страницы, и как использовать Zend Framework для ускорения обработки запросов пересылкой данных в и из JavaScript Object Notation (JSON).

Николас Чейз (Nicholas Chase), президент, Chase and Chase, Inc.

Николас Чейз (Nicholas Chase), автор Studio B , занимается разработкой Web-сайтов для таких компаний, как Lucent Technologies, Sun Microsystems, Oracle и Tampa Bay Buccaneers. Ник работал школьным преподавателем физики, управляющим предприятия по утилизации малоактивных радиоактивных отходов, редактором онлайнового журнала по научной фантастике, специалистом по мультимедиа и инструктором Oracle. Не так давно он занимал пост главного директора по технологиям компании Site Dynamics Interactive Communications в Клируотере, Флорида, США. Автор четырех книг по Web-разработке, включая XML Primer Plus (издательство Sams). Ник всегда рад получить комментарии от читателей, которые можно присылать по адресу nicholas@nicholaschase.com.



14.06.2007

Введение

В восьмой части этой серии мы добавляли результаты Yahoo!, Amazon и Flickr в приложение Chomp. Теперь мы собираемся усовершенствовать программу, загружая только те данные, которые запросил пользователь, и только когда он запросил. Но сначала давайте посмотрим, где мы находимся.

Как мы здесь оказались

Эта девятая статья из серии "Понимание Zend Framework" – одна из частей хронологии создания онлайновой программы для чтения лент, Chomp, объясняющая основные аспекты использования уже упоминавшегося продукта с открытым исходным кодом - PHP Zend Framework.

В первой части мы говорили об основных понятиях Zend Framework, включая список релевантных классов и обсуждение шаблона MVC (Model-View-Controller). Во второй части мы показали, как МVC работает в приложении Zend Framework. Также мы осуществляли регистрацию пользователей и процесс входа в систему, добавляя информацию о пользователе в базу данных и извлекая ее обратно.

В частях 3 и 4 мы имели дело с фактическим RSS- и Atom-лентами. В третий части мы показывали пользователям, как подписываться на индивидуальные ленты и отображать элементы данных из списков в этих лентах. Мы также обсуждали некоторые возможности Zend Framework по обработке формы, контролю данных и отбору элементов данных ленты. Часть 4 объясняет, как создавать Proxy-сервер для извлечения данных с сайта, не имеющего ленту.

Остальные статьи данной серии вносят дополнительный вклад в приложение Chomp. Часть 5 объясняет, как использовать модуль Zend_PDF , чтобы пользователь мог создавать свой собственный PDF-файл сохраненных статей, картинок и осуществлять поиск. В шестой части мы использовали модуль Zend_Mail для извещения пользователей о новых сообщениях. В седьмой части мы осуществляли поиск по сохраненным документам и получали упорядоченные результаты. В восьмой части мы добавляли дополнительные размеры нашему reader-у, связывая ресурсы Amazon.com, Yahoo! и Flickr с нашим текущим приложением, для создания надежного mashup - приложения, объединяющего данные нескольких источников.

В последней статье серии мы будем использовать Ajax и компонент Zend Framework - Zend_Json, чтобы автоматически обновить часть страницы поиска с определенной запрашиваемой информацией.


Итак, что же такое Ajax и JSON?

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

В основном нет необходимости в замещении всей страницы, когда вы всего лишь хотите обновить строку. Вместо этого более удобным было бы оставить страницу на месте и просто добавить или изменить информацию, которая уже есть. Для этого разработчики используют комбинацию HTTP, JavaScript и иногда XML. Это программное mashup использовалось в относительной неясности процесса в течении многих лет. Тем не менее, ему присвоили имя Ajax (Asynchronous JavaScript и XML) и он стал феноменом. Процесс Ajax заставляет браузер отсылать запросы HTTP в фоновом режиме. Когда он получает данные, он добавляет их на страницу, обычно в качестве div элемента.

Теперь об XML. В общем и целом хорошо подходящий для запросов Web-сервера, XML не всегда хорошо отображается в браузере. Оказывается, внутри JavaScript объекты представлены как простые строки, которые мы можем сами создавать и дешифровать вручную. К примеру, взгляните на объект ниже, который вы можете создать самостоятельно.

Листинг 1. Создание объекта
var theFeed = new Object();
theFeed.title = "Chaos Magnet";
theFeed.url = "http://feeds.feedburner.com/ChaosMagnet";

Вместо этой строки может быть представлена другая – строка JSON, показанная ниже.

{"title":"Chaos Magnet",
  "url":"http://feeds.feedburner.com/ChaosMagnet"}

Может показаться, что это не слишком просто, однако постарайтесь осмыслить тот факт, что практически каждый язык программирования имеет целый алгоритм перевода своих родных объектов в такую форму. А эта возможность позволяет создавать объект JavaScript, отсылать его как строку JSON в алгоритм PHP, который переводит ее в родной объект PHP. Объект PHP затем переводится обратно в строку JSON, который возвращается как результат Web-сервера в язык JavaScript, который превращает его опять в родной объект JavaScript.

Мы можем даже посылать и возвращать эти строки в качестве запросов Ajax. Но сначала нам нужно сделать небольшую реструктуризацию приложения Chomp.


Разбиение запросов

Итак, когда пользователь выполняет поиск, действие viewSearchResults в FeedController не только создает поисковые результаты как таковые, но также выполняет запрос в сервисы Amazon и Flickr и встраивает их в общий просмотр. Одна из проблем, связанных с этим, - задержка результата, т.к. запросы в Web-серверах редко выполняются быстро. И если разместить два запроса на одной странице, можно действительно сильно замедлить процесс выполнения.

Первым делом при создании запроса Ajax нужно разбить его на отдельные составляющие. Например, мы можем переместить результаты Amazon и Flickr из общего просмотра, viewedSearchResults.php, в их собственные файлы, amazonView.php и flickrView.php.

Листинг 2. amazonView.php
<h4>Вы искали какие-нибудь книги?</h4>
<ol>
<?php
  foreach ($this->amazonHits as $result) {
    echo "<li><img src='" .
 $result->SmallImage->Url->getUri() .
         "' width='" . $result->SmallImage->Width .
         "' height='" . $result->SmallImage->Height . "' /> ";
    echo "<a href='" . $result->DetailPageURL . "' title='" .
         htmlentities($result->Title, ENT_QUOTES). " at Amazon.com'>";
    echo "<strong>" . htmlentities($result->Title) .
         "</strong></a>";
        echo " (Ranked #" . $result->SalesRank . ")</li>";
  }
?>
</ol>

Это тот же код, что был при общем просмотре. Мы просто передвинули его в отдельный файл. Проделаем то же самое с результатами Flickr (см. Листинг 3).

Листинг 3. flickrView.php
<table>
<caption>Фотографии от <a
 href="http://flickr.com/">Flickr</a></caption>

<tbody>
<?php

foreach ($this->flickrHits as $index=>$result) {
    // Начинаем колонку (column)
    if ( $index % $this->columns == 0 ) {

      echo '<tr>';
    }

    $thumbnail = '<img src="' . $result->Square->uri .
                 '" width="75" height="75" />';
    echo '<td><a href="' . $result->Large->clickUri .
         '" title="to Flickr">' . $thumbnail . '</a><br />';
    echo '<small>by <a href="http://www.flickr.com/photos/' .
 $this->escape($result->ownername) .
         '" title="Owner">' . htmlentities($result->ownername) .
         '</a> on ' . $result->datetaken .
 '</small></td>';
    
    // Закрываем колонку
    if ( $index % $this->columns == $this->columns - 1 ) {
      echo '</tr>';
    }
}
?>
</tbody>
</table>

Разместим оба файла (amazonView.php и flickrView.php) в директории просмотра.

Обновление общего просмотра

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

Листинг 4. Упрощение viewSearchResults.php
...
         $title = $feedTitle;
         if($channelTitle != '')
             $title = "$title > $channelTitle";
         echo "<tr><td>#" . $i++ . ":</td>";
         echo "<td><a href=\"$url\">$title</a></td>";
         echo "<td>$score</td></tr>";
     }
  ?>
  </table>

<?php echo($this->renderedAmazon) ?>

<?php echo($this->renderedFlickr) ?>

</body>
</html>

Чтобы сделать эти данные доступными, нужно обновить FeedController.

Листинг 5. Обновление FeedController.php
    public function viewSearchResultsAction()
    {
...
        $view = Zend::registry('view');
        $view->title = "Search Results for: $query";
        $view->hits = $hits;

        $amazonView = Zend::registry('view');
        require_once 'Zend/Service/Amazon/Query.php';

        $key = 'YOUR_AMAZON_KEY_HERE';
        $amazonQuery = new Zend_Service_Amazon_Query($key);
        $amazonQuery->Category('Books')
                  ->Keywords($filterGet->getRaw('query'))
                  ->ResponseGroup('Medium');

        $amazonView->amazonHits = $amazonQuery->search();
        $view->renderedAmazon = $amazonView->render('amazonView.php');

        $flickrView = Zend::registry('view'); 
        $key = 'f50c3c5b6384493f20e69b70b9ff7d29';
        $flickrQuery = new Zend_Service_Flickr($key);
        $tags = explode(' ', $filterGet->getRaw('query'));
        $flickrView->flickrHits = $flickrQuery->tagSearch($tags);
        $view->renderedFlickr =
 $flickrView->render('flickrView.php');

        echo $view->render('viewSearchResults.php');
    }

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

В результате должна появиться страница, которая в точности повторяет рисунок 1.

Рисунок 1. Обработанные результаты
Обработанные результаты

Разница в том, что теперь мы можем управлять отдельными частями данных.

Создание новых ссылок

Следующим шагом будет совместное удаление данных из основного просмотра и перемещение их вместе со ссылками, которыми мы можем при необходимости воспользоваться. Чтобы это выполнить, измените файл viewedSearchResults.php так, как показано ниже.

Листинг 6. Перемещение содержимого со ссылками
...
         echo "<tr><td>#" . $i++ . ":</td>";
         echo "<td><a href=\"$url\">$title</a></td>";
         echo "<td>$score</td></tr>";
     }
  ?>
  </table>


<center><p>
<a href="javascript:getMashup('amazon')" 
target="_blank">Show related books</a> 
| 
<a href="javascript:getMashup('flickr')" 
target="_blank">Show related photos</a>
</p></center>

</body>
</html>

Эти ссылки еще не активны. Скоро мы создадим функцию getMashup(), при перезагрузке поисковой страницы вы увидите результат, отображенный на рисунке 2.

Рисунок 2. Отображение новых ссылок
Отображение новых ссылок

Создание нового действия mashup

Перед тем, как создать функцию JavaScript, которая запросит новые данные, мы должны создать действие, которое JavaScript будет вызывать. В данном случае мы создаем новое действие, mashupAction, которое поддерживает тип mashup и запросы и возвращает соответствующие данные, как показано ниже.

Листинг 7. Добавление нового действия в FeedController.php
...
    public function viewSearchResultsAction()
    {
...
        $view = Zend::registry('view');
        $view->title = "Search Results for: $query";
        $view->hits = $hits;

        $view->query = $query;

        echo $view->render('viewSearchResults.php');
    }

    public function mashupAction()
    {
        $filterGet = Zend::registry('fGet');
        $type = $filterGet->getRaw('type');

        if ($type == 'amazon'){
            $amazonView = Zend::registry('view');
            require_once 'Zend/Service/Amazon/Query.php';

            $key = 'YOUR_AMAZON_KEY_HERE';
            $amazonQuery = new Zend_Service_Amazon_Query($key);
            $amazonQuery->Category('Books')
                      ->Keywords($filterGet->getRaw('query'))
                      ->ResponseGroup('Medium');

            $amazonView->amazonHits = $amazonQuery->search();
            echo $amazonView->render('amazonView.php');
        }

        if ($type == 'flickr'){
            $flickrView = Zend::registry('view'); 
            $key = 'YOUR_FLICKR_KEY_HERE';
            $flickrQuery = new Zend_Service_Flickr($key);
            $tags = explode(' ', $filterGet->getRaw('query'));
            $flickrView->flickrHits = $flickrQuery->tagSearch($tags);
            echo $flickrView->render('flickrView.php');
        }

    }
...

Во-первых, отметим, что мы удаляем лишнюю информацию из viewSearchResultsAction. Во-вторых, мы создаем mashupAction, которое поддерживает два параметра с использованием фильтром GET: type и query. В зависимости от типа type действие обеспечивает просмотр Amazon или Flickr.

Вы можете просмотреть это действие, указав местонахождение вашего браузера в http://localhost/feed/mashup?type=flickr&query=pentagon или URL с тем же запросом. Результат должен быть похож на рисунок 3.

Рисунок 3. Просмотр нового действия mashup
Просмотр нового действия mashup

Также вы можете изменить параметр type на amazon, чтобы увидеть другие данные. Мы включим эти данные в страницу результата поиска, но только при необходимости.

Теперь можно начать добавление Ajax к нашему приложению.


Добавление Ajax

Процесс добавления Ajax на страницу всегда был мучительным. Одних только различий в браузерах было достаточно, чтобы отпугнуть многих разработчиков. К счастью, этот процесс был упрощен появлением некоторых бесплатных инструментов. В нашей статье мы будем использовать Prototype Framework. Загрузите "простой JavaScript" с http://prototype.conio.net/ и сохраните файл в корневом документе Web-сервера. На момент написания статьи последней версией является 1.4.0.

Мы можем использовать эту библиотеку, включив ее на страницу и оставив ссылку к объекту Ajax, как показано ниже.

Листинг 8. Добавление Ajax к viewSearchResults.php
<html>
<head>

    <script src="/prototype.js"></script>

    <title><?php echo $this->escape($this->title);
 ?></title>

    <script type="text/javascript">

        function getMashup(mashupType){
            var url = 'http://localhost/feed/mashup';
            var myAjax = new Ajax.Request
                         (
                             url,
                             {
                                 method: 'get', 
                                 parameters:   
               'type='+mashupType+'&query=<?php echo $this->query
 ?>', 
                                 onSuccess: renderResults
                             }
                         );

        }

        function renderResults(response){

            var renderDiv = document.getElementById('mashupResults');
            renderDiv.innerHTML = response.responseText;

        }

    </script>


</head>
<body>
  [<a href='/'>Back to Main Menu</a>]<br>
  <h1><?php echo $this->escape($this->title); ?></h1>
...
<center><p>
<a href="javascript:getMashup('amazon')">Show related books</a> 
| 
<a href="javascript:getMashup('flickr')">Show related photos</a>
</p></center>

<div id="mashupResults"></div>

</body>
</html>

Сначала мы добавляем библиотеку на страницу. (Мы переименовали ее на prototype.js для удобства.) Установка библиотеки в корневом документе позволяет нам ссылаться на нее, не загромождая код ее действительным местонахождением.

Далее мы создаем функцию getMashup(), которая создает новый запрос Ajax.Request. Атрибутом этого запроса является адрес URL – заметьте, что это действие mashup для FeedController – и ряд параметров, включая выбор метода (GET или POST), параметры, посылаемые с запросом, и действия JavaScript для выполнения запроса, когда он возвращается.

В данном случае функция renderedResults() принимает запрос HTTP как параметр. Эта функция просто получает ссылку к новому div-элементу mashupResults, который мы добавляем, и устанавливает содержимое как текст ответа.

Так как этот текст в HTML, пользователь может выбрать одну из ссылок и увидеть результат добавления на странице, как показывает рисунок 4.

Рисунок 4. Результат Ajax
Результат Ajax

Добавление JSON

Этот процесс стал проще, чем был раньше. На самом деле он и был совершенно простым. Единственная сложность здесь – это то, что, в сущности, в браузере возникает один большой текстовый фрагмент. Теперь это уже не имеет значения, поскольку мы отображаем это все на одной странице, но в большинстве случаев такой результат нежелателен. Итак, перед тем как закончить, посмотрим, как можно по-другому решить проблему с запросами: JSON.

Начнем с JavaScript. Вместо отсылки параметров запроса mashup как пар имен, мы создадим объект JavaScript, в который включим эти пары как атрибуты.

Листинг 9. Создание объектного запроса JavaScript
<html>
<head>

    <script src="/prototype.js"></script>
    <script src="/json.js"></script>

    <title><?php echo $this->escape($this->title);
 ?></title>

    <script type="text/javascript">

        function getMashup(mashupType){

            var requestObject = new Object();
            requestObject.type = mashupType;
            requestObject.query = '<?php echo $this->query ?>';

            var jsonRequest = requestObject.toJSONString();

            alert(jsonRequest);

            var url = 'http://localhost/feed/mashup';
            var myAjax = new Ajax.Request(
                                          url,
                                          {
                                              method: 'get', 
                                              parameters: 
                                  'request='+escape(jsonRequest), 
                                              onSuccess: renderResults
                                          }
                                         );

        }
...

Мы добавляем вторую библиотеку, доступную на http://www.json.org/js.html. Эта библиотека добавляет две новые функции в JavaScript: toJSONString() и parseJSON().

Далее создаем простой объект и устанавливаем значения его атрибутов. Как и прежде, этот запрос закодирован процессом просмотра PHP. Мы можем напрямую обратиться к этому объекту, строке JSON, и добавить его к запросу как параметр. Если мы отображаем строку в текстовом окне, то это должно выглядеть так, как показано на рисунке 5.

Рисунок 5. Текст JSON
Текст JSON

Затем мы должны обновить метод mashupAction(), чтобы он соответствовал новым данным.

Листинг 10. Введение текста JSON в mashupAction()
...
    public function mashupAction(){
        $filterGet = Zend::registry('fGet');
        $request = $filterGet->getRaw('request');

        $requestObject = Zend_Json::decode($request,
                                           Zend_Json::TYPE_OBJECT);
        $type = $requestObject->type;
        $query = $requestObject->query;

        if ($type == 'amazon'){
            $amazonView = Zend::registry('view');
            require_once 'Zend/Service/Amazon/Query.php';
...

Вместо того, чтобы разделять запрос по атрибутам type и query, мы вырезаем одну строку из текста, $request, и, используя компонент Zend_Json, превращаем его в родной объект PHP. (Если вы отбросите второй параметр метода decode(), то, скорее всего, вместо объекта появится матрица). Затем мы можем вырезать атрибуты type и query так же, как и атрибуты других объектов PHP.

Возврат объекта JSON оказывается не такой уж и простой задачей, но не из-за сложности технологии. Компонент Zend_JSON также включает метод encode(), поэтому мы можем сделать так:

echo Zend_Json::encode($amazonQuery->search());

Этот процесс происходит – предоставляются результаты JSON – но процесс этот, к сожалению, недостаточно глубок. Например, объект, получаемый в результате, относится адресу URI рисунка, но не к атрибуту url. Во многих случаях это не проблема, но так как объект ответа Amazon слишком сложен, мы не будем просто выбирать информацию, необходимую нам для создания собственного объекта.

Начнем с создания классов Amazon, как показано ниже.

Листинг 11. Создание классов Amazon
class AmazonResults 
{

   public $results = array();

}

class AmazonResult 
{

   public $salesrank = null;
   public $imgUri;
   public $imgWidth;
   public $imgHeight;
   public $detailPage;
   public $title; 
   public $salesRank; 

}

Разместите эти классы в любом подходящем месте. С точки зрения PHP вы могли бы разместить эти классы в файле FeedController.php (кроме описания класса, разумеется), но с точки зрения Zend Framework, вы можете разместить их в директории модели, которая находится в том же месте, что и контроллер, и изображения.

Эти классы не несут никаких функций; они существуют лишь для обеспечения имени объектов, которые они представляют. Мы можем создать анонимные объекты, но вы окажетесь в затруднении, когда попробуете найти отдельные объекты, относящиеся к одной строке JSON.

А теперь мы можем создать собственные объекты, как показано ниже.

Листинг 12.Создание объектов результата Amazon
...
        if ($type == 'amazon'){
            require_once 'Zend/Service/Amazon/Query.php';

            $key = 'YOUR_AMAZON_KEY_HERE';
            $amazonQuery = new Zend_Service_Amazon_Query($key);
            $amazonQuery->Category('Books')
                      ->Keywords($query)
                      ->ResponseGroup('Medium');

            $responseObject = new AmazonResults();

            foreach ($amazonQuery->search() as $result) {

                $resultObject = new AmazonResult();

                $resultObject->imgUri = 
                                
 $result->SmallImage->Url->getUri();
                $resultObject->imgWidth =
 $result->SmallImage->Width;
                $resultObject->imgHeight =
 $result->SmallImage->Height;
                $resultObject->detailPage = $result->DetailPageURL;
                $resultObject->title = htmlentities($result->Title); 
                $resultObject->salesRank = $result->SalesRank; 

                array_push($responseObject->results, $resultObject); 

            }
            echo Zend_Json::encode($responseObject);
        }

        if ($type == 'flickr'){
            $key = 'YOUR_FLICKR_KEY_HERE';
...

Прежде всего, создайте общий объект, как пример для класса AmazonResults. Сделайте это для каждого результата поиска, выделяя из каждого необходимую нам информацию и добавляя ее к новому объекту AmazonResult. Каждый из объектов результата добавляется к массиву результатов нового объекта. Мы можем закодировать объект и отправить его обратно в браузер.

Сейчас страница просто отображает любую строчку, которую мы отсылаем обратно. Если вы выполняете запрос, то можете увидеть реальный текст JSON на странице, как это показано на рисунке 6.

Рисунок 6. Возвращенный текст JSON
Возвращенный текст JSON

Все, что нам нужно сделать сейчас, - это настроить функцию renderResults(), чтобы она сообщалась с объектом во время отправки.

Листинг 13. Управление последним ответом
...
 function renderResults(response){

     var responseObject = response.responseText.parseJSON();

     var outputString = '<ol>';
     for (i=0; i < responseObject.results.length; i++) {
         thisResult = responseObject.results[i];
         outputString += '<li><img src="' + thisResult.imgUri;
         outputString += '" width="' + thisResult.imgWidth;
         outputString += '" height="' + thisResult.imgHeight + '" /> ';
         outputString += '<a href="' + thisResult.detailPage + '">';
         outputString += '<strong>' + thisResult.title + 
                                                '</strong></a>';
         outputString += ' (Ranked #' + thisResult.salesRank + 
                                                ')</li>';
     }
     outputString += '</ol>';

     var renderDiv = document.getElementById('mashupResults');
     renderDiv.innerHTML = outputString;
 }
...

Сначала мы должны получить ссылку к реальному объекту. Для этого нужно применить метод parseJSON() к тексту ответа. Получив объект, мы можем управлять им, как и любым другим объектом в JavaScript. В данном случае мы формируем вывод результатов. Чтобы сделать это, мы должны просматривать массив результатов каждый раз при получении ссылки к отдельному элементу и его атрибутам. Исследуя каждый результат, мы просто выводим его на страницу, как и прежде.

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


Заключение

Таким образом, мы подошли к завершению нашего проекта. В этой серии, начав с нуля, мы смогли упростить использование процесса создания интерактивного Chomp!-reader'а с помощью Zend Framework. Это приложение выполняет обычные задания в интернете, такие как обработка формы, а также менее традиционные задания, как, например, интерпретация лент RSS и Atom, и еще менее привычные задания – динамическая генерация файлов PDF.

Конечно, приложение само по себе не закончено. Мы создали только основу, скелет, в который нужно вдохнуть жизнь с помощью графического дизайна, возможного изменения (или даже повторного изменения) базы данных и некоторых современных деталей, таких как способность динамического добавления новой формы, которая не существует в текущем режиме работы системы.

Но, не смотря ни на что, процесс был увлекательным и очень продуктивным – он затребовал гораздо меньше работы благодаря использованию Zend Framework. Сама система Zend Framework тоже изменяется и расширяется. К тому времени как вы прочитаете эту статью, система пополнится функциональными новшествами, которые облегчат ее использование.


Загрузка

ОписаниеИмяРазмер
Исходный код Части 9os-php-zend9.source.zip12KB

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=230829
ArticleTitle=Понимание Zend Framework, Часть 9: Добавление интерактивности с помощью Ajax и JSON
publish-date=06142007