CFFORM – Flash Remoting 2

Publicado por Pedro Claudio em 20/11/2006

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\’));


Assine o nosso Feed
1.281 assinantes,
assine você também!
Publique esse artigo no Twitter Salve este artigo no Delicious Cadastre esse artigo no Dihitt Cadastre esse artigo no UEBA Cadastre esse artigo no Rec6

Pedro Claudio

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-2010. 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.