terça-feira, 16 de setembro de 2008

On-demand javascript com PHP

A técnica de script on-demand serve para compartilhar dados entre domínios. A idéia dela é driblar as restrições da classe XMLHttpRequest, que só permite requisições no mesmo domínio, e a restrição do iframe que no máximo permite comunicação entre sub-domínios de um mesmo domínio.

Basicamente consiste em adicionar um script à página quando uma informação é necessária. Esse script proverá a informação necessária chamando uma função de callback ao solicitador. Uma explicação mais detalhada sobre a técnica pode ser encontrada em On-Demand_Javascript - AjaxPatterns.

Com PHP fica ainda mais fácil desenvolver o script provedor de dados. Digamos por exemplo que você queira obter a lista de livros de uma biblioteca, seu javascript ficaria assim:
var Livros = {
listar:function() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'listaDeLivros.php?callback=Livros.onload_listar';
document.getElementsByTagName('head')[0].appendChild(s);
}
onload_listar:function(html) {
document.getElementsByTagName('lista').innerHTML = html;
}
}

A função listar insere um javascript à página informando a ele a função javascript de callback. No PHP informaremos o html gerado chamando a função enviada no parâmetro callback. Mais ou menos como mostrado abaixo:
<?php echo $_REQUEST['callback']; ?>("<h1>Lista de livros</h1>");

Mas é claro que normalmente o html gerado não será de apenas uma linha. Além disso ele poderá ter diversos dados com aspas e outros caracteres que poderiam causar erros de javascript. Ficar se preocupando com esse tipo de coisa na diagramação do html é trabalhoso e passível de muitos erros.

Para evitar isso podemos utilizar a função ob_start, que faz com que tudo o que for escrito no output seja guardado em buffer e ao final remetido a uma função de callback do PHP. Nesta função então pode-se tratar o html e enfim escrever no real output para o cliente. Veja como ficaria:
<?php 
function captura_buffer($html) {
$html = addslashes($html);
$html = str_replace("\n", '\n', $html);
$html = str_replace("\r", '\r', $html);
return $_REQUEST['callback'] . '("' . $html . '");';
}
ob_start('captura_buffer');

$livros = funcao_ficticia_para_obter_livros();

foreach($livros as $livro) {
?>

<p>
<?php echo $livro->id ?> -
<b><?php echo $livro->titulo ?></b> -
<?php echo $livro->autor ?>
</p>

<?php } ?>

Um comentário: