[ Tutorial ] Zend Framework – Parte 05

Formulários, Zend_Mail

Sumário

Na parte anterior vimos o Objeto Request e aprender como trabalhar com parametros do URL e fazer redirecionamentos baseados em parametros e fizemos uma revisita no Layout e Views. Vamos aprender agora como criar Forms e enviar emails utilizando o Zend_Mail.

Formulários

Criar formulários com o Zend é relativamente muito fácil.
Você deve estar se questionando o que este assunto tem de importante, pois você melhor do que ninguém sabe como criar formulários em HTML e PHP, ou atém mesmo utiliza alguma classe que gera formulários para você.
Bom, este tema é muito importante em todos os casos, pois além de gerar os formulários você pode integrar os formulários gerados pelo Zend de diversas formas e realizar validações, filtragens de dados, autenticação tudo de uma forma natural sem sobrecarregar a aplicação

Criando Formulários com o Zend Framework

Para entender, nada melhor que colocar a mão na massa.
Então vamos lá. Abra o seu prompt de comando ou terminal e acesse a pasta de nosso projeto.

Digite o comando:

 lang="plain
zf create form contato

A linha de comando acima irá criar um arquivo chamado Contato.php contendo uma classe Application_Form_Contato dentro da pasta /application/forms/

IMPORTANTE: É possível trabalhar com formulários distintos por módulos. Entretanto, como o mesmo envolve muitas configurações, e possui alguns ‘bugs’, vamos criar o formulário da maneira mais simples.

O arquivo gerado pelo ZF Tool contem o nome da classe que é extendida de Zend_Form e o método init() que tem a mesma finalidade vista para os Controllers.

/application/forms/Contato.php


<?php

class Application_Form_Contato extends Zend_Form
{

    public function init()
    {
        /* Form Elements & Other Definitions Here ... */
    }


}

Para testar o formulário gerado pelo ZF Tool, abra o arquivo IndexController.php do módulo default.
Vamos criar um view que disponibilizará o formulário no nosso arquivo script views/scripts/index/contato.phtml do módulo default.

Para chamar o objeto instanciamos desta forma no controlador:

/application/modules/default/controllers/IndexController.php


...
public function contatoAction
{
    $form = new Application_Form_Contato();
    $this->view->form = $form;
}
...

e no arquivo view contato.phtml coloque em qualquer lugar a sentença:


<?= $this->form; ?>

IMPORTANTE:Na parte 03 eu não coloquei a rota para a página ‘contato’ no arquivo de configuração. Se você está seguindo este tutorial a risca e for testar agora, vai receber um erro, então logo abaixo das linhas onde configuramos as rotas, insira as linhas:

 lang="plain
resources.router.routes.contato.route = /contato
resources.router.routes.contato.defaults.module = default
resources.router.routes.contato.defaults.controller = index
resources.router.routes.contato.defaults.action = contato

Agora abra a página http://zend.localhost/contato e você não verá nada ( risos ).
Claro! Não criamos nenhum elemento ainda.
Mas para fins de curiosidade, veja o código-fonte.
Repare que o Zend criou a tag FORM com alguns atributos mais uma tag DL:


<form enctype="application/x-www-form-urlencoded" action="" method="post"><dl class="zend_form">
</dl></form>

Formulário de Contato

Vamos então definir atributos para nosso formulário e adicionar elementos.
Como o objetivo deste tutorial é ser didático, vamos criar um formulário contendo um exemplo dos elementos HTML que mais utilizamos em formulários.

  • radio [tratamento]
  • input [nome, email]
  • select [assunto]
  • textarea [mensagem]
  • checkbox [newsletter]
  • submit [enviar]

Para criar os elementos do formulário, é claro, teremos que digitar (risos).

Atributos da tag FORM

Antes de criamos os elementos, precisamos definir os atributos do formulário em si, tais como:

  • method
  • action
  • name
  • id
  • enctype – embora não vamos fazer uploads e podemos utilizar o gerado pelo Zend, vou deixar a dica

Vou deixar os comentários dentro do código abaixo para não saturar o texto do tutorial, então analise o código abaixo.


<?php
class Default_Form_Contato extends Zend_Form
{
    public function init()
    {
        
        /*******************************************
         * As definições abaixo são obrigatórias 
         * todo formulário deve conter
         *******************************************/
        /**
         * Vai gerar o atributo/valor name="contato"
         */
        $this->setName( 'contato' );
        /**
         * Vai gerar o atributo/valor action="/contato"
         */
        $this->setAction( '/contato' );
        /**
         * Vai gerar o atributo/valor method="post"
         */
        $this->setMethod( 'post' );
        
        /**********************************************
         * As definições abaixo são opcionais 
         * e dependem de peculiaridades de seu FORM
         *********************************************/
        $this->setAttrib('enctype', 'multipart/form-data');
        /**
         * Vai gerar o atributo/valor id="form-contato"
         */
        $this->setAttribute( 'id', 'form-contato' );   
    }
}

NOTA: Como você deve ter notado todas as definições foram feitas dentro do método init().

Vamos criar os elementos agora. Analise o código abaixo, creio que ele seja bem intuitivo em relação ao qual campo do formulário estamos criando:


class Application_Form_Contato extends Zend_Form
{
    public function init()
    {
        /**
         * Definições para o FORM
         */
        $this->setName( 'contato' );
        $this->setAction( '/contato' );
        $this->setMethod( 'post' );
        $this->setAttrib( 'enctype', 'multipart/form-data' );
        $this->setAttrib( 'id', 'form-contato' );
        
        /**
         * Elementos do formulário
         */
        $tratamento = new Zend_Form_Element_Radio('tratamento');
        $tratamento->setLabel('Como gostaria de ser atendido?')
            ->addMultiOptions(
                array(
                    'Você' => 'Você',
                    'Sr(a).' => 'Sr(a)',
                    'Pelo Nome' => 'Pelo Nome',
                )
            )
            ->setValue('Pelo Nome');   

        $nome = new Zend_Form_Element_Text( 'nome' );
        $nome->setLabel( 'Nome' );

        $email = new Zend_Form_Element_Text( 'email' );
        $email->setLabel( 'E-mail' );
        
        $assunto = new Zend_Form_Element_Select( 'assunto' );
        $assunto->setLabel('Assunto')
            ->addMultiOptions(
                array(
                    '' => ' - - Escolha um assunto - - ', // em branco
                    'Dúvidas' => 'Dúvidas',
                    'Elogios' => 'Elogios',
                    'Reclamações' => 'Reclamações',
                    'Outros' => 'Outros',
                )
            );
        
        $mensagem = new Zend_Form_Element_Textarea( 'mensagem' );
        $mensagem->setLabel( 'Mensagem' );
        
        $newsletter = new Zend_Form_Element_MultiCheckbox( 'newsletter' );
        $newsletter->setLabel('Gostaria de Assinar Nosso Newsletter?')
            ->addMultiOptions(
                array(
                    'Tecnologia' => 'Tecnologia',
                    'Entretenimento' => 'Entretenimentos',
                    'Curiosidades' => 'Curiosidades',
                    'Produtos' => 'Produtos',
                    'Nenhum' => 'Não quero receber'
                )
            )
            ->setValue( 'Nenhum' );
        
        $submit = new Zend_Form_Element_Submit( 'submit' );
        $submit->setLabel( 'Enviar' );
        $this->addElements(
            array(
                $tratamento,
                $nome,
                $email,
                $assunto,
                $mensagem,
                $newsletter,
                $submit
            )
        );

    }
}

Salve o arquivo e abra novamente a página de contato. Veja que o formulário apareceu.

Entendendo o código

Como você pode ter notado, para cada elemento existe uma classe correspondente que chamamos através de


$nome_do_elemento = new Zend_Form_Element_<TIPO_DO_ELEMENTO>( VALOR_DO_ATRIB_NAME );

O protótipo acima deixa bem claro o que cada coisa significa.
Para cada elemento existem disponíveis vários métodos.
Em todos elementos utilizamos setLabel() que define o texto que o usuário verá na tela a fim de identificar o campo em questão.
[IMPORTANTE]Para elementos do tipo Submit e Button, o setLabel() funciona como o atributo value do elemento, como é o caso do botão Enviar que não possui Label, mas utilizamos setLabel(‘Enviar’).

No caso de campos como Radio, Checkbox e Select utilizamos o método addMultiOptions() para definir os valores desejados. Este método espera que um array seja passado contendo CHAVE => VALOR, conforme definimos para os campos tratamento|assunto|newsletter.

Para os elementos que precisam de um valor default quando o formulário é carregado, utilizamos setValue( VALOR ). Quando utilizado em elementos que o valor é parte de um addMultiOptions(), ele é sensível ao caso, ou seja você precisa passar EXATAMENTE o mesmo valor da chave, veja o caso do campo tratamento. Se colocassemos ‘pelo nome‘ ao invés de ‘Pelo Nome‘, ele não definiria nada. Ele funciona como checked para checkboxes e radios e selected para selects. Para outros campos de valor único funciona como value=”ALGUM VALOR”.

E por fim, temos o método addElements() do Zend_Form, que vai esperar um array contendo os objetos criados para cada elemento(campo) de nosso formulário. Os valores passados são as próximas variáveis, já que elas são os objetos.

CURIOSIDADE Abra o código-fonte da página contado e veja que o Zend adicionou algumas Marcações HTML utilizando listas de definição.

Outros elementos

Além dos elementos que criamos em nosso formulário, também estão disponíveis criar elementos:

  • button
  • reset
  • password
  • hidden
  • image
  • captcha [captcha] – apesar de não ser um elemento, atualmente utiliza-se muito e é algo bem elaborado no Zend

Qual a Vantagem de se criar Formulários com o Zend

No momento você pode estar pensando nisto, entretanto, apenas criamos o formulário.
Vamos ver agora como aplicar validação e filtros para entender o poder de se criar formulários com o Zend.

Validando o Formulário

Supondo que os campos nome|email|assunto|mensagem são obrigatórios e que os usuários poderiam passar código malicioso aos nossos códigos ou banco de dados através de nosso formulário, é interessante aplicar filtros e no caso de algum campo não ser enviado em branco, vamos informar que estes campos são obrigatórios.

Modifique o código:


...
        $nome = new Zend_Form_Element_Text( 'nome' );
        $nome->setLabel( 'Nome' )
            ->setRequired( true )
            ->addValidator( 'NotEmpty' )
            ->addFilter( 'StripTags' )
            ->addFilter( 'StringTrim' )
            ->addErrorMessage('Informe o seu nome');
        

        $email = new Zend_Form_Element_Text( 'email' );
        $email->setLabel( 'E-mail' )
            ->setRequired( true )
            ->addValidator( 'NotEmpty' )
            ->addFilter( 'StripTags' )
            ->addFilter( 'StringTrim' )
            ->addErrorMessage('Informe o seu email');                
        
        $assunto = new Zend_Form_Element_Select( 'assunto' );
        $assunto->setLabel('Assunto')
            ->addMultiOptions(
                array(
                    '' => ' - - Escolha um assunto - - ', // em branco
                    'Dúvidas' => 'Dúvidas',
                    'Elogios' => 'Elogios',
                    'Reclamações' => 'Reclamações',
                    'Outros' => 'Outros',
                )
            )
            ->setRequired( true )
            ->addErrorMessage('Escolha o assunto');
        
        $mensagem = new Zend_Form_Element_Textarea( 'mensagem' );
        $mensagem->setLabel( 'Mensagem' )
            ->setRequired( true )
            ->addValidator( 'NotEmpty' )
            ->addFilter( 'StripTags' )
            ->addFilter( 'StringTrim' )
            ->addErrorMessage('Escreva uma mensagem'); 
...

Se você executar o código agora, não vai acontecer nada!

Antes de fazer a coisa funcionar vamos explicar as linhas adicionadas aos elementos nome|email|assunto|mensagem.

Preste atenção nos comentários:


        $nome = new Zend_Form_Element_Text( 'nome' );
        $nome->setLabel( 'Nome' )
            // Marca o campo como obrigatório
            ->setRequired( true )
            // Não pode estar vazio
            ->addValidator( 'NotEmpty' )
            // Remove TAGS HTML
            ->addFilter( 'StripTags' )
            // Remove espaços brancos no inicio e fim
            ->addFilter( 'StringTrim' )
            // Define uma mensagem de erro personalizada
            ->addErrorMessage('Informe o seu nome');

Existem vários validadores e filtros entre os mais usados são os que você viu acima, mas ainda existem vários outros disponíveis.

No caso do email, além dos que utilizamos para os outros campos, utilizamos:


addValidator('EmailAddress', true);

Obtendo os dados enviados

Para que a validação ocorra de verdade é preciso que o Zend envie o formulário e faça algumas verificações. Caso ele identifique o valor de um dos elementos não corresponde com a validação solicitada, ele volta para a página do formulário e popula novamente o mesmo com os dados.

Para fazer isto, abra o arquivo IndexController.php e dentro do método contatoAction() insira o código abaixo:


...
    public function contatoAction()
    {

        $form = new Application_Form_Contato();
        $this->view->form = $form;
        
        $dadosFormulario = $this->getRequest()->getPost();
        
        if( $this->getRequest()->isPost() ) {
            
            if( $form->isValid( $dadosFormulario ) ) {                
            } else {
                $form->populate( $dadosFormulario );
            }
        }     
    }
...

Entendendo o Código – Solicitação POST

Tem bastante informação nova disponível agora, mas creio ser fácil de entender. Todo o código gira em torno de uma solicitação POST. Ao invés de utilizar $_POST o Zend oferece métodos exclusivos para tal.

Para obter os dados do Formulário utilizamos o Objeto Request que já conhecemos junto com o método getPost().

Este método pega a solicitação POST realizada e guarda todos os valores passados pelo formulário.

Isto é feito na linha:


$dadosFormulario = $this->getRequest()->getPost();

Para verificar se uma solicitação POST foi realizada o Objeto Request utiliza o método isPost().

Na estrutura de controle onde verificamos se há uma solicitação POST há uma condição que verifica se os dados do formulário correspondem com o que solicitamos ao Zend validar. Isto é feito através do método isValid().

1 – Se isValid() for verdadeiro, não acontece nada
2 – Se for falso popula o formulário novamente incluindo as mensagens de erros passadas pela validação.


...
        if( $this->getRequest()->isPost() ) {
            
            if( $form->isValid( $dadosFormulario ) ) {                
            } else {
                $form->populate( $dadosFormulario );
            }
        }
...

Tente enviar o formulário vazio e veja o resultado.
As mensagens de erro apareceram logo abaixo do campo solicitado validação.

Agora se você preencher corretamente os dados ele vai mostrar o formulário com todos os dados carregados novamente.
Como boa prática de programação web, sempre que você enviar um formulário e os dados estiverem preenchidos corretamente, você deve redirecionar o usuário para outra página com alguma mensagem ou para a mesma página.
Podemos redirecionar o usuário para outra página ou para a mesma utilizando:


 if( $form->isValid( $dadosFormulario ) ) {                
     $this->_redirect( '/contato' );
     // ou
     // $this->_redirect( '/qualquer-pagina-com-mensagem' );
 } 

Seria interessante se fossemos notificados do contato ou salvássemos os dados no banco de Dados.
Como este tutorial se estendeu demais sobre o assunto, vou terminar por aqui e vou pular para a parte de envio de emails com Zend_mail, deixando ai como dica e curiosidade para os mais ‘metidos’ e ensinar como criar Models na próxima parte.

Conclusão

Nesta parte de nosso tutorial você aprendeu a criar Forms e enviar email utilizando o Zend_Mail.
Na próxima parte de nosso tutorial vamos aprender como criar criar um sistema de autenticação utilizando Zend_Auth.

BONUS E-Mails com Zend_mail

IMPORTANTEEste procedimento somente é disponível em servidores locais configurados para enviar emails ou em servidores remotos. Você não conseguirá enviar email do localhost.
Então se você dispõe de um servidor dedicado, VPS, cloud, revenda, hospedagem, etc… Crie um subdominio no seu site chamado “zend” e envie os arquivos por FTP e faça o teste abaixo.

O Zend Dispõe de uma ferramenta muito legal para envio de Emails.
Ainda com o arquivo IndexController aberto no método contatoAction(), adicione as linhas abaixo:


...
    public function contatoAction()
    {

        $form = new Application_Form_Contato();
        $this->view->form = $form;
        
        $dadosFormulario = $this->getRequest()->getPost();
        
        if( $this->getRequest()->isPost() ) {
            
            if( $form->isValid( $dadosFormulario ) ) {  
                
                $tratamento = $form->getValue('tratamento');
                $nome = $form->getValue('nome');
                $email = $form->getValue('email');
                $assunto = $form->getValue('assunto');
                $mensagem = $form->getValue('mensagem');
                $newsletter = $form->getValue('newsletter');

                $conteudo = sprintf('
                        Assunto: <STRONG>%s</STRONG><BR>
                        <HR>
                        Tratamento: <STRONG>%s</STRONG><BR>
                        Nome: <STRONG>%s</STRONG><BR>
                        E-mail: <STRONG>%s</STRONG><BR>
                        Mensagem: <STRONG>%s</STRONG><BR>
                        Newsletter: <STRONG>%s</STRONG><BR>
                    '
                    , $assunto
                    , $tratamento
                    , $nome
                    , $email
                    , nl2br( $mensagem )
                    , implode(', ', $newsletter )
                );

                $to = 'contato@seusite.com';
                
                $subject = utf8_decode( "Contato pelo site por: " . $nome );
                $html = "
                    <html>
                    <body>
                        ".$conteudo."
                    </body>
                    </html>
                ";

                $mail = new Zend_Mail('utf-8');                
                $mail->setBodyHtml( $html );
                // poderia ser somente texto
                //$mail->setBodyText( $text ); 
                $mail->setFrom( $email, $nome );
                $mail->addTo( $to, 'Contato Site');
                $mail->setSubject( $subject );
                $mail->send();
                
                
                $this->_redirect( '/contato' );
                // ou
                // $this->_redirect( '/qualquer-pagina-com-mensagem' );
            } else {
                $form->populate( $dadosFormulario );
            }
        }
        
    }
...

Creio que o código acima é bem intuitivo.
Abraços do Giba!

9 comentários sobre “[ Tutorial ] Zend Framework – Parte 05”

  1. Grande Gilberto! Gostaria de tirar algumas dúvidas sobre o Zend Form…se você puder me ajudar, ficarei agradecido!

    Então..montei um layout de pagina de login, e cada está dentro de uma div personalizada com css…

    estou tendo dificuldades para resolver isso no zend…e descobri 2 formas, mas não muito claras até agora:
    através do setDecorators()
    através de impressão de view individual (ex: $this->form->login e $this->form->senha na pagina)

    poderia me ajudar?

    1. Olá, Eric.
      Bem, eu normalmente crio um arquivo view para o form.
      E recupero os elementos direto dentro dele.
      Vou postar um exemplinho aqui com 1 campo somente para você ver como eu faria:
      Formulario.php
      <?php
      class Application_Form_Formulario extends Zend_Form {
      public function init(){
      $this->setAction('/contato');
      $this->setName('formulario');
      $this->setMethod('post');
      $nome = new Zend_Form_Element_Text( 'nome' );
      // validações e filtros aqui

      $this->addElements(
      array(
      $nome,
      // n elementos aqui
      )
      );

      foreach($this->getElements() as $element) {
      $element->removeDecorator('DtDdWrapper');
      $element->clearDecorators();
      $element->removeDecorator('Label');
      $element->setDecorators(array(
      'ViewHelper',
      'label',
      'Errors',
      array(
      'HtmlTag',
      array(
      'tag' => '<div>',
      'class' => 'element'
      )
      )
      )
      );
      }
      $this->setDecorators(
      array(
      array(
      'ViewScript',
      array(
      'viewScript' => 'formulario.phtml'
      )
      )
      )
      );
      }
      }< ;/code>;
      e em:
      CAMINHO_PARA_ESTA_PASTA/views/scripts/formulario.phtml
      <form action="<?php echo $this->element->getAction() ?>"
      method="<?php echo $this->element->getMethod() ?>"
      id="<?php echo $this->element->getName() ?>"
      autocomplete="off">
      <div class="item">
      <div class="Field">Nome</div>
      <?=$this->element->nome;?>
      </div>
      </form>

      Creio que esta é a melhor forma de trabalhar com Zend_Form considerando o padrão MVC.
      Entretanto, vale ressaltar que algumas funcionalidades não estarão disponíveis, automaticamente, como é o caso de setDescription().
      Você terá que fazer algo assim:
      <div class="item">
      <div class="Field">Nome</div>
      <?=$this->element->nome;?>
      <br /><?=$this->element->nome->getDescription();?>
      </div>

      Bom, espero ter lhe ajudado.
      Abraço do Giba!

      1. Cara, segui a tua dica, e deu certo. Obrigado!…utilizei um arquivo de view, e chamei de forma separada os elementos. O único que não foi, era um objeto Zend_Form_Element_Hidden…então coloquei ele manualmente no arquivo da view, já que esse input não precisa necessariamente de validação…tem algum problema?

        1. Hum. Que bom que deu certo!
          Eu utilizo Elementos input hidden e consigo recuperar ele no arquivo view.
          Deve ter algo errado no seu código.
          Como você está criando o elemento Hidden?

          1. crio uma instancia da classe Zend_Form_Element_Hidden, adiciono ela no form, e depois,chamo individualmente através da view, da mesma forma que os outros elementos…mas só o hidden que não ta indo!

  2. Grande Giba,

    Apenas uma sugestão onde acredito ser útil para você.

    No último exemplo do código, onde você complementou um bônus para enviar e-mails, acredito que o mais adequado seria destinar quase todo o código disponível no contatoAction() para a classe “Application_Form_Contato”, pois se trata de uma regra de negócio, onde estes deveriam ser destinados em Model. Também visa aumentar a alta coesão da classe.

    Eu acho que deixar o código no controller ficaria muito mais bagunçado à medida que a aplicação crescer…

    Mas, mesmo assim, o artigo está de parabéns!

    Um abraço.

  3. Olá.. gostaria de saber como colocar os formularios nos modulos, ex.: no modulo default ter uma pasta form
    eu fiz dessa forma porem o zend não ta dando auto load deste formularios quando o uso em um controller deste modulo
    como posso fazer para que isso funcione corretamente..

    outra coisa, não querendo abusar, gostaria de fazer as validações e salvamento dos dados por ajax.. tem como vc me dar algumas dicas de qual caminho seguir..

    muito obrigado..
    um abraço

  4. Bom dia,

    com relação ao Zend_Form, gostaria de saber como consigo recuperar os erros do form e renderiza-los na view em forma de lista?

    Desde já agradeço…

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *