HUFERSIL.WEBDEVELOPER

Exemplo Lumine / Zend_Amf

Esse final de semana foi de grandes melhorias no Lumine, principamente para desenvolvimento com Ajax e AMF!

Agora é possível enviar os elementos serializados em JSON utilizando os métodos toJSON e allToJSON! Assim, você não precisa mais fazer uma iteração para recuperar os elementos no formato necessário para envio via Ajax!

Para quem gosta de utilizar Flex com AMF, outra atualização muito interessante.
No momento em que você realizar a engenharia reversa, você tem a opção de gerar as classes DTO (ou VO) para sua entidades de negócio. Além disso, foram criados dois métodos: toObject e allToObject.

A grande vantagem destes dois métodos, quando utilizando DTO’s, é que você pode setar na configuração de Lumine para que ele faça o cast automaticamente para o tipo de dados (classe) correspondente. E também nesta engenharia o DTO gerado já vem com o atributo $_explicitType. Assim, ficou ainda mais fácil integrar com RemoteObject.

Hoje, vou mostrar um exemplo bem básico de como trabalhar com Lumine, Zend_Amf e Flex.

Parte 1 – Estrutura de arquivos

Para este exemplo, utilizaremos a estrutura de arquivos abaixo (veja que já tem até os arquivos com os nomes finais):

Estrutura de pastas

Parte 2 – Banco de dados

Abaixo está o script de criação do banco de dados que vou usar no exemplo:

-- MySQL dump 10.13  Distrib 5.1.34, for Win32 (ia32)
--
-- Host: localhost    Database: lumine
-- ------------------------------------------------------
-- Server version	5.1.34-community

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `pessoa`
--

DROP TABLE IF EXISTS `pessoa`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `pessoa` (
  `idpessoa` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `nome` varchar(100) NOT NULL,
  `email` varchar(100) NOT NULL,
  `data_cadastro` datetime NOT NULL,
  PRIMARY KEY (`idpessoa`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `pessoa`
--

LOCK TABLES `pessoa` WRITE;
/*!40000 ALTER TABLE `pessoa` DISABLE KEYS */;
INSERT INTO `pessoa` VALUES (1,'Hugo Ferreira da Silva','hufersil@gmail.com','2009-07-13 16:11:56'),(2,'Mirian Brisch da Silva','mirian@gmail.com','2009-07-13 13:19:07'),(3,'João Francisco','joao@gmail.com','2009-07-13 13:19:31'),(4,'Juliano','juliano.polito@247id.com.br','2009-07-13 13:06:19'),(5,'Macarena','macarena@gmail.com','2009-07-13 13:18:04');
/*!40000 ALTER TABLE `pessoa` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `telefone`
--

DROP TABLE IF EXISTS `telefone`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `telefone` (
  `idtelefone` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `numero` varchar(20) NOT NULL,
  `idpessoa` int(10) unsigned NOT NULL,
  PRIMARY KEY (`idtelefone`),
  KEY `FK_telefone_1` (`idpessoa`),
  CONSTRAINT `FK_telefone_1` FOREIGN KEY (`idpessoa`) REFERENCES `pessoa` (`idpessoa`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `telefone`
--

LOCK TABLES `telefone` WRITE;
/*!40000 ALTER TABLE `telefone` DISABLE KEYS */;
INSERT INTO `telefone` VALUES (1,'3004-7777',1),(2,'7777-0000',1),(3,'7400-0000',2),(4,'3000-3333',1);
/*!40000 ALTER TABLE `telefone` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2009-07-13 19:57:38


Parte 3 – Criação do arquivo de configuração

Agora, precisamos criar o arquivo de configuração do Lumine.
Se você já trabalhou com Lumine anteriormente, você verá que é basicamente a mesma coisa.
Neste exemplo, só adicionamos a linha para carregar automaticamente as classes de persistência e também as classes DTO (este último só funciona com versão mais atual de Lumine, 1.3.7). Salve o arquivo em php/config.php.

// carrega Lumine
require_once 'lumine/Lumine.php';
// carrega as configuracoes de Lumine
require_once dirname(dirname(__FILE__)).'/lumine-conf.php';
// instancia uma configuracao
$cfg = new Lumine_Configuration($lumineConfig);
// indica o timezone padrao
date_default_timezone_set('America/Sao_paulo');
// auto-carregamento de classes de Lumine
spl_autoload_register(array('Lumine','Import'));
// auto-carregamento de classes DTO de Lumine
spl_autoload_register(array('Lumine','ImportDTO'));
// registra uma funcao para o fechamento da conexao ao termino do script
register_shutdown_function(array($cfg->getConnection(),'close'));

Parte 4 – Criação da classe de Serviços

A classe de serviços é, na verdade, uma classe comum, onde você escreverá os métodos públicos que serão acessados pelo Zend_Amf, através das requisições feitas pelo Flex.
Neste exemplo, vou fazer somente a parte de poder criar/editar pessoas e editar telefones.
Abaixo está a classe que vou utilizar neste exemplo (salve este arquivo na pasta server/services/ExampleService.php:

/**
 * Classe de servico para AMF
 *
 * @author Hugo Ferreira da Silva
 * @link http://www.hufersil.com.br/lumine
 *
 */
class ExampleService {

	/**
	 * Retorna todas as pessoas cadastradas
	 * @return array
	 */
	public function getPessoas(){
		// cria o objeto de pessoa de persistencia
		$list = new Pessoa();
		// pega todos os cadastros
		$list->find();
		// retorna todos os itens como objetos (tipados!)
		return $list->allToObject();
	}

	/**
	 * grava os dados da pessoa
	 *
	 * @param PessoaDTO $pessoa
	 * @return int
	 */
	public function gravarPessoa(PessoaDTO $pessoa){
		// cria o objeto de pessoa de persistencia
		$pess = new Pessoa();

		// pega os dados vindos do Flex
		$pess->idpessoa = empty($pessoa->idpessoa) ? null : $pessoa->idpessoa;
		$pess->nome = $pessoa->nome;
		$pess->email = $pessoa->email;
		$pess->dataCadastro = time();

		// grava os dados
		$pess->save();

		// retorna o id da pessoa
		return $pess->idpessoa;
	}

	/**
	 * Retorna os telefones de uma determinada pessoa
	 * @return array
	 */
	public function getTelefones($idpessoa){
		// recupera todos os telefones da pessoa
		return Telefone::staticGet('idpessoa',$idpessoa)->allToObject();
	}

	/**
	 * grava os dados do telefone
	 *
	 * @param TelefoneDTO $telefone
	 * @return int
	 */
	public function gravarTelefone(TelefoneDTO $telefone){
		// cria o objeto de persistencia de telefone
		$tel = new Telefone();
		// se nao achar nenhum telefone com o id indicado
		if( $tel->get($telefone->idtelefone) == 0){
			// coloca como nulo (auto-increment)
			$tel->idtelefone = null;
		}
		// pega o restante dos dados
		$tel->idpessoa = $telefone->idpessoa;
		$tel->numero = $telefone->numero;
		// grava o telefone
		$tel->save();
	}

}

Parte 5 – Criação do servidor AMF com Zend_Amf

A criação de um servidor AMF (na verdade, um endpoint para comunicação AMF) é realmente muito simples utilizando o Zend Framework.
Abaixo um exemplo de criação do servidor (grave em server/server.php)

// carrega os arquivos necessarios
require_once 'Zend/Amf/Server.php';
require_once 'services/ExampleService.php';
require_once '../php/config.php';

// inicia o servidor de AMF
$server = new Zend_Amf_Server();
// indica qual classe vai ser usada
// vc pode chamar mais vezes com as classes desejadas
$server->setClass('ExampleService');
// processa a resposta
$response = $server->handle();
// envia a resposta
echo $response;

Parte 6 – criação do services.xml

Neste arquivo, definimos todas as configurações básicas de serviços que o Flex precisa para se comunicar com o servidor.
Para mais informações a respeito deste arquivo, acesse a

documentação oficial da Adobe

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

 

Parte 7 – Criação do MXML
 

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	layout="absolute"
	creationComplete="init()"
	>

	<mx:Script>
		<![CDATA[
			/**************************************************************/
			/************************* IMPORTS ****************************/
			/**************************************************************/
			import mx.events.FlexEvent;
			import mx.events.ListEvent;
			import mx.events.DataGridEvent;
			import mx.controls.Alert;
			import com.hufersil.dto.PessoaDTO;
			import com.hufersil.dto.TelefoneDTO;
			import flash.sampler.NewObjectSample;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			import mx.collections.ArrayCollection;

			[Bindable]
			/**
			 * objeto de pessoa
			 * */
			private var pessoa:PessoaDTO = new PessoaDTO;

			[Bindable]
			/**
			 * lista de pessoas
			 * */
			private var arrcPessoas:ArrayCollection;

			[Bindable]
			/**
			 * lista de telefones
			 * */
			private var arrcTelefones:ArrayCollection;

			/**************************************************************/
			/************************* METODOS ****************************/
			/**************************************************************/
			/**
			 * metodo chamado na inicializacao
			 *
			 * */
			private function init():void {
				// recupera a lista de pessoas
				remote.getPessoas();
				// adiciona o ouvinte para quando clicar em um item da lista de pessoas
				gridPessoas.addEventListener(ListEvent.ITEM_CLICK, gridPessoas_itemClickHandler);
				// adiciona um ouvinte para quando terminar de editar um item de telefone
				gridTelefones.addEventListener(DataGridEvent.ITEM_FOCUS_OUT, gridTelefones_dataChangeHandler);
				// ouvinte para quando clicar no botao de gravar pessoa
				btnGravarPessoa.addEventListener(MouseEvent.CLICK, btnGravarPessoa_clickHandler);
			}

			/******************************************************/
			/****************** EVENT HANDLERS ********************/
			/******************************************************/
			/***************************/
			/******** interface ********/
			/***************************/
			// Quando clicar no botao de gravar
			private function btnGravarPessoa_clickHandler(e:MouseEvent):void {
				// pega o nome da pessoa do form
				pessoa.nome = nome.text;
				// pega o email da pessoa do form
				pessoa.email = email.text;
				// grava os dados da pessoa
				remote.gravarPessoa(pessoa);
			}

			// quando clicar em um item da grid de pessoas
			private function gridPessoas_itemClickHandler(e:ListEvent):void {
				// recupera o objeto de pessoa escolhido
				pessoa = PessoaDTO(gridPessoas.selectedItem);
				// recupera os telefones
				remote.getTelefones(pessoa.idpessoa);
			}

			// quando terminar de editar um item de telefone
			private function gridTelefones_dataChangeHandler(e:DataGridEvent):void {
				// pega o objeto relacionado
				var tel:TelefoneDTO = TelefoneDTO(e.itemRenderer.data);
				// pega o numero escolhido
				tel.numero = TextInput(e.itemRenderer).text;
				// manda gravar o telefone
				remote.gravarTelefone(tel);
			}

			/***************************/
			/********* remoting ********/
			/***************************/
			// ao recuperar a lista de pessoas
			private function getPessoas_resultHandler(e:ResultEvent):void {
				arrcPessoas = new ArrayCollection(e.result as Array);
			}

			// quando der erro ao recuperar a lista de pessoas
			private function getPessoas_faultHandler(e:FaultEvent):void {
				Alert.show('Erro ao recuperar pessoas: ' + e.fault.message);
			}

			// ao recuperar os telefones
			private function getTelefones_resultHandler(e:ResultEvent):void {
				// popula o array collection de telefones
				arrcTelefones = new ArrayCollection(e.result as Array);
			}

			// se der erro ao recuperar os telefone
			private function getTelefones_faultHandler(e:FaultEvent):void {
				Alert.show('Erro ao recuperar telefones: ' + e.fault.message);
			}

			// quando gravar os dados de uma pessoa certinho
			private function gravarPessoa_resultHandler(e:ResultEvent):void {
				remote.getPessoas();
				pessoa.nome = '';
				pessoa.email = '';
				pessoa.idpessoa = 0;
			}

			// quando der erro ao gravar uma pessoa
			private function gravarPessoa_faultHandler(e:FaultEvent):void {
				Alert.show('Erro ao gravar dados da pessoa: ' + e.fault.message);
			}

			// quando gravar os dados do telefone com sucesso
			private function gravarTelefone_resultHandler(e:ResultEvent):void {
			}

			// se houve erro ao gravar o telefone
			private function gravarTelefone_faultHandler(e:FaultEvent):void {
				Alert.show('Erro ao gravar dados do telefone: ' + e.fault.message);
			}

		]]>
	</mx:Script>

	<mx:TabNavigator x="0" y="0" width="100%" height="100%">
		<!-- ************************************************************** -->
		<!-- ********************* ABA DE PESSOAS ************************* -->
		<!-- ************************************************************** -->
		<mx:Canvas label="Cadastro de Pessoas" width="100%" height="100%">

		 <!-- Vbox para colocar a grid abaixo do formulario -->
		 <mx:VBox
		 	height="100%"
		 	width="100%"
		 	>

			 <!-- exibindo os telefones -->
		 	<mx:HBox
		 		width="100%"
		 		height="100%"
		 		>
				<!-- ************************************************************** -->
				<!-- ******************** FORM DE PESSOAS ************************* -->
				<!-- ************************************************************** -->
				<mx:Form x="0" y="0" width="100%" height="100%">
					<mx:FormItem label="Nome" horizontalAlign="left">
						<mx:TextInput width="223" id="nome" text="{pessoa.nome}" />
					</mx:FormItem>
					<mx:FormItem label="E-mail">
						<mx:TextInput width="224" id="email" text="{pessoa.email} "/>
					</mx:FormItem>
					<mx:FormItem width="124">
						<mx:Button label="Gravar" id="btnGravarPessoa"/>
					</mx:FormItem>
				</mx:Form>

				<!-- ************************************************************** -->
				<!-- ******************** GRID DE TELEFONES *********************** -->
				<!-- ************************************************************** -->
				<mx:DataGrid
					id="gridTelefones"
					dataProvider="{arrcTelefones}"
					height="100%"
					width="100%"
					editable="true"
					>

					<mx:columns>
						<mx:DataGridColumn headerText="ID" dataField="idtelefone" width="30" editable="false" />
						<mx:DataGridColumn headerText="Número" dataField="numero" editable="true" />
					</mx:columns>

				</mx:DataGrid>

			</mx:HBox>

			<!-- ************************************************************** -->
			<!-- ******************** GRID DE PESSOAS ************************* -->
			<!-- ************************************************************** -->
			<mx:DataGrid
				id="gridPessoas"
				height="100%"
				width="100%"
				dataProvider="{arrcPessoas}"
				>

				<mx:columns>
					<mx:DataGridColumn width="30" headerText="ID" dataField="idpessoa"/>
					<mx:DataGridColumn headerText="Nome" dataField="nome" />
					<mx:DataGridColumn headerText="E-mail" dataField="email" />
				</mx:columns>

			</mx:DataGrid>

		  </mx:VBox>
		</mx:Canvas>

	</mx:TabNavigator>

	<!-- ************************************************************** -->
	<!-- ********************** REMOTE OBJECT ************************* -->
	<!-- ************************************************************** -->
	<mx:RemoteObject
		id="remote"
		destination="zend"
		source="ExampleService"
		>
		<!-- recupera as pessoas cadastradas -->
		<mx:method name="getPessoas"
			 result="getPessoas_resultHandler(event)"
			 fault="getPessoas_faultHandler(event)" />

		<!-- recupera os telefones de uma pessoa -->
		<mx:method name="getTelefones"
			 result="getTelefones_resultHandler(event)"
			 fault="getTelefones_faultHandler(event)" />

		<!-- grava os dados da pessoa -->
		<mx:method name="gravarPessoa"
			 result="gravarPessoa_resultHandler(event)"
			 fault="gravarPessoa_faultHandler(event)" />

		<!-- grava os dados do telefone -->
		<mx:method name="gravarTelefone"
			 result="gravarTelefone_resultHandler(event)"
			 fault="gravarTelefone_faultHandler(event)" />

	</mx:RemoteObject>
</mx:Application>

Claro, para facilitar a vida, os arquivos estão disponíveis para download!

@braços e fiquem com Deus!

Deixar uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

*

Pode usar estas etiquetas HTML e atributos: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">