Validando formulários com Zend Form, jQuery e Ajax.
Sabemos que validar formulários hoje em dia é uma obrigação de todo bom desenvolvedor. E não validar apenas no cliente usando javascript, mas validar também no servidor. Validação é o primeiro de muitos passos para tornar sua aplicação mais segura.
Uma técnica que eu acabei descobrindo recentemente e estou usando bastante é juntar o poder do componente Zend_Form com o beleza do jQuery, o que me trouxe resultados muito bons, principalmente nos quesitos qualidade e desenvolvimento ágil.
Para demostrar essa técnica que eu estou utilizando eu vou partir do pressuposto que você já esta familiarizado com o ambiente do Zend Framework. Partindo disso, vou mostrar o código simples do formulário de cadastro:
class Cadastro_Form extends Zend_Form {
public function init() {
$this->setAttrib(‘id’, ‘cadastro’)
->setAction(‘/index/index’)
->setMethod(‘post’);
$this->addElement( ‘text’, ‘nome’, array(
‘label’ => ‘Nome’,
‘required’ => true,
‘validators’ => array(
‘NotEmpty’,
array(‘StringLength’, false, array(0, 60) )
)
));
$this->addElement(‘text’, ‘email’, array(
‘label’ => ‘E-mail’,
‘required’ => true,
‘validators’ => array(
‘NotEmpty’,
‘EmailAddress’
)
));
$this->addElement( ’submit’, ’submit’, array(
‘ignore’ => true,
‘label’ => ‘Entrar’
));
$this->getElement(’submit’)->removeDecorator(‘label’);
}
}
Agora que nosso formulário de cadastro já é um componente do projeto, vamos fazer as paginas, vou supor aqui que estamos trabalhando no controller index, portando criaremos duas actions para que nosso controller aqui fique da seguinte maneira:
/** Nesta action iremos exibir o formulario */
public function indexAction() {}
/** Nesta action iremos receber o dados por ajax para validação */
public function validarAction() {}
}
Temos o básico para começarmos a trabalhar. Agora a ideia é validarmos estes dados na tela do cliente via ajax, para que antes do cliente submeter os dados ele consiga visualizar os possíveis erros e já corrigi-los. Lembrando também que isso NÃO descarta a validação no servidor.
Vamos ver como fica nosso metodo indexAction():
$form = new Cadastro_Form;
if ($this->_request->isPost()) {
if ($form->isValid( $this->_request->getPost() )) {
$this->view->mensagem = ‘Formulario valido’;
}
else {
$this->view->mensagem = ‘Ops. Formulario invalido.’;
$form->populate( $this->_request->getPost() );
}
}
$this->view->form = $form;
}
E agora nossa index.phtml
<p><?php echo $this->mensagem; ?></p>
<?php echo $this->form; ?>
Não podemos esquecer de adicionar a biblioteca jQuery a nossa camada view, pois ela irá nos ajudar muito no processo, vejamos o nosso código javascript para a validação:
$(‘#submit’).bind(‘click’, function (e) {
e.preventDefault();
var nome = $(‘#nome’).val();
var email = $(‘#email’).val();
$.ajax({
url: ‘/index/validar’,
type: ‘post’,
dataType: ‘json’,
data: {
nome: nome,
email: email
}
success: function (data) {
$(‘.form-errors’).remove();
if (data == true) alert( ‘Passou…’ );
else {
for (campo in data) {
$(‘#’+campo).after(‘<ul id="’+campo+‘_errors" class="form-errors"></ul>’);
for (mensagem in data[campo]) {
$(‘#’+campo+‘_errors’).append(‘<li>’+data[campo][mensagem]+‘</li>’);
}
}
}
}
});
});
});
Como vocês podem ver, nosso método validar irá retornar um objeto json para o jQuery poder trabalhar, e com o for iremos percorrer este objeto colocando cada mensagem em seu devido lugar. É um bom método por não fazer você ter que escrever duas validações, uma para javascript e outra para php. Você escreve apenas uma e utiliza em ambas as validações.
Agora nosso método validar:
if ($this->_request->isXmlHttpRequest()) {
$form = new Cadastro_Form;
echo $form->processAjax($this->_request->getPost());
}
}
Como vocês viram, devido ao nosso componente de formulário já está pronto tudo ficou muito mais simples, com apenas algumas linhas validamos e retornamos o resultado para o javascript poder exibir ao usuário.
O resultado desta combinação é muito interessante, pois mantem nossa aplicação modularizada, de forma que para adicionar novos campos no nosso formulário de cadastro não é necessário se preocupar com html e validação javascript, basta editar o componente Cadastro_Form.
Qualquer duvida deixa nos comentários ai que vamos trocando uma ideia.
Referencias:
http://framework.zend.com/manual/en/zend.form.html
http://framework.zend.com/manual/en/zend.validate.html
http://docs.jquery.com/Ajax
Excelente artigo! Tudo a funcionar excepto um pormenor.. O captcha.
O meu captcha tem id “captcha”, mas a textbox com o valor inserido pelo utilizador para verificar que este é humano tem um id “captcha-input” que é gerado automaticamente a partir do id original “captcha”.
O problema é que o JavaScript não aceita que eu escreva:
captcha-input: captcha-input,
no parametro data. Parece que entende aquilo como uma subtração.
Tentei fazer o seguinte:
var captcha_input = $(‘#captcha-input’).val(); // O javascript só aceita underscore…
e no parâmetro data usei
captcha_input: captcha_input,
Se criar um alert no ciclo que escreve as mensagens de erro, o campo captcha não é mencionado.
O que está a correr mal??
Obrigado
PS: Sem usar AJAX, o form funciona perfeitamente.
Como podemos personalizar as mensagens de erro?
Oi Fabio,
Vou preparar um post sobre como traduzir e personalizar as mensagens de erro do Zend_Validate.
Abraços
Obrigado! Deixe-me só adiantar que arranjei uma maneira de fazer isso no Bootstrap, mas quando activo essas traduções/customizações, a validação apresenta mensagens com o texto “null” em vez das mensagens traduzidas ou as originais…
protected function _initFormMessages()
{
$translateValidators = array(
Zend_Validate_NotEmpty::IS_EMPTY => ‘Campo obrigatório’,
Zend_Validate_Regex::NOT_MATCH => ‘Valor inválido’,
Zend_Validate_Date::NOT_YYYY_MM_DD => ‘Formato inválido (YYYY-MM-DD)’,
Zend_Validate_StringLength::TOO_SHORT => ‘Campo não pode ter menos do que %min% caracteres’,
Zend_Validate_StringLength::TOO_LONG => ‘Campo não pode ter mais do que %max% caracteres’,
Zend_Validate_EmailAddress::INVALID => ‘Endereço de e-mail inválido’,
Zend_Validate_Digits::NOT_DIGITS => ‘Campo só pode conter algarismos’
);
$translator = new Zend_Translate(‘array’, $translateValidators);
Zend_Validate_Abstract::setDefaultTranslator($translator);
}
Isto funciona bem sem a validação ajax. Na validação ajax, as mensagens de erro passam a aparecer “null” (todas elas).
Vou ficar a aguardar o seu post. Mais uma vez obrigado! Abraços
Fabio,
Talvez seja melhor você definir as mensagens diretamente no seu formulário.
Inclusive, vou preparar um post mostrando essa ideia.
Abraços