AJAX e PHP: Aprendendo a base [Parte 1]
- ajax, Javascript, PHP
- August 19, 2008
nota: Este artigo foi publicado pela primeira vez na Quarta Edição da Revista PHP Magazine em março de 2008. Estou agora re-publicando ele aqui em duas partes, 1 e 2 , para melhor visualização
Neste artigo, pretendo apresentar ao Leitor a tecnologia AJAX, resolvendo algumas confusões sobre o que realmente é, e como e onde deve ser usada. Este artigo apresenta um exemplo de como implementar uma solução AJAX sem auxílio de Frameworks. Após palestrar sobre o assunto no 1º PHPDF RoadShow (E no PHP Conference 2007 em São Paulo) decidi por todo material das palestras em um artigo, que foi publicado pela primeira vez na PHP Magazine, e que agora re-publico aqui em meu Blog. Esta primeira parte esta dividida em duas pois descobri que meu WordPress fica louco com artigos grandes. E e breve este artigo terá uma sequencia que entrará no uso de FrameWorks.
Desde que comecei a pesquisar sobre AJAX devo admitir que me apaixonei pela forma que ele permite executar tarefas simples e avançadas de forma amigável, simples e ágil. Desde então, tenho procurado repassar este conteúdo, contribuindo brevemente com o site AJAX Online (www.ajaxonline.com.br ) e publicando diversos artigos em meu blog pessoal.
1. AJAX: detergente ou tecnologia?
O caminho para o aprendizado de AJAX não é muito longo, mas mesmo assim possui diversos atalhos que podem agilizar no desenvolvimento, porém podem acabar “saindo pela culatra” mais tarde, pois prejudicam o conhecimento. O primeiro passo e também o ponto de maior confusão, é a velha pergunta, “O que é AJAX?”. Leigos lhe dirão que é um detergente, alguns dirão que é uma nova linguagem de programação, eu lhes digo que se trata apenas de uma nova forma de ver algo mais antigo.
O AJAX é um conjunto de técnicas novas, envolvendo diversas tecnologias antigas, dentre elas: Javascript, XML, Document Object Model (DOM). Dentre estas tecnologias o único elemento novo é o XMLHttpRequest, e mesmo assim ele não é tão novo quanto parece.
O XMLHttpRequest surgiu pela primeira vez em 2000, criado pela Microsoft para ser usado no Outlook Web Access. Em 2002 a Mozilla incorporou o objeto em seus browsers e somente em 2006 foi lançado o primeiro draft na W3C. Neste ponto dá inicio o grande hype da “Web 2.0” e o AJAX começa a ser amplamente utilizado.
Conceitualmente, AJAX significa “Asynchronous JavaScript and XML” ou Javascript Assíncrono e XML, mas na prática é possível utilizar objetos com notação JSON (JavaScript Object Notation) também, ao invés de XML. Mais adiante vou discutir as vantagens e desvantagens disto. O grande conceito de AJAX é permitir que o cliente se comunique com o servidor através deste request, que é realizado em segundo plano, sem recarregar a página, efetivamente unindo a tecnologia client-side com a tecnologia server-side e potencializando a comunicação.
Atenção: use com moderação! Embora seja algo muito legal, o AJAX não deve ser usado em qualquer lugar, pois, ao invés de ajudar, pode tornar truncada a experiência do usuário, evite usar AJAX, por exemplo, como sua forma de navegação principal.
2. Aprendendo AJAX
Como disse anteriormente, o caminho para aprender AJAX tem diversos atalhos e, no momento em que se decide aprender AJAX, é necessário avaliar qual caminho irá tomar. Existem dois caminhos principais para se trilhar, aprender AJAX com frameworks ou sem frameworks. Cada um tem sua vantagem como, por exemplo, com frameworks a produtividade aumenta, porém sem ter trilhado o caminho “primitivo” dar manutenção em scripts que apresentam erros pode se tornar uma tarefa difícil. Eu, pessoalmente, defendo que se deve aprender pelo caminho difícil para depois viver no caminho fácil, então vou abordar as duas formas de se usar e aprender AJAX, iniciando neste artigo pelo AJAX puro, ou seja, primitivo, e deixando o segundo exemplo para uma futura contribuição..
2.1. AJAX primitivo
Implementar funções de AJAX “na mão” não é tarefa difícil, ao contrario do que muitos pensam, porém é importante, antes de mais nada, entender como funciona o objeto XMLHttpRequest.
O Request simula o funcionamento do browser. Neste último, quando se clica em um link, é feita uma requisição para determinado arquivo e o resultado desta requisição é apresentado na tela do browser. No AJAX, essa requisição é feita da mesma forma, porém o resultado não se carrega na janela e sim dentro do próprio objeto de request, isso causa o efeito de segundo plano que o AJAX apresenta.
Para isso, o objeto possui alguns métodos e propriedades importantes. Primeiro as propriedades:
- ReadyState: estado atual da requisição, indica se a pagina ainda está sendo buscada ou se o resultado já chegou, pode possui estes estados:
- 0 = uninitialized (não inicializado)
- 1 = loading (carregando)
- 2 = loaded (carregado)
- 3 = interactive (interagindo)
- 4 = complete (pronto)
- ResponseText: Resultado da requisição em formato de texto comum, usado também para JSON
- ResponseXML: Resultado em formato XML
- Status: Códigos de erro ou sucesso como: 200,404,403…
- StatusText: mesmo erro, mas de forma textual (Not found…)
- Onreadystatechange: propriedade/evento, indica a função que será executada quando a requisição mudar seu readyState
Para executar seu papel, o objeto conta também com alguns métodos:
- Open(“method”,“URL”,async,“uname”,“pswd”) este método abre uma nova requisição para a URL determinada com o método escolhido (GET ou POST). Esta requisição pode ser síncrona ou assíncrona, determinando se o código continua sendo executado independente da resposta ou se a resposta é aguardada para continuar o processamento.
- Send(content) este método inicia a comunicação com a URL e recebe apenas o parâmetro (opcional) de que conteúdo deve enviar. Este conteúdo está em formato de URL, ou seja, var=valor&var2=valor2.
- Abort() este método é simples e pode ser muito importante, pois finaliza uma requisição que ainda não retornou qualquer resposta do servidor, e é útil em casos onde novas requisições podem ocorrer descartando as anteriores sem respostas, como em campos de auto-complete.
- SetRequestHeader(“label”, “value”) este método é importante quando POST é utilizado, permitindo setar o conteúdo da requisição para “multipart/form-data”, por exemplo. Uma falha neste ponto pode derrubar toda a requisição.
- GetResponseHeader(“headername”) e getAllResponseHeaders() estes métodos são úteis em verificações de segurança que permitem, por exemplo, verificar se o conteúdo da resposta realmente está em JSON ou XML.
Para entender como usar este objeto e como devemos manipular seus métodos e propriedades, a seguir, definirei um exemplo simples de uma aplicação que pode utilizar AJAX, e acompanharei passo a passo com vocês a implementação.
3. Desenvolvendo um mural de recados com AJAX
O sistema proposto é bem simples, justamente para facilitar o entendimento do AJAX e não se focar em outros aspectos. De forma geral, o sistema deve possuir uma região onde apresenta as mensagens, o mural, e um campo que permita a alguém digitar algo, sendo isto inserido no mural sem haver um re-carregamento da página como um todo.
3.1 Modelagem
O primeiro passo de um sistema deve ser sempre a modelagem, utilizando UML ou outras formas de modelagem, porém, como este não é nosso foco, farei apenas uma modelagem simples para compreensão do sistema. O sistema contará com duas funcionalidades, adição e visualização de imagens. Portanto a figura abaixo apresenta o fluxo dos dados e eventos do momento que o usuário envia seu recado até ele aparecer no mural (por motivos de simplicidade, ao recarregar a página, as mensagens não são recarregadas no mural).
Separei o sistema em três módulos: javascript (verde), HTML (amarelo) e PHP (azul), para podermos ver a interação entre essas linguagens. No módulo de javascript, será realizada toda a operação de AJAX propriamente dita, como demonstrado na figura acima. Para isso, devemos criar 3 funções: uma para criar o request, uma para enviar a mensagem e outra para receber o retorno e publicar no mural.
No PHP precisamos de duas funções: uma que receba os dados e grave no banco e outra que formate o retorno e envie de volta para o javascript. Neste caso, estamos usando XML, mas o uso de JSON será demonstrado em futuros artigos. A estrutura do retorno XML proposta é a seguinte:
<?xml version="1.0" encoding="iso-8859-1" ?> <response> <erro>0/1</erro> <item id="1">Retorno em HTML ou Texto</item> </response>
No HTML teremos apenas um campo de input, um botão e um div que representa o mural. A figura abaixo demonstra como as funções interagem entre sim, de forma simplificada. Escolhi separar o sistema em 3 arquivos, onde cada um representa um dos módulos acima descritos.
A tabela onde os dados serão guardados pode ser criada com este código:
CREATE TABLE \`mural\` ( \`id\` int(3) NOT NULL auto\_increment, \`msg\` text character set latin1 collate latin1\_general\_ci, PRIMARY KEY (\`id\`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
3.2 Módulo Javascript
A primeira função que precisamos é a função responsável por criar o request de XMLHTTPRequest, mas por que fazer uma função? Simples, como o IE implementa o objeto de forma diferente de outros browsers implementamos estes diferentes métodos em uma função, com isso a instanciação do objeto se torna algo mais simples e pontual, veja código:
function criaRequest(){ try { request = new XMLHttpRequest(); } catch (trymicrosoft) {
try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) {
try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { request = false; } } }
if (!request) alert("Error initializing XMLHttpRequest!"); else return request; }
Agora devemos definir a função que vai enviar estes dados. Esta função deve chamar a função anterior para obter um request, e então iniciar seu processamento. O próximo passo é buscar o texto do campo e montar a requisição. Usaremos o método POST e, com isso, devemos definir o header de Content-Type, passando o texto do campo com o nome de variável “msg”.
Neste momento, também é importante definirmos a função que será executada ao final da requisição, usando o onreadystatechange. Para dar um efeito a mais neste momento, tornamos visível um DIV com o texto “Carregando…” para que o usuário possa saber que algo está acontecendo.
function enviaDados(){ //Novo Request linkReq = criaRequest();
if(linkReq != undefined){ //Pegar dados var msgBox = document.getElementById('msgBox');
//Montar requisição linkReq.open("POST","mural.ajax.php",true); linkReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); linkReq.onreadystatechange = recebeDados;
var params = "msg="+msgBox.value;
//Carregar DIV de "loading" document.getElementById('loading').style.display = 'block';
//Enviar linkReq.send(params);
//Esvaziar form msgBox.value = ""; }
}
Definimos a função recebeDados como o retorno do request, mas ela será chamada a cada alteração de estado. Portanto, precisamos verificar o novo estado para sabermos se o resultado final já foi retornado. Uma vez confirmado o estado 4, podemos tratar o retorno.
Para isso, como foi definido o retorno em XML, leremos os dados da variável responseXML, lendo os campos através de DOM e inserido este retorno no DIV, dentro de uma DIV própria da mensagem. Esta manipulação toda é feita através de DOM com funções que estão disponíveis desde o início dos browsers.
function recebeDados(){
//Verificar pelo estado "4" de pronto if (linkReq.readyState == '4'){
//Pegar dados da resposta XML var xmlRes = linkReq.responseXML;
//Verificar erro var erro = xmlRes.getElementsByTagName('erro');
if (erro\[0\].firstChild.nodeValue == '1'){ alert("Erro no retorno"+erro\[0\].firstChild.nodeValue); }else{ //Pegar mensagem var msg = xmlRes.getElementsByTagName('item');
//Pegar DIV destino var targetDiv = document.getElementById('msgList');
//Montar Nova msg var mDiv = document.createElement('div'); mDiv.id = "msg\_"+msg\[0\].id; mDiv.innerHTML = msg\[0\].firstChild.nodeValue;
//Adicionar ao destino targetDiv.appendChild(mDiv);
//Remove loading document.getElementById('loading').style.display = 'none'; }
} }
Veja na parte 2 os módulos de PHP e HTML e as conclusões finais e live demo, Parte 2 »