PHP
Arquitetura com Adobe Flex, PHP e Zend Framework
Olá Pessoal,
Um item básico quando se trata de sites, é um local onde o visitante pode de alguma forma entrar em contato com a empresa do site, hoje existem algumas boas soluções para isso, como por exemplo um client msn que pode ser colocado no site e se o visitante quiser, pode entrar em contato com o msn da empresa.
Mas hoje vou mostrar a vocês uma forma simples e funcional, que consiste em um formulário onde o visitante preenche os dados, e gera um e-mail para o destinatário.
Mostrarei isso usando PHP/ZEND/AMFPHP/FLEX, poderia fazer isso somente com HTTPService? concerteza, ficaria menos código e até mais simples, porém concordamos que ninguém iria fazer uma aplicação só com essa funcionalidade, pois o Formulário de Contato seria apenas um módulo do sistema.
Então vou lhes mostrar também uma proposta de como você pode trabalhar arquiteturalmente com Flex e PHP, trocando apenas VO/TO/DTO entre as camadas, lembrando que isso é uma boa prática, vejo muitos porae trocando array’s com Flex e PHP, isso é totalmente desnecessário.
Detalhes da Arquitetura
A arquitetura usa o ZEND para abstração do banco de dados usando a Classe Zend_Db_Table, e outros recursos como o Zend_Loader e Zend_Registry.
AMFPHP para a comunicação entre o AdobeFlex e o PHP, esta comunicação rodando em cima do protocolo AMF3, que provém comunicação binária não mais String como no HTTP puro, e também compactação.
Estruturando a aplicação
Historic image unavailable from the original source: Estrutura de Pastas. Listagem 1
Crie uma estrutura de pastas como mostrado na Listagem 1
O package entitybean contém classes que segue os conceitos de um EntityBean como nas especificações J2EE/JEE, só que claro BMP através do Zend_Db_Table, e uma outra classe que eu fiz chamada EntityBeanImpl, que abstrai ainda mais os métodos CRUD de um caso de uso, como por Exemplo eliminei os métodos Inserir e Atualizar, e criei um Salvar, que insere ou atualiza baseado na Primary-Key. Em poucas palavras, um EntityBean, é reponsável pela abstração de um Banco de Dados Relacional, as camadas acima de entityBean apenas conhecem o entitybean, não tem acesso ao Banco de dados.
Para Garantir transação e concorrência, criei uma classe chamada DB que cotém um singleton me garantindo apenas uma instância da mesma em uma transação, ela é reponsavel por iniciar uma transação através do método beginTransaction() realizar o commit se toda a operação ocorrer com sucesso atraveés do método commit() e realizar o roolback no banco de dados através do método rollback().
O package sessionbean contém classes que segue os conceitos de um SessionBean também como nas especificações J2EE/JEE só que apenas sendo Stateless. Em poucas palavras um SessionBean tem a responsábilidade de implementar a regra de negócio do caso de uso, como por exemplo validações, calculos e etc.
O package facade contém classes que implementam o Pattern Facade em outras palavras é a fachada do sistema, neta arquitetura ela é responsável por garantir a transação usando a classe DB, também é reponsável pelo tratamento de exceções (Erros).
O package vo contém simples classes que implementam os Patterns VO/TO/DTO, são os vo’s encarregados de transportar entre as camadas as informações de cada caso de uso. Lembrando que o mesmo VO no PHP, será automaticamente serializado pelo AMFPHP para um VO no Flex para isso os VO devem ficar assim:
No PHP: *Coloque a tag do php no inicio e no fim.
class ContatoVO
{
var $idContato;
var $dsNome;
var $dsEmail;
var $nuTelefone;
var $dsCidade;
var $dsEstado;
var $dsMensagem;
//NOME DO VO NO FLEX
var $_explicitType = "ContatoVO";
}
No Flex/AS3
package com.digows.Artigos.FlexPHP.vo
{
//NOME DO VO NO PHP
public class ContatoVO
{
public var idContato:int;
public var dsNome:String;
public var dsEmail:String;
public var nuTelefone:String;
public var dsCidade:String;
public var dsEstado:String;
public var dsMensagem:String;
}
}
O package services contem as classes de serviços de toda aplicação, estes serviços podem ser disponibilizados para o AMFPHP como veremos a seguir, ou também se você conhece bem o Zend Framework, pode gerar serviços através de WebServices ou até mesmo serviços para o Controller do Zend Framework, neste caso usando HTML na View.
O package config apenas contém arquivos de configuração, como por exemplo path do servidor, dados do banco de dados e etc.
E finalmente o package libs que contém as bibliotecas utilizadas na aplicação, no caso o AMFPHP e Zend Framework.
Configurando a aplicação
Nós precisamos fazer uma integração com o Zend Framework, e o AMFPHP, então primeiramente vamos gerar o application-config.php do Zend.
Dentro do package config, crie um arquivo chamado application-config.php com este conteúdo:
*Coloque a tag do php no inicio e no fim.
set_include_path('.'.PATH_SEPARATOR.'../../libs'.PATH_SEPARATOR.get_include_path());
require_once ('Zend/Loader.php');
/**
* Loaders
*/
//Registrador de Variaveis
Zend_Loader::loadClass('Zend_Registry');
//Carregador de configuracoes de um .ini
Zend_Loader::loadClass('Zend_Config_Ini');
//Classe que encapsula o Banco
Zend_Loader::loadClass('Zend_Db');
//Classe para usar as tabelas como objetos.
Zend_Loader::loadClass('Zend_Db_Table');
//Usada para fazer o parser dos xml
Zend_Loader::loadClass('Zend_Config_Xml');
/**
* Configuracoes da Persistencia.
*/
//Carrega o arquivo de configuracoes.
$configDB = new Zend_Config_Ini(dirname(__FILE__).'/config.ini', 'database');
Zend_Registry::set('configDB', $configDB);
$configPaths = new Zend_Config_Ini(dirname(__FILE__).'/config.ini', 'paths');
Zend_Registry::set('configPaths', $configPaths);
/**
* Configuracoees variadas...
*/
//Configura o formato para moeda
setlocale(LC_MONETARY, 'ptb');
//Configura as mensagens de erro que devem ser apresentadas.
error_reporting(E_ALL | E_STRICT);
Perceba que a configuração usa um arquivo chamado config.ini este contém as configurações do Banco de Dados e paths:
db.adapter=PDO_MYSQL
db.config.host=localhost
db.config.username=root
db.config.password=
db.config.dbname=flexphp
path.dirImg=C:/resources/img
No package libs você coloca os arquivos do ZEND e do AMFPHP ficando assim:
Historic image unavailable from the original source: Libs. Listagem 2
A única coisa que precisa ser feita com o AMFPHP, é dizer a ele aonde está os services, que usa para mandar os VO’s para o PHP, e aonde se encontra o package dos VO’s, que ele usa para serializar os VO’s Flex e PHP.
Para isso, abra o arquivo globals.php dentro da pasta do AMFPHP e deixe assim:
*Coloque a tag do php no inicio e no fim.
//This file is intentionally left blank so that you can add your own global settings
//and includes which you may need inside your services. This is generally considered bad
//practice, but it may be the only reasonable choice if you want to integrate with
//frameworks that expect to be included as globals, for example TextPattern or WordPress
//Set start time before loading framework
list($usec, $sec) = explode(" ", microtime());
$amfphp = ((float)$usec + (float)$sec);
$servicesPath = "../../application/services/";
$voPath = "../../application/business/vo/";
//As an example of what you might want to do here, consider:
/*
if(!PRODUCTION_SERVER)
{
define("DB_HOST", "localhost");
define("DB_USER", "root");
define("DB_PASS", "");
define("DB_NAME", "amfphp");
}
*/
Perceba as variaveis $servicesPath e $voPath.
É preciso configurar os sources_paths do projeto no caso o src_flex e src_php, para isso:
No seu projeto de um botão direito -> Properties -> Selecione a opção Flex Build Path -> clique no botão Add Folder e procure a pasta src_php -> Em Main source folder selecione a pasta src_flex.
Esta tela deverá ficar assim:
Historic image unavailable from the original source: Flex Build Path. Listagem 3
E para concluir, precisamos informar ao compilador Flex qual o endereço do gateway onde será possível trocar dados em cima do protocolo AMF3, para isso gere um arquivo com o nome de services-config.xml na raiz da pasta src_flex com este conteúdo:
XML
1: <services-config>
2: <services>
3: <service id=“amfphp-flashremoting-service”
4: class=“flex.messaging.services.RemotingService”
5: messageTypes=“flex.messaging.messages.RemotingMessage”>
6: <destination id=“amfgateway”>
7: <channels>
8: <channel ref=“channel-amf”/>
9: </channels>
10: <properties>
11: <scope>session</scope>
12: <source>*</source>
13: </properties>
14: </destination>
15: </service>
16: </services>
17: <channels>
18: <channel-definition id=“channel-amf” class=“mx.messaging.channels.AMFChannel”>
19: <endpoint uri=“http://{server.name}:{server.port}/FlexPHP/libs/amfphp/gateway.php”
20: class=“flex.messaging.endpoints.AMFEndpoint”/>
21: </channel-definition>
22: </channels>
23: </services-config>
E nos Properties do Projeto, o FlexCompiler deverá ficar assim:
Historic image unavailable from the original source: Flex Compiler.
Listagem 4
Detalhando as Camadas
O Fluxo das Camada é a seguinte:
O Flex chama um Serviço através do AMFPHP que direciona para uma classe com um especifico método no package services;
Ex: O Flex Chama a classe ContatoService, solicitando o método save(), passando por parâmentro uma instância de ContatoVO.
A Service chama uma classe da Facade com o respectivo método solicitado;
Ex: O ContatoService chama o ContatoFacade solicitando o método save() passando por parâmentro uma instância de ContatoVO.
A Facade abre uma transação, e chama um SessionBean;
Ex: O ContatoFacade chama o ContatoBean solicitando o método save() passando por parâmentro uma instância de ContatoVO.
O SessionBean faz a regra de negócio específica do caso de uso, e se tudo tiver ok chama um EntityBean para fazer a persistência, se não dispara uma nova Exception dando rollback no banco e mostrando uma mensagem de erro para o Flex através do catch na Facade;
Ex: O ContatoSession chama o ContatoBean solicitando para que insira ou atualize os dados através do ContatoVO passado por parâmentro.
Tendo conhecimento do Fluxo das camadas pode se observar que o código ficou bem separado, o que garante baixo acoplamento e alta coesão.
E como Fica no Flex?
Historic image unavailable from the original source: Estrutura de Pastas Flex. Listagem 5
Como este exemplo tem por finalidade de mostrar uma proposta de arquitetura com Flex e PHP, este exemplo não adota padrões de projetos no lado Flex, mas é extremamente recomendável o uso de Padrões seja com o Cairngorm da Adobe ou tantos outros existentes porae.
A classe RemoteConnection é uma classe que tem por finalidade de abstrair o uso do RemoteObject, como por exemplo você pode chamar o ContatoService desta forma:
var contatoVO:ContatoVO = new ContatoVO();
contatoVO.dsNome = txtNome.text;
contatoVO.dsEmail = txtEmail.text;
contatoVO.nuTelefone = txtTelefone.text;
contatoVO.dsCidade = txtCidade.text;
contatoVO.dsEstado = txtEstado.text;
contatoVO.dsMensagem = txtMensagem.text;
RemoteConnection.call("ContatoService","save",
function(event:ResultEvent):void
{
Alert.show("Email enviado com sucesso!","SUCESSO!");
clear();
},
contatoVO
);
Perceba que gero um VO com as informações da Tela, e Solicito o serviço ContatoService chamando o método save() passando por parâmetro uma instância de ContatoVO.
A Função de retorno implementei dentro do próprio método, mas eu poderia criar uma função só para tratar o retorno do método assíncrono.
Bom Senhores, acredito que consegui dar uma boa explicação sobre como trabalhar arquiteturalmente com Flex e PHP.
Estarei diponibilizando o projeto usado no exemplo, para executar, dentro da pasta docs contém 2 arquivos, um chamado localhost.sql.zip que pode ser usado para gerar o banco de dados e outro chamado MER.xml que é o MER feito com o DBDesigner. Após gerar o banco, é só importar no seu Flex Builder 3.
Aplicação Rodando
Source do Projeto: Projeto FlexPHP
Para aqueles que tiverem dúvidas, sujestões ou críticas podem entrar em contato comigo, na medida do possível estarei lhes respondendo.
Obrigado a Todos e um Bom Proveito!
Liz.. te amo querida! =*
O que este artigo provocou?
Você pode marcar mais de uma opção e desfazer quando quiser.
Comentários
Carregando comentários…