framework.zend.com
Stable релиз 2.0 / 1.12

Использование Zend_Amf и Adobe Flex SDK.

К комментариям

Содержание

Введение

Одним из важных организационных моментов в разработке RIA является вопрос выбора и реализации механизма «общения» приложения в браузере с серверными компонентами. В данной статье, написанной по мотивам англоязычного руководства Get to know Flex and Zend_Amf, рассмотрен частный случай решения этого вопроса с помощью связки Adobe Flex с компонентом Zend Framework — Zend_Amf.

Для тех кто не знает что такое Adobe Flex, или знаком с этой технологией «понаслышке», автор должен заметить, что знакомство стоит потраченного на него времени. Flex – это набирающая популярность технология разработки веб-ориентированных и прикладных (посредством Adobe AIR) интерфейсов и многофункциональных приложений. Достаточно часто Flex сравнивают с JavaScript, потому что время от времени эти технологии сменяют друг друга в решении каких-то задач по реализации сложных интерфейсов. Неплохой обзор на тему такого сравнения можно прочитать вот в этой статье: Общий обзор Flex-а и связки PHP&Flex. В качестве дополнительного вводного материала в данной статье даются рекомендации по началу знакомства с Adobe Flex.

Рекомендации по началу изучения Flex

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

Для начала знакомства с Flex и Flex Builder IDE лучше всего начать с прочтения соответствующих разделов в википедии и на официальном сайте Adobe. Потом, читателю стоит ознакомится с тем, что из себя представляют составляющие Flex: декларативный язык описания интерфейсов MXML и объектно-ориентированный язык программирования Action Script 3. В качестве учебника по принципам программирования на языке Action Script 3 вполне подойдет материал с официального сайта на русском языке: Программирование на Action Script 3.0. Также, полезными могут оказаться такие русскоязычные ресурсы, как http://flasher.ru/ и http://wiki.flash-ripper.com/, многочисленные русско- и англоязычные блоги.

Вплане инструментария, существует несколько подходов к разработке Flex приложений. О различных IDE, редакторах и ручной компиляции в swf файлы читатель сможет, при желании, без труда найти информацию самостоятельно. Однако автор настоятельно рекомендует использовать IDE от Adobe – Adobe Flex Builder (пример разрабатываемый в статье написан с использованием версии 3.0.2), потому что этот вариант наиболее комфортен. В случае если для разработки на PHP и Zend Framework читатель использует Zend Studio for Eclipse, то он может установить Adobe Flex Builder в виде плагина,- вероятно, это будет наиболее удобным вариантом.

Перед тем как приступить к чтению оставшихся частей статьи, автор должен заметить, что он предполагает знакомство читателя с тем, что такое Zend Framework, как его установить и использовать его компоненты и, также, имеет некоторый базовый опыт разработки приложений с использованием Adobe Flex.

Формат AMF

AMF – это бинарный формат передачи данных, позволяющий вызывать методы серверных объектов удаленно из Flex приложения. Использование этого формата более предпочтительно чем использование XML или JSON с точки зрения скорости передачи данных. Также он более удобен, так как на сервере не придется делать никаких дополнительных действий для преобразования объектов или данных, ими возвращаемых (которые в свою очередь тоже могут быть объектами) в XML или JSON.

PHP не поддерживает AMF формат по умолчанию, поэтому для реализации связки PHP-Flex необходимо использовать одно из существующих решений: php расширение AMFPHP, библиотека WebORB или компонент Zend_Amf. В данной статье будут рассматриваться аспекты реализации данной связки только с использованием компонента Zend_Amf.

Компонент Zend_Amf предназначен для работы с протоколом AMF и доступен как часть Zend Framework начиная с версии 1.7.

Разработка приложения

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

Перед началом разработки необходимо произвести следующие подготовительные действия:

  • Подготовка каталога для размещения файлов. Необходимо настроить веб-сервер так, чтобы каталог открывался по адресу http://zendamf/ (этот адрес использовался в приложении статьи, читатель может использовать любой другой, например http://localhost)
  • Необходимо включить каталог с Zend Framework в indlude_path. Автор сделал это путем добавления полного пути к фреймворку в php.ini. Также возможно использование функции set_include_path непосредственно в скрипте Zend_Amf сервиса.
  • Так как серверная компонента приложения работает с базой данных, необходимо её предварительно создать. Автор использовал в качестве СУБД MySql версии 5.0.45-community-nt, хотя, так как для работы с базой данных используется компонент Zend_Db, выбор СУБД может быть и другим. В качестве имени базы данных было использовано 'testdb'. Имя базы данных также может быть любым другим, разумеется.
  • Для хранения пользователей нужно создать таблицу 'users' с четырьмя полями:
    • id – Идентификатор пользователя, int(11)
    • name — Имя пользователя, varchar(255)
    • login — Логин пользователя, varchar(255)
    • email — Адрес электронной почты пользователя, varchar(255)
  • Добавить одну тестовую запись в таблицу с любыми данными.

Sql запросы на создание таблицы с тестовой записью для MySql:

 CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) NOT NULL,
`login` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `users` VALUES (1, 'Alexander Steshenko', 'lcf', 'lcf@example.com');

Реализацию поставленной задачи можно условно разделить на две части: проектирование и программирование серверной части приложения, и разработка клиентской части на Flex.

Разработка приложения. Программирование веб-сервиса

Для работы с пользователями реализованы два класса: User — класс представляющий одного пользователя и класс Users, предоставляющий функционал по управлению пользователями. Функционал классов достаточно примитивен, и полностью понятен из тщательно прокомментированных исходных кодов

Файл User.php

 <?php
/**
 * Класс представляющий модель пользователя.
 * 
 * @author Steshenko Alexander (http://lcf.name)
 * @license http://framework.zend.com/license/new-bsd New BSD License
 */
class User
{
  /**
  * Идентификатор пользователя
  *
  * @var integer
  */
  public $id;
   
  /**
  * Имя пользователя
  *
  * @var string
  */
  public $name;
   
  /**
  * Логин (никнейм) пользователя
  *
  * @var string
  */
  public $login;
   
  /**
  * Адрес электронной почты
  *
  * @var string
  */
  public $email;
   
  /**
  * Конструктор. В качестве необзатятельного параметра принимает 
  * массив с данными пользователя.
  *
  * @param array $userData данные пользователя
  */
  public function __construct($userData = null)
  {
  if ($userData != null) {
  $this->id = $userData['id'];
  $this->name = $userData['name'];
  $this->login = $userData['login'];
  $this->email = $userData['email'];
  }
  }
}

Файл Users.php

 <?php
/** User */
require_once 'User.php';

/**
 * Класс для управления пользователями
 * 
 * @author Steshenko Alexander (http://lcf.name)
 * @license http://framework.zend.com/license/new-bsd New BSD License
 */
class Users
{
  /**
  * Подключение к бд
  *
  * @var Zend_Db_Adapter_Abstract
  */
  protected $_db;
   
  /**
  * Конструктор. Получает из регистра и сохраняет
  * для внутренних нужд ссылку на объект подключения к бд.
  *
  */
  public function __construct()
  {
  $this->_db = Zend_Registry::get('db');
  }
   
  /**
  * Добавление нового пользователя
  *
  * @param User $user
  */
  public function add(User $user)
  {
  $userData = array(
  'name' => $user->name,
  'login' => $user->login,
  'email' => $user->email
  );
  $this->_db->insert('users', $userData);
  }
   
  /**
  * Сохранение измененного пользователя в базе данных
  *
  * @param User $user
  */
  public function save(User $user)
  {
  $userData = array(
  'name' => $user->name,
  'login' => $user->login,
  'email' => $user->email
  );
  $this->_db->update('users', $userData, 'id = ' . $user->id);
  }
   
  /**
  * Удаление пользователя по его идентификатору
  *
  * @param integer $userId
  */
  public function deleteById($userId)
  {
  $this->_db->delete('users', 'id = ' . $userId);
  }
   
  /**
  * Получение массива с пользователями
  *
  * @return array
  */
  public function getAll()
  {
  $usersArray = $this->_db->fetchAll(
  $this->_db->select()->from('users', '*')
  );
  $users = array();
  foreach ($usersArray as $userData) {
  $users[] = new User($userData);
  }
   
  return $users;
  }
   
}

Главный файл серверной части приложения, service.php в котором используется Zend_Amf_Server также тщательно прокомментирован и выглядит следующим образом:

 <?php
/**
 * Zend_Amf сервис предоставляющий доступ к объекту Users
 * Для управления пользователями
 *
 * @copyright 2009 Steshenko Alexander (http://lcf.name)
 * @license http://www.zend.com/license/3_0.txt PHP License 3.0
 */
 
/*
 * Подключение необходимых компонент Zend Framework
 */

/** Zend_Aml_Server */
require_once('Zend/Amf/Server.php');

/** Zend_Db */
require_once('Zend/Db.php');

/** Zend_Config */
require_once('Zend/Config.php');

/** Zend_Registry */
require_once('Zend/Registry.php');

/**
 * Подключение объекта по управлению пользователями
 */
require_once('Users.php');

// Определяем настройки подключения к базе данных
$config = new Zend_Config(array(
  'adapter' => 'pdo_mysql',
  'params' => array(
  'host' => 'localhost',
  'username' => 'user',
  'password' => 'pass',
  'dbname' => 'testdb',
  'driver_options'=> array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8')
  )
));

// Создание объекта подключения к базе данных
$db = Zend_Db::factory($config);

// Сохранине объекта подключения в регистре
Zend_Registry::set('db', $db);

// Создание сервера Zend_Amf
$server = new Zend_Amf_Server();

// Добавляем класс к серверу
$server->setClass("Users");

// Связываем php класс User с одноименным action script классом User
$server->setClassMap("User", "User");

// И, наконец, позволяем AMF серверу сделать всю остальную работу
echo $server->handle();

Положив все три файла в каталог вебсервера, убедимся что компонент amf сервера работает. Для этого откроем в браузере страницу http://zendamf/service.php. Результат должен быть следующим:

Термин Endpoint в данном случае обозначает ресурс, которому могут быть адресованы сообщения.

Если результат другой и отображаются какие-либо ошибки, их желательно исправить до того как приступить к разработке клиентской части приложения.

Разработка приложения. Flex

Автор для наглядности демонстрации предмета статьи решил не рассматривать аспекты структурирования приложения на Flex и подходы к реализации тех или иных шаблонов проектирования. Поэтому весь основной код программы будет расположен в главном файле проекта — zendamf.mxml. В целом, структура каталогов и файлов представляет из себя следующее:

Назначение каждого файла будет рассмотрено ниже, так как логично будет начать описание процесса разработки с подготовки визуальной части приложения.

Flex приложение должно предоставлять следующие возможности по управлению серверными объектами:

  • обеспечивать просмотр записей о всех пользователях
  • предоставлять возможность добавления нового пользователя
  • редактировать данные о пользователе
  • удалять любого пользователя из списка

С помощью декларативного языка описания интерфейсов MXML и режима 'Design' в среде Flex Builder IDE, реализовать необходимый интерфейс не составит абсолютно никакого труда. У автора, он представляет из себя панель, содержащую таблицу для отображения данных, форму для добавления и пару управляющих кнопок. Читатель может собрать такой интерфейс с учетом личных пожеланий по внешнему виду, у автора же получилось следующее:

Тут стоит заметить, что автор использовал в качестве компонента для отображения таблицы с данными не обычный DataGrid, а его расширенный вариант DoubleClickDataGrid (класс которого описывается в файле /classes/controls/DoubleClickDataGrid.as), нужный для того чтобы редактирование элементов в таблице начиналась по двойному, а не по одинарному клику на ячейке. В принципе, это не является обязательным условием и носит чисто эстетический характер, поэтому пользователь может использовать обычный DataGrid. В таком случае, файл DoubleClickDataGrid.as из проекта можно удалить.

MXML описание получившейся панели:

 <mx:Panel width="484"
  height="400"
  layout="vertical"
  title="Управление пользователями"
  paddingBottom="5"
  paddingLeft="5"
  paddingRight="5"
  paddingTop="5"
  horizontalAlign="center"
  horizontalCenter="-5"
  verticalCenter="17"
  borderColor="#2A2929"
  color="#F5F5F5">

  <controls:DoubleClickDataGrid id="usersDataGrid"
  width="446"
  height="100%"
  editable="true"
  itemEditEnd="onSaveClick(event)"
  color="#171717"
  alternatingItemColors="[#DAD9D9, #FFFFFF]">
  <controls:columns>
  <mx:DataGridColumn headerText="Имя"
  dataField="name"/>
  <mx:DataGridColumn headerText="Логин"
  dataField="login"/>
  <mx:DataGridColumn headerText="Email"
  dataField="email"/>
  </controls:columns>
  </controls:DoubleClickDataGrid>

  <mx:HBox width="453">
  <mx:Form color="#0B0B0B">

  <mx:FormItem label="Имя"
  horizontalAlign="left">
  <mx:TextInput id="nameTextInput"/>
  </mx:FormItem>
  <mx:FormItem label="Логин">
  <mx:TextInput id="loginTextInput"/>
  </mx:FormItem>
  <mx:FormItem label="Email">
  <mx:TextInput id="emailTextInput"/>
  </mx:FormItem>

  <mx:Button label="Добавить пользователя"
  click="onAddClick(event)"
  color="#141414"/>
  </mx:Form>
  <mx:Button label="Удалить пользователя"
  click="onDeleteClick(event)"
  color="#141414"
  textAlign="right"
  width="172"/>

  </mx:HBox>
</mx:Panel>

Далее автор решил рассмотреть создание конфигурационного файла с описанием расположения веб сервиса для разрабатываемого Flex приложения.

Файл services-config.xml:

 <?xml version="1.0" encoding="UTF-8"?>
<services-config>
  <services>
  <service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
  <destination id="zend">
  <channels>
  <channel ref="my-zend"/>
  </channels>
  <properties>
  <source>*</source>
  </properties>
  </destination>
  </service>
  </services>
  <channels>
  <channel-definition id="my-zend" class="mx.messaging.channels.AMFChannel">
  <endpoint uri="http://zendamf/service.php" class="flex.messaging.endpoints.AMFEndpoint"/>
  </channel-definition>
  </channels>
</services-config>

Читателю может потребоваться отредактировать строчку <endpoint uri="http://zendamf/service.php" class="flex.messaging.endpoints.AMFEndpoint" /> с учетом специфических настроек веб-сервера.

Данный конфигурационный файл подключается в приложение с помощью установки параметра компиляции -service с полным значением пути месторасположения конфигурационного service-config.xml файла. У автора эта строка имеет следующий вид: -services "D:\articles\zendamf\public\services-config.xml". В Flex Builder IDE такие параметры можно указывать в разделе Flex Compiler свойств проекта.

Для использования удаленного сервиса в главном файле проекта необходимо добавить его описание. Автор сделал это с помощью MXML:

 <mx:RemoteObject id="remoteUsers"
  destination="zend"
  source="Users"
  showBusyCursor="true">
  <mx:method name="getAll"
  result="onGetAllResult(event)"/>
</mx:RemoteObject> 

Метод getAll – один из методов удаленного объекта (класса Users). Описывать таким образом все методы удаленного объекта не обязательно, однако может быть полезно, если необходимо определить обработчик для события result. В данном случае, автор таким образом определил обработчик onGetAllResult, для того чтобы назначить полученные методом данные как источник данных для DataGrid.

На сервере имеется еще один тип объектов - класс User, предназначенный для представления данных одного пользователя. (Объекты таких классов являются так называемыми Value Object, поэтому часто именуются как: UserVO,- возможно читатель сочтет удобным такой подход). Для Flex части приложения такой класс тоже должен быть описан, как модель для хранения данных о пользователе.

Файл /models/User.as:

 package classes.models
{
 [RemoteClass(alias="User")]

 [Bindable]
 public class User
 {
  public var id:int;
  public var name:String;
  public var login:String;
  public var email:String;

 }
}

Все что осталось сделать — написать функции обработчики для следующих событий:

  • загрузка данных о пользователях с сервера
  • нажатие кнопки удаления пользователя
  • нажатие кнопки добавления пользователя
  • завершение редактирования ячейки с данными о пользователе

Обработчики должны вызывать методы удаленного объекта (например remoteUsers.deleteById(user.id)) и читатель может вполне реализовать эти функции сам, либо изучить код автора, содержащий подробные комментарии:

 <mx:Script>
  <![CDATA[
  import mx.controls.Button;
  import classes.controls.DoubleClickDataGrid;
  import mx.events.DataGridEvent;
  import classes.models.User;
  import mx.controls.DataGrid;
  import mx.controls.dataGridClasses.DataGridColumn;
  import mx.controls.Alert;
  import mx.rpc.events.FaultEvent;
  import mx.rpc.events.ResultEvent;
  import mx.collections.ArrayCollection;

  /**
  * Обработчик события DataGridEvent.ITEM_EDIT_END
  */
  private function onSaveClick(event:DataGridEvent):void
  {
  // Получаем объект DataGrid
  var dataGrid:DataGrid=DataGrid(event.target);
  // Получаем значение ячейчки
  var newPropertyValue:String=dataGrid.itemEditorInstance["text"];
  // Получаем редактируемое свойство (name, email или login)
  var dataField:String=event.dataField;
  // Создаем объект User на основе данных _до_редактирования_
  var user:User=User(event.itemRenderer.data)
  // Сравниваем старое значение свойства с новым
  if (newPropertyValue == user[dataField])
  {
 // Если данные не поменялись, выходим из функции
 return;
  }
  // Устанавливаем значение нового свойства
  user[dataField]=newPropertyValue;
  // Сохранение пользователя, используя метод удаленного объекта
  remoteUsers.save(user);
  // Отображение окна с сообщением об успешном сохранении
  Alert.show("Пользователь изменен", "Zend Amf Example");
  }

  /**
  * Обработчик события ResultEvent.RESULT
  */
  private function onGetAllResult(event:ResultEvent):void
  {
  // Устанавливаем данные возвращенные сервером в DataGrid
  usersDataGrid.dataProvider=event.result as Array;
  }

  /**
  * Обработчик события нажатия на кнопку добавления пользователя.
  */
  private function onAddClick(event:Event):void
  {
  // Создаем объект User
  var user:User=new User();
  // Определяем его свойства
  user.name=nameTextInput.text;
  user.login=loginTextInput.text;
  user.email=emailTextInput.text;
  // Добавляем используя удаленный вызов метода
  remoteUsers.add(user);
  // Сбрасываем значения
  nameTextInput.text="";
  loginTextInput.text="";
  emailTextInput.text="";
  // Обновляем значения DataGrid
  remoteUsers.getAll();
  // Отображение окна с сообщением об успешном добавлении
  Alert.show("Пользователь добавлен", "Zend Amf Example");
  }

  /**
  * Обработчик события нажатия на кнопку удаления пользователя
  */
  public function onDeleteClick(event:Event):void
  {
  // Берем пользователя который отмечен в DataGrid
  var user:User=User(usersDataGrid.selectedItem);
  // Вызываем метод удаленного объекта для удаления пользователя
  // по его идентификатору
  remoteUsers.deleteById(user.id);
  // Обновляем данные DataGrid
  remoteUsers.getAll();
  // Отображение окна с сообщением об успешном удалении
  Alert.show("Пользователь удален", "Zend Amf Example");
  }
  ]]>
 </mx:Script>

В заключение, автор приводит полный код файла zendamf.mxml:

 <?xml version="1.0" encoding="utf-8"?>
<mx:Application pageTitle="Zend AMF sample"
  layout="absolute"
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:controls="classes.controls.*"
  color="#000000"
  backgroundGradientAlphas="[1.0, 1.0]"
  backgroundGradientColors="[#878484, #A79797]"
  borderColor="#8D9295"
  creationComplete="remoteUsers.getAll()">

 <mx:RemoteObject id="remoteUsers"
  destination="zend"
  source="Users"
  showBusyCursor="true">
  <mx:method name="getAll"
  result="onGetAllResult(event)"/>
 </mx:RemoteObject>

 <!--

  Adobe Flex & Zend_Amf Demo
  Alexander Steshenko | Mar 2009
  http://lcf.name/

 -->

 <mx:Script>
  <![CDATA[
  import mx.controls.Button;
  import classes.controls.DoubleClickDataGrid;
  import mx.events.DataGridEvent;
  import classes.models.User;
  import mx.controls.DataGrid;
  import mx.controls.dataGridClasses.DataGridColumn;
  import mx.controls.Alert;
  import mx.rpc.events.FaultEvent;
  import mx.rpc.events.ResultEvent;
  import mx.collections.ArrayCollection;

  /**
  * Обработчик события DataGridEvent.ITEM_EDIT_END
  */
  private function onSaveClick(event:DataGridEvent):void
  {
  // Получаем объект DataGrid
  var dataGrid:DataGrid=DataGrid(event.target);
  // Получаем значение ячейчки
  var newPropertyValue:String=dataGrid.itemEditorInstance["text"];
  // Получаем редактируемое свойство (name, email или login)
  var dataField:String=event.dataField;
  // Создаем объект User на основе данных _до_редактирования_
  var user:User=User(event.itemRenderer.data)
  // Сравниваем старое значение свойства с новым
  if (newPropertyValue == user[dataField])
  {
 // Если данные не поменялись, выходим из функции
 return;
  }
  // Устанавливаем значение нового свойства
  user[dataField]=newPropertyValue;
  // Сохранение пользователя, используя метод удаленного объекта
  remoteUsers.save(user);
  // Отображение окна с сообщением об успешном сохранении
  Alert.show("Пользователь изменен", "Zend Amf Example");
  }

  /**
  * Обработчик события ResultEvent.RESULT
  */
  private function onGetAllResult(event:ResultEvent):void
  {
  // Устанавливаем данные возвращенные сервером в DataGrid
  usersDataGrid.dataProvider=event.result as Array;
  }

  /**
  * Обработчик события нажатия на кнопку добавления пользователя.
  */
  private function onAddClick(event:Event):void
  {
  // Создаем объект User
  var user:User=new User();
  // Определяем его свойства
  user.name=nameTextInput.text;
  user.login=loginTextInput.text;
  user.email=emailTextInput.text;
  // Добавляем используя удаленный вызов метода
  remoteUsers.add(user);
  // Сбрасываем значения
  nameTextInput.text="";
  loginTextInput.text="";
  emailTextInput.text="";
  // Обновляем значения DataGrid
  remoteUsers.getAll();
  // Отображение окна с сообщением об успешном добавлении
  Alert.show("Пользователь добавлен", "Zend Amf Example");
  }

  /**
  * Обработчик события нажатия на кнопку удаления пользователя
  */
  public function onDeleteClick(event:Event):void
  {
  // Берем пользователя который отмечен в DataGrid
  var user:User=User(usersDataGrid.selectedItem);
  // Вызываем метод удаленного объекта для удаления пользователя
  // по его идентификатору
  remoteUsers.deleteById(user.id);
  // Обновляем данные DataGrid
  remoteUsers.getAll();
  // Отображение окна с сообщением об успешном удалении
  Alert.show("Пользователь удален", "Zend Amf Example");
  }
  ]]>
 </mx:Script>

 <mx:Panel width="484"
  height="400"
  layout="vertical"
  title="Управление пользователями"
  paddingBottom="5"
  paddingLeft="5"
  paddingRight="5"
  paddingTop="5"
  horizontalAlign="center"
  horizontalCenter="-5"
  verticalCenter="17"
  borderColor="#2A2929"
  color="#F5F5F5">

  <controls:DoubleClickDataGrid id="usersDataGrid"
  width="446"
  height="100%"
  editable="true"
  itemEditEnd="onSaveClick(event)"
  color="#171717"
  alternatingItemColors="[#DAD9D9, #FFFFFF]">
  <controls:columns>
  <mx:DataGridColumn headerText="Имя"
  dataField="name"/>
  <mx:DataGridColumn headerText="Логин"
  dataField="login"/>
  <mx:DataGridColumn headerText="Email"
  dataField="email"/>
  </controls:columns>
  </controls:DoubleClickDataGrid>

  <mx:HBox width="453">
  <mx:Form color="#0B0B0B">

  <mx:FormItem label="Имя"
  horizontalAlign="left">
 <mx:TextInput id="nameTextInput"/>
  </mx:FormItem>
  <mx:FormItem label="Логин">
 <mx:TextInput id="loginTextInput"/>
  </mx:FormItem>
  <mx:FormItem label="Email">
  <mx:TextInput id="emailTextInput"/>
  </mx:FormItem>

  <mx:Button label="Добавить пользователя"
  click="onAddClick(event)"
  color="#141414"/>
  </mx:Form>
  <mx:Button label="Удалить пользователя"
  click="onDeleteClick(event)"
  color="#141414"
  textAlign="right"
  width="172"/>

  </mx:HBox>
 </mx:Panel>
</mx:Application>

Также следует отметить, что в статье не приводится код дополнительного компонента DoubleClickDataGrid. Если читатель решит его использовать, то ему следует скачать исходный код примера, ссылка на который приведена ниже.

Итоги

В статье мы рассмотрели пример использования компонента Zend_Amf в связке с приложением, разработанным с использованием Adobe Flex SDK.

Полный код приложения, включая php файла, файлы клиентского приложения, дамп для создания базы данных можно скачать здесь: zend_amf_example_sources.zip.

Результат работы разработанного приложения можно увидеть по ссылке http://articles.lcf.name/zend_amf_flex_example/ (база данных периодически очищается).

Тема на форуме

метки: Flex, Zend_Amf, RIA
Лучший способ следить за обновлениями сайта это подписаться на RSS
Если информация была полезной для вас, вы можете поддержать сайт.
Комментарии:
w1zard 28.03.2009 20:50 #
Очень интересно. Спасибо за статью, это дало мне повод задуматься насчет изучения Flex...
Ответить
owl 29.03.2009 16:20 #
Большое спасибо за перевод ! Статья довольно таки интересная и для меня сейчас очень даже актуальна !
Ответить
lcf 29.03.2009 16:34 #
Прощу прощения, но это не перевод.
Спасибо.
Ответить
тимур 30.03.2009 07:18 #
То что я лично давно ждал... Два года с Делфи приучили к визуальному проектированию страницы, интерфейсов...к событийному механизму. Так что поюзаем.

Я кстати писал свой фреймворк, который работает аналогично: с помощью пользовательских тегов проектирую интерфейс, определяю обработчики событий, потом парсер компилирует теги в низкоуровневый PHP-код+javascript...В качестве обработки клиентского интерфейса использовал jquery.

Ответить
lcf 30.03.2009 10:10 #
Да, для джей эс тоже есть такие фреймворки, насколько я знаю. Типа http://www.backbase.com/

А вот интересная (хоть и старая, так что вряд ли претендующая на актуальность) статья: http://www.xakep.ru/magazine/xs/073/064/1.asp

Цитата от туда (человек после ковыряния backbase знакомится с flex):
Крайнее удивление перемежается с приступами дежа вю. Тот же XML, те же объявления пространств имен, что и в Backbase, тот же набор стандартных компонентов с одной лишь разницей: в BB были префиксы <s: … > и <b: … >, a здесь - <mx: … >.

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

Ответить
тимур 31.03.2009 06:55 #
Мда... backbase явно не рулит:).

А, представляете, как я был удивлен, когда сравнил свой недописанный фреймворк с Flex? :) Полная аналогия по разметке проекта тегами... Это шутка конечно.

Вообще, нужно оценивать Flex все же в спарке с Zend-ом, ради этого, собственно, статья и писалась...наверное. И наличие такого компонента как Zend_Amf, на мой взгляд, дает хорошую возможность попробовать Zend/Flex в реальных проектах уже сейчас.

Правда не везде и не всегда.
Ответить
Ilya Remizov 17.04.2009 16:29 #
Используйте Zend_Amf с осторожностью.

Проблемы:

- очепятки и ошибки в коде: Zend/Amf/Request.php:92, исправлено только в 1.8.х, Zend/Amf/Value/Messaging/AcknowledgeMessage.php:56 - обращение к несуществующему свойству объекта. Это насущное, а остальное в багтрекере зенда.

- Оооооочень тормозной. В нагруженных проектах без патчей использовать нельзя. Зачем-то используется Zend_Server_Reflection вместо стандартного Reflection API. Дебильный алгоритм сборки amf-ответа - очень глубокая рекурсия, множество switch внутри циклов.

- Проблемы с передачей агрументов в методы сервисов. Вместо нескольких аргументов всегда передается один массив.
Ответить
Павел 20.08.2009 02:35 #
Илья, не могли бы подробнее написать о "тормозах" Zend_Amf?

Сейчас начинаю в перспективе высоконагруженный проект, спасают ли патчи от тормозов, и какие?

И какую альтернативу можно найти для нагруженных проектов?

Спасибо.
Ответить
Павел 22.08.2009 05:50 #
Большое спасибо автору!
Статья помогла/направила в нужное русло.
Ответить
Igor 01.02.2010 12:52 #
Ссылка с примерами - битая :(
Если можно, выложите пример на файлообменнике.
Ответить
lcf 01.02.2010 13:11 #
Это результат моей эпопеи по переносу домена к другому регистратору. Очередной "транзакционный период" подходит к концу, я надеюсь все заработает в ближащие пару дней.
Ответить
Уважаемые пользователи. Комментарии не для того чтобы:
  1. Спрашивать почему у вас не работает код, для этого есть тема форума закрепленная за статьей.
  2. Спрашивать как реализовать ту или иную функциональность, для этого необходимо создать свою тему на форуме.

Комментарии для того чтобы: высказать свое аргументированное мнение о статье, указать какие участки вызывают непонимание, что нужно исправить/улучшить, просто сказать спасибо.

Комментарии имеют древовидную структуру.
Если вы хотите ответить на определенный комментарий - нажмите на ссылку "Ответить" возле этого комментария.

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