Hoje vou compartilhar com vocês um serviço para o Symfony2 que criei para recuperar um endereço (logradouro, bairro, cidade e estado) apartir do CEP usando o web service dos Correios do Brasil. Isto pode ser de grande utilidade em formulários de cadastro.
No screenshot do formulário encima, o usuário ao entrar o CEP e clicar na Lupa os campos Logradouro, Bairro, Cidade e Estado vão se autocompletar.
Primeiro vamos criar o nosso service chamado CorreiosService. O método cep2endereco(string de poche) vai chamar a seguinte URL http://m.correios.com.br/movel/buscaCepConfirma.do enviando o CEP em formato 99999-999 ou 99999999 por POST, vai parsear o resultado e retornar ele dentro de um Array.
Project/src/AppBundle/Service/CorreiosService.php
<?php
namespace AppBundle\Service;
class CorreiosService
{
// >=PHP5
public function cep2endereco($cep)
{
$url = 'http://m.correios.com.br/movel/buscaCepConfirma.do';
$data = array(
'cepEntrada' => $cep,
'metodo' => 'buscarCep'
);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
),
);
$context = stream_context_create($options);
$html = file_get_contents($url, false, $context);
$html = preg_replace("/\s+/", " ", $html);
$pattern = "/<span class=\"respostadestaque\">([^<]*)<\/span>/";
preg_match_all($pattern, $html, $out);
if (isset($out[1][0]) && isset($out[1][1]) && isset($out[1][2])) {
$endereco = array(
'logradouro' => utf8_encode(preg_replace("/ - .*/", "", trim($out[1][0]))),
'bairro' => utf8_encode(trim($out[1][1])),
'cidade' => utf8_encode(split(" /", trim($out[1][2]))[0]),
'estado' => utf8_encode(split(" /", trim($out[1][2]))[1])
);
} else {
$endereco = array(
'logradouro' => '',
'bairro' => '',
'cidade' => '',
'estado' => ''
);
}
return $endereco;
}
}
Uma vez que já temos nosso service vamos declarar ele no arquivo services.yml com o nome de app.correios para poder acessar ele em qualquer lugar dentro do nosso projeto.
Project/app/config/services.yml
services:
app.correios:
class: AppBundle\Service\CorreiosService
É possivel acessar o nosso serciço desde qualquer controller de esta maneira.
$endereco = $this->get('app.correios')->cep2endereco($cep);
Agora que temos acesso o nosso serviço, vamos criar um controller chamado AjaxController na rota (/ajax/cep/). Quando enviamos o CEP por GET (/ajax/cep/?cep=22020-002) ele retorna um JSON como o endereço com a estrutura seguinte.
{
"logradouro":"Avenida Nossa Senhora de Copacabana",
"bairro":"Copacabana",
"cidade":"Rio de Janeiro",
"estado":"RJ"
}
Project/src/AppBundle/Controller/AjaxController.php
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
/**
* @Route("/ajax")
*/
class AjaxController extends Controller
{
/**
* @Route("/cep/", name="ajax_cep")
*/
public function cepAction(Request $request)
{
return new JsonResponse(
$this->get('app.correios')->cep2endereco($request->get('cep'))
);
}
}
Agora vamos criar um script Javascript usando a librária jQuery para detectar o evento de click no botão de Lupa e ai como o método getJSON enviar o CEP colocado no primeiro input, recuperar o JSON retornado pelo controller e preencher os inputs logradouro, bairro, cidade e estado automaticamente.
Project/web/assets/js/scripts.js
$(document).ready(function() {
$('.btn-cep2endereco').click(function() {
var ico = $(this).children('i');
ico.attr('class', 'fa fa-circle-o-notch fa-spin');
$.getJSON($(this).data('route'), { cep: $('.ac-cep').val() })
.done(function(data) {
if (data.logradouro != '') {
$('.ac-logradouro').val(data.logradouro);
$('.ac-bairro').val(data.bairro);
$('.ac-cidade').val(data.cidade);
$('.ac-estado').val(data.estado);
ico.attr('class', 'fa fa-check');
} else {
ico.attr('class', 'fa fa-ban');
}
setTimeout(function(){ ico.attr('class', 'fa fa-search'); }, 2000);
})
.fail(function() {
ico.attr('class', 'fa fa-exclamation-circle');
setTimeout(function(){ ico.attr('class', 'fa fa-search'); }, 2000);
});
});
});
Finalmente, já só falta a view da secção do form onde sai o template do endereço (não vou colocar o Form Type nem a Entity neste exemplo). Este exemplo usa Bootstrap3 e os iconos FontAwesome. O mais importante aqui é colocar as seguintes classes css para indicar a que campo pertence cada input (ac-cep, ac-logradouro, ac-bairro, ac-cidade e ac-estado), a classe btn-cep2endereco, e a propiedade data-route=”{{ path(‘ajax_cep’) }}” no botão da Lupa.
Project/app/Resources/views/form.html.twig
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-home"></i> Endereço</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-4">
<div class="form-group">
{{ form_label(form.cep) }}
<div class="input-group">
{{ form_widget(form.cep, {'attr': {
'class': 'form-control ac-cep',
'placeholder': 'CEP',
'data-mask': '99999-999'
}}) }}
<span class="input-group-btn">
<button type="button" class="btn btn-default btn-cep2endereco tooltip-ajuda" data-toggle="tooltip" data-placement="left" title="Busca endereço a partir do CEP" data-route="{{ path('ajax_cep') }}">
<i class="glyphicon glyphicon-search"></i>
</button>
</span>
</div>
{{ form_errors(form.cep) }}
</div>
</div>
<div class="col-md-8">
<div class="form-group">
{{ form_label(form.logradouro) }}
{{ form_widget(form.logradouro, {'attr': {
'class': 'form-control ac-logradouro',
'placeholder': 'Logradouro'
}}) }}
{{ form_errors(form.logradouro) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
{{ form_label(form.bairro) }}
{{ form_widget(form.bairro, {'attr': {
'class': 'form-control ac-bairro',
'placeholder': 'Bairro'
}}) }}
{{ form_errors(form.bairro) }}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{{ form_label(form.cidade) }}
{{ form_widget(form.cidade, {'attr': {
'class': 'form-control ac-cidade',
'placeholder': 'Cidade'
}}) }}
{{ form_errors(form.cidade) }}
</div>
</div>
<div class="col-md-2">
<div class="form-group">
{{ form_label(form.estado) }}
{{ form_widget(form.estado, {'attr': {
'class': 'form-control ac-estado',
'placeholder': 'Estado'
}}) }}
{{ form_errors(form.estado) }}
</div>
</div>
<div class="col-md-3">
<div class="form-group">
{{ form_label(form.numero) }}
{{ form_widget(form.numero, {'attr': {
'class': 'form-control',
'placeholder': 'Número'
}}) }}
{{ form_errors(form.numero) }}
</div>
</div>
</div>
</div>
</div>
Cualquer duvida é so deixar um comentario.

