Requisições Ajax com CakePHP - Artigo super completo Artigo

Conheça os cursos gratuitos do WebDevBr! - Inscreva-se!


Este artigo foi publicado a 3 anos, 7 meses, 2 semanas, 5 dias atrás.

Como tudo em CakePHP, fazer requisição ajax não é um bicho de 7 cabeças, retornar uma view formatada para o ajax, retornar o array do find() em json, gerar o html com os options em um select ou o que você precisar, é fácil e muito prático de conseguir.

O que é Ajax (leia, por favor)

E dizia Zeca Pagodinho: "Nunca vi nem comi eu só ouço falar", e é essa a realidade de 90% (se não mais) dos desenvolvedores web no mercado, já ouviu falar, a maioria até usou e quase todos nunca pesquisaram nem ao menos o que significa ou a origem da palavra, se você é um destes que já usou, mas não sabe o que é de verdade te dou duas opções, leia esta seção do artigo ou então pule e continue a comer caviar sem saber o que é.

Ajax é uma sigla para "Asynchronous Javascript and XML" ou "Javascript Assíncrono e XML" e foi originalmente criado por Jessé James Garret. Embora as palavras "assíncrono" e "xml" apareçam alí ele não se limita apenas a isso.

Gostou deste artigo?

Receba atualizações semanais com novos artigos do WebDevBr e outras dicas!

Primeiramente o Ajax pode fazer requisições assíncronas e síncronas, em ambos os modos a página não é recarregada por completo, mas a diferença principal é que no modo assíncrono várias requisições são feitas ao mesmo tempo e no modo síncrono apenas uma requisição pode ser feita por vez e o restante da página tem que esperar terminar.

Embora tenha sido feito originalmente para xml (note que o x da sigla é de xml e que o objeto usado no Javascript se chama XMLHttpRequest, note as 3 primeiras letras) o json é muito usado também, além do próprio html. O Ajax evoluiu muito e hoje em dia muitos formatos são aceitos, o Jquery, por exemplo, aceita no parâmetro dataType os valores xml, json, script e html.

Logo que foi lançado, a ideia foi muito bem aceita, até a Microsoft "criou" o MicrosoftXMLHTTP, a versão deles do XMLHttpRequest (frescura?), para IE 5 (pra você ter uma ideia do suporte).

Mas neste momento o objeto XMLHttpRequest e o Javascript não interessam para nós, queremos mesmo é montar o retorno do CakePHP, e agora que você sabe como funciona, já deve saber que o CakePHP apenas vai gerar o retorno para o seu Javascript.

Como identificar e setar um retorno ajax no CakePHP

O PHP tem uma variável super global chamada $SERVER que traz diversos dados do servidor e do seu script, entre as informações você encontra o HTTPXREQUESTEDWITH que diz quando uma requisição é ajax, o CakePHP usa isso pra identificar requisições ajax através do comando $this->request->is('ajax'), veja um exemplo de como setar o layout ajax automaticamente quando necessário no CakePHP.

if ($this->request->is('ajax') {
    $this->layout = "ajax";
}

Com isso você pode construir aquele action que lista as cidades e gerar os options em html ou o json pra quando selecionar o estado (:D) no formulário o seu javascript trazer eles com o ajax.

Gerando arquivos Json

Hoje em dia o Xml já não é mais tão utilizado assim, a vez é do json agora. Pra gerar um arquivo json você vai precisar de 3 coisas:

  1. Configurar o routes.php
  2. Incluir o component Request Handler
  3. E configurar sua view

Configurando o routes.php

Não vou nem estender muito, abra o routes.php que está em app/Config/routes.php e acrescente no começo.

Router::parseExtensions('json');

Pronto, você já pode usar a extensão .json e o CakePHP vai interpretar e informar a view correta (que não é a que você está acostumado), mas aguarde, vamos chegar na view daqui a pouco.

O Request Handler

Abra também o AppController (ou o controller específico que quer usar), e inclua na variável $components o component request, assim:

public $components = array('RequestHandler');

Ele cuida dos cabeçalhos, requisições e afins (setar um cabeçalho json quando você usar a extensão, por exemplo).

Configurando a view

E por fim na sua view, inclua uma pasta com a extensão que configurou no routes.php (json) e dentro o nome do arquivo ctp, por exemplo, o controller Paginas com uma action index ficaria com os arquivos da view assim

  • app View

    • Paginas
      • json
        • index.ctp - Arquivo de view quando usar a extenção
      • index.ctp - Arquivo de view normal

Se a extensão passada tiver uma view na pasta correta ele abre, se não é erro 404.

Na view da pasta json use o json_encode() para transformar um array em um resultado json:

    echo json_encode($cidades);

É só isso, não esqueça que para acessar seu arquivo json você precisa passar a extensão na action, assim:

www.seusite.com.br/controller/action.json

Ou se tiver algum parametro (como o estado):

www.seusite.com.br/controller/action/estado/id.json.

Enfim, a extensão vai no fim (claro).

Aqui a página da documentação do json_encode(), nativo do php: http://www.php.net/manual/pt_BR/function.json-encode.php

Exemplos

E pra fechar, vou dar um exemplo de como requisitar uma lista de estados e cidades ao CakePHP usando Javascript (Jquery).

Pra começar vamos preparar nosso Controller com uma action que será responsável por trazer a lista de estados, vamos supor que você tenha duas tabelas, uma chama estados e a outra chamada cidades, com isso teremos então dois Models, um chamado Estado e o outro chamado Cidade aonde:

Estado hasMany Cidade

E no controller Estados, duas actions:

public function ajax_estados()
{
    $retorno= $this->Estado->find('list', array('fields'=>array('Estado.id', 'Estado.nome')));
    $this->set(compact('retorno'));
    $this->render('ajax');
}

public function ajax_cidades($id_estado)
{
    $retorno= $this->Estado->Cidade->find('list', array('fields'=>array('Estado.id', 'Estado.nome')), 'conditions'=>array('Cidade.estado_id'=>$id_estado));
    $this->set(compact('retorno'));
    $this->render('ajax');
}

Então a primeira action (ajax_estados()) traz a lista completa de estados com um find, sendo que a chave do arrai será o id e o label será o nome (do estado), já a segunda busca no model Cidade (que pode ser acessado através do model Estado, já que é relacionado). Note também que informei em ambas as actions um $this->render, alterando assim a view padrão, é apenas pra evitar ficar criando um monte de view com o mesmo conteúdo, nada tem a ver com o retorno ajax. Só pra constar, não chequei se o estado existia alí, seria legal fazer isso, fique esperto.

E a view ficaria em app/View/Estados/json/ajax.ctp (ajax.ctp por conta do $this->render()):

echo json_encode($retorno);

Se você já configurou o $this->layout = 'ajax', o Router::parseExtensions('json'); e o public $components = array('RequestHandler'); você já está pronto pra começar, se não, faça isso agora, o $this->layout = 'ajax' ficaria assim aqui:

public function beforeRender()
{
    if ($this->request->is('ajax') {  
        $this->layout = "ajax";  
    }
}

public function ajax_estados()
{
    $retorno= $this->Estado->find('list', array('fields'=>array('Estado.id', 'Estado.nome')));
    $this->set(compact('retorno'));
    $this->render('ajax');
}

public function ajax_cidades($id_estado)
{
    $retorno= $this->Estado->Cidade->find('list', array('fields'=>array('Estado.id', 'Estado.nome')), 'conditions'=>array('Cidade.estado_id'=>$id_estado));
    $this->set(compact('retorno'));
    $this->render('ajax');
}

Você ainda pode querer incrementar mais suas actions incluindo uma checagem de requisição, assim só permitiria acesso ajax e algumas outras coisas que possa pensar, eu apenas escrevi o código aqui para demonstrar, nem testei ele.

Já seu javascript ficaria assim:

base_url = '<?php echo $this->webroot;?>;';
$('.campo-de-estados').change(function(){
    var este = $(this);
    $.ajax({
        'url':base_url+'estados/ajax_cidades/'+este.val(),
        'dataType':'json',
        'success':function(data) {
            var html='';
            $.each(data, function(i, item) {
                html = html+'<option value="'+i+'">'+data[i]+'</option>';
            });​
            $('.campo-de-estados').html(html);
        }
    });
});

Claro... também não testei, escrevi de primeira aqui, mas tenha em mente que você vai precisar ter os valores iniciais porque o evento que estou usando (change) busca os dados quando vc alterar escolhar um estado, então:

  1. Você vai precisar trazer a lista de estados no CakePHP.
  2. Você vai precisar setar um valor em branco ('empty') para o campo de cidades.
  3. Conferir o código e ver se eu não cometi alguma gafe

De primeira é isso, imagino que já da pra ter uma idéia de que depois do server configurado você só precisa saber a URL que vai acessar, além de Javascript, claro.

Conclusão

Se você gostou deste artigo, saiba que eu sempre atualizo meus artigos, então se cadastra ai do lado, que eu te aviso quando atualizar este.


Cursos relacionados


* Parcelamento apenas cartão de crédito! Pode haver uma pequena variação no parcelamento em relação a simulações apresentadas!