Adobe User Group

CFFORM – Flash Remoting 2

Data de publicação: 20-11-2006

Visitas: 718

Pedro Claudio

Colunistas desde: 2007

Matérias publicadas: 41

Introdução

Quando iniciamos os estudos sobre uma linguagem, ferramenta ou servidor devemos nos aprofundar, para que possamos maximizar a utilização, minimizando a quantidade de código, para criar uma aplicação otimizada. Então demonstrarei aqui como melhorar o código da aplicação de exemplo, passada no final no artigo anterior, de forma que a inclusão de ActionScript no código CFML, seja miníma, e para isto o desenvolvedor deve ter um conhecimento mínimo sobre construção de classes ActionScript 2.0 , e também informado onde essas classes devem ser armazenadas.

Pré-requisito

- ColdFusion MX 7.0.2, com um repositório de classes configurado.
- Para que você possa acompanhar os exemplos a seguir, verifique se o mapeamento / do Administrador ColdFusion, será na pasta que ali está registrado onde será armazenado o componente (Usuario.cfc) deste artigo.

Conceitos

Não vou conceituar, apenas falarei das peculiaridades, ok? ok! E segurem o folego!
A construção e utilização de classes AcitionScript 2.0 no servidor ColdFusion MX 7, obedece algumas regras e necessita de algum conhecimento específico, a primeira regra que devemos respeitar é a restrição de código imposta pelo servidor , ter um repositório de classes definido em flex-config.xml, implementar classes a partir da classe Object e/ou classes que possam receber chamadas diretas a seus métodos, uma particularidade nas declarações, todas devem ser estáticas (static), exceto o construtor, e para uma depuração detalhada, configure seu servidor para exibir as mensagens warning e/ou erro geradas no momento da execução – geralmente uso o comando tail (linux) para verificar as últimas entradas nos logs.
Com relação a execução e testes de classes em Flash Forms CFFORM, você pode ouvir, ou até chegar a pensar ?Ah! Eu atualizei a classe, copiei para o repositório configurado, mas quando executo na pagina, ele não demonstra o incremento que fiz!?, isto ocorre porque o servidor ColdFusion possui uma cache própria para Flash Forms, e para que o servidor saiba que deve atualizar a cache, você precisa requisitar sua aplicação por uma url que contenha a variável ?recompile? com valor verdadeiro (?recompile=true).
Basicamente é isso, mas no transcorrer do seu desenvolvimento poderá perceber outras particularidades dependendo do tipo de servidor que estiver usando.
E quanto a compartilhar um diretório para vários sites, bom, não aconselho.

Conteúdo

Para o conteúdo vamos utilizar o componente do artigo anterior, que já deve estar configurado e respondendo pela url http://localhost/labs/remoting/Usuario.cfc, como também estar com o banco de dados implementado, se você não fez ou não tem isso leia o artigo anterior , e implemente como orientado.

Basicamente o que faremos é implementar o ActionScript (faça um outro diagrama) em cima do diagrama de classe desenvolvido para componente, o sugere que devemos ter na classe ActionScript ao menos seis métodos, relembrando, eles são: validate, append, update, remove, get e search.
Aos que ficaram perdidos na frase acima, sugiro passar o olho em algum artigo, livro ou texto sobre UML e OO.
Nossa classe ActionScript receberá dois métodos novos, a partir da estrutura do cfc, o primeiro será o comunicador, responsável em criar a conexão e cuidar do transporte das informações entre cliente e servidor, e o segundo apenas fará uma faxina nas informações do cliente (communication,clear), dispondo então da seguinte estrutura.

hUsuario.as

import mx.remoting.NetServices;
import mx.remoting.NetServiceProxy;
import mx.remoting.Connection;
import mx.controls.Alert;
import mx.managers.CursorManager;

class hUsuario extends Object{

private static var currentService:NetServiceProxy;

public static var userid:String;
public static var username:String;
public static var nome:String;
public static var email:String;

private function hUsuario();
private static function communication(onresult:Function):Void;
private static function validate():Object;

public static function append():Void;
public static function update(user:String):Void;
public static function remove(user:String):Void;
public static function get():Void;
public static function search(query:String):Void;
public static function clear():Void;

}

Os atributos userid, username, nome e email, são uma abstração das colunas da tabela lá do banco de dados, e o elemento mais importante nesta classe é o atributo currentService, por default sempre apontará para o mesmo conjunto de serviços, porém receberá ações diferentes, para que sejam executadas no retorno dos serviços, em cada serviço que estiver sendo executado, aqui resolvi coloca-lo como privado.

Os atributos.

private static var currentService:NetServiceProxy;
public static var userid:String;
public static var username:String;
public static var nome:String;
public static var email:String;


Neste exemplo o construtor não executa nenhum comando, mesmo porque ele está declarado como privado, e não será executado da forma que utilizaremos, como pode ter reparado, nossa classe é filha da classe Object, e é assim que será tratada, ou seja, como um objeto previamente criado “diferente do padrão”? Pode ser mas a classe mx.remoting.NetServices, também utiliza este artifício.
O construtor, apenas pro forme.

private function hUsuario(){
}

O próximo método é o mais importante e o motivo da criação desta classe, pois é nele que será construída a comunicador, que fará a ponte com o servidor.

/*
Tem como parâmetro a ações que deve ser executada em um retorno ok do servidor.
*/
private static function communication(onresult:Function):Void {

/* aqui uma firula ao cliente */
CursorManager.setBusyCursor();

/* endereço do gateway */
var defaultGateway:String = “http://localhost/cfusion/flashservices/gateway/”;

/* endereço do conjunto de serviços */
var defaultPath:String = “labs.remoting.Usuario”;

/* conexão com servidor */
var conn:Connection = NetServices.createGatewayConnection(defaultGateway);

/* prepara parâmetro obrigatório da conexão com serviço*/
var eventReturn:Object = new Object();

/* ação será executada em um retorno ok do servidor, com um leve complexidade, pois é uma execução padrão, e em seu conteúdo o parâmetro do método communication será executado */
eventReturn.onResult = function(o):Void{

/* executa ação de fato */
onresult(o);
/* encerra conexão */
conn.close();
/* destrói a firula */
CursorManager.removeBusyCursor();
}
/* onStatus :o */
eventReturn.onStatus = function(info:Object):Void{
Alert.show(info.description,info.level);
conn.close();
CursorManager.removeBusyCursor();
};
/* constrói conexão com o conjunto de serviços, variável poderá ser acessada pelos demais métodos */
currentService = conn.getService(defaultPath,eventReturn);

}

Para um entendimento da lógica da código comentarei agora a operação mais simples desta classe.

/* método invoca todos os registros da base de dados*/
public static function get():Void{/* ação que será executada de fato em um retorno ok do servidor*/
var onResult:Function = function(result):Void{
var query:Array = result._items;
var recordount:Number = query.length;
Alert.show(’Resposta (’+recordount+’) do servidor’,'result’);
};

/* executa método passando a função como parâmetro, função esta que será inserida e invocada dentro de outra função, repare no método anterior (communication)*/
communication(onResult);
/* invoca serviço */
currentService.get();

}

Os métodos seguintes são simplesmente os códigos do artigo anterior, contudo dispostos de forma mais organizada e vistosa, não vou comentar, apenas exibirei a classe completa e passarei ao formulário CFML.

hUsuario.as

import mx.remoting.NetServices;
import mx.remoting.NetServiceProxy;
import mx.remoting.Connection;
import mx.controls.Alert;
import mx.managers.CursorManager;

class hUsuario extends Object{

private static var currentService:NetServiceProxy;

public static var userid:String;
public static var username:String;
public static var nome:String;
public static var email:String;

private function hUsuario(){
}

private static function communication(onresult:Function):Void {

CursorManager.setBusyCursor();

var defaultGateway:String = “http://localhost/cfusion/flashservices/gateway/”;
var defaultPath:String = “labs.remoting.Usuario”;

var conn:Connection = NetServices.createGatewayConnection(defaultGateway);

var eventReturn:Object = new Object();
eventReturn.onResult = function(o):Void{
onresult(o);
conn.close();
CursorManager.removeBusyCursor();
}
eventReturn.onStatus = function(info:Object):Void{
Alert.show(info.description,info.level);
conn.close();
CursorManager.removeBusyCursor();
};
currentService = conn.getService(defaultPath,eventReturn);

}

private static function validate():Object{

var r:Object = new Object();
var error:Boolean = true;

if(username != undefined && username.length > 0){
r.username = username;
error = false;
}

if(nome != undefined && nome.length > 0){
r.nome = nome;
error = false;
}

if(email != undefined && email.length > 0){
r.email = email;
error = false;
}
if(error){
return null;
}
return r;

}

public static function append():Void{

var user = validate();

if(user != null){

var onResult:Function = function(result):Void{
switch(result){
case -1:
Alert.show(”Erros entre os dados do registro”,”Erro”);
break;
case 0:
Alert.show(”Duplicata de identificador recusada”,”Erro”);
break;
default:
Alert.show(”Resposta ok (”+result+”)”,”result”);
clear();
break;
}
};

var arg:Object = new Object();
arg.dados = user;
communication(onResult);
currentService.append(arg);

}else{
Alert.show(”Infomação insuficiente!”,”Erro”);
}

clear();

}

public static function update(user:String):Void{

var u = validate();

if(u != null){

var onResult:Function = function(result):Void{
switch(result){
case -1:
Alert.show(”Erros entre os dados do registro”,”Erro”);
break;
case 0:
Alert.show(”Duplicata de identificador recusada”,”Erro”);
break;
default:
Alert.show(”Resposta ok”,”result”);
clear();
break;
}
};

var arg:Object = new Object();
arg.id = user;
arg.dados = u;
communication(onResult);
currentService.update(arg);

}else{
Alert.show(”Infomação insuficiente!”,”Erro”);
}

clear();

}

public static function remove(user:String):Void{

var onResult:Function = function(result):Void{
if(result){
Alert.show(’Resposta do servidor’,'result’);
}else{
Alert.show(’Idenficador recusado’,'Erro’);
}
};
var arg:Object = new Object();
arg.id = user;
communication(onResult);
currentService.remove(arg);

}

public static function get():Void{

var onResult:Function = function(result):Void{
var query:Array = result._items;
var recordount:Number = query.length;
Alert.show(’Resposta (’+recordount+’) do servidor’,'result’);
};
communication(onResult);
currentService.get();

}

public static function search(query:String):Void{

var onResult:Function = function(result):Void{
var query:Array = result._items;
var recordount:Number = query.length;
if(recordount > 0){
Alert.show(’Resposta (’+recordount+’) do servidor’,'result’);
}else{
Alert.show(”Nenhum registro foi encontrado.”,’Erro’);
}
};
var arg:Object = new Object();
arg.str = query;
communication(onResult);
currentService.search(arg);

}

public static function clear():Void{

username = nome = email = “”;

}

}

Vou executar um método por arquivo, iniciando pelo get, muito complicado como pode ver.

1.cfm

<cfform name=”basic” format=”flash” onload=”hUsuario.get();”>
</cfform>

O método a seguir realizará a inclusão de um novo registro, caso a inclusão termine com sucesso retornará o ID do novo individuo, vou comentar, porque ele é muito mais complicado que o anterior.

2.cfm

<cfform name=”basic” format=”flash” onload=”initRemoting();”>
<cfformitem type=”script”>
function initRemoting(){
//informo nome
hUsuario.nome = “orlando”;
//informo e-mail
hUsuario.email = “velho@mail.com”;
//informo username
hUsuario.username = “velho”;
//adiciono as informações no banco
hUsuario.append();
}
</cfformitem>
</cfform>

Vou aproveitar o ID que foi retornado no append, para nas demais execuções.
A atualização é bem semelhante ao cadastro, a diferença está justamente no identificador do usuário, que deve ser passado como parâmetro, o restante é idêntico..

3.cfm

<cfform name=”basic” format=”flash” onload=”initRemoting();”>
<cfformitem type=”script”>
function initRemoting(){
hUsuario.nome = “Orlando”;
hUsuario.email = “gandalf@mail.com”;
hUsuario.username = “gandalf”;
hUsuario.update(”20″);
}
</cfformitem>
</cfform>

As próximas execuções apresentam a mesma complexidade que a primeira, ou seja nenhuma.
Removeremos agora o gandalf da base de dados.

4.cfm

<cfform name=”basic” format=”flash” onload=”hUsuario.remove(’20′);”>
</cfform>

E para finalizar a sequencia, vamos pesquisar um caracter comum a todos os registro.

5.cfm

<cfform name=”basic” format=”flash” onload=”hUsuario.search(’@');”>
</cfform>

Para que entendam, mais claramente, de que ser este tipo de implementação, façam uma comparação do código da aplicação do artigo anterior para o código da aplicação a seguir.

index.cfm

<cfform name="form1" format="flash" onload="initApp()"> 

		<cfformitem type="script">			function initApp(){				Usuario.formName = 'form1';			}		</cfformitem> 

		<cfformgroup type="panel" width="420">			<cfformgroup  type="horizontal" >				<cfinput type="text"   name="qry"    id="qry"                                                                 />				<cfinput type="button" name="search" id="search" value="Pesquisar" onclick="Usuario.search(_root.qry.text);"  />			</cfformgroup>		</cfformgroup> 

		<cfformgroup type="panel" width="420" visible="false" id="pGrid">			<cfgrid name="listUsuarios" width="400" rowheaders="false" onchange="_root.pUser.visible = true;">				<cfgridcolumn name="nome"     />				<cfgridcolumn name="username" />				<cfgridcolumn name="email"    />			</cfgrid> 			<cfformgroup type="horizontal">				<cfinput name="RefreshUsuarios" id="RefreshUsuarios" type="button" value="Refresh" onclick="Usuario.get();"                                          />				<cfinput name="addUsuarios"     id="addUsuarios"     type="button" value="Novo"    onclick="Usuario.clear(); _root.pUser.visible = true;"            />				<cfinput name="RemoveUsuarios"  id="RemoveUsuarios"  type="button" value="Remove"  onclick="Usuario.remove(_root.listUsuarios.selectedItem.userid);" />			</cfformgroup>		</cfformgroup> 

		<cfformgroup type="panel" width="420" id="pUser" visible="false">			<cfinput type="text"    id="id"           name="id"           label="ID"       validate="integer"  enabled="false"  bind="{listUsuarios.selectedItem.userid}"                                           />			<cfinput type="text"    id="username"     name="username"     label="username" validate="noblanks" required="true"  bind="{listUsuarios.selectedItem.username}"                                         />			<cfinput type="text"    id="nome"         name="nome"         label="nome"     validate="noblanks" required="false" bind="{(listUsuarios.selectedItem.nome != null)?listUsuarios.selectedItem.nome:''}" />			<cfinput type="text"    id="email"        name="email"        label="email"    validate="email"    required="true"  bind="{listUsuarios.selectedItem.email}"                                            />			<cfinput  type="button" id="saveUsuarios" name="saveUsuarios" value="Salvar"					onclick="							Usuario.nome = _root.nome.text ;							Usuario.email = _root.email.text;							Usuario.username = _root.username.text;							if(_root.id.text == ''){								Usuario.append();							}else{								Usuario.update(_root.id.text);							}" >		</cfformgroup> 

</cfform>

Obs.: São três imagens, mas não houve reload, basta testar o cfml e verá.

Conclusão

“Uma boa prática deixa seu código muito mais apresentável, otimizado, com uma produtividade alta e um tempo de implementação reduzido.”


Pedro Claudio – pcsilva@mxstudio.com.br
visite o fórum MXStudio ColdFusion
Blog

FormatCF(new Array(\’1.cfm\’,\’2.cfm\’,\’3.cfm\’,\’4.cfm\’,\’5.cfm\’,\’index.cfm\’)); FormatAS(new Array(\’hUsuario.as\’,\’oget\’,\’communication\’,\’Construtor\’,\’atributos\’));

Divulgue

Adicionar artigo ao Rec6 Adicionar artigo ao Linkk Adicionar artigo ao doMelhor Adicionar artigo ao Eu Curti Adicionar artigo ao del.icio.us

Nenhum usuário comentou em " CFFORM – Flash Remoting 2 "

Assine o Feed de Comtentários ou URL de Trackback

Deixe o seu comentário abaixo...

 Username (*required)

 Email Address (*private)

 Website (*optional)

 

MXStudio © 2003-2009. Todos os direitos reservados.
É expressamente proibido a cópia, reprodução e difusão dos textos, fotos e outros elementos contidos neste site sem autorização expressa do MXStudio.