Zend\Form

Zend\Form
O Form é uma classe da Zend Framework 2 que nos permite trabalhar de maneira OO com formulários, ou seja, inserir outros objetos como campos e relacioná-lo com uma entidade e depois exibí-lo em uma view.
Criando um pequeno Form
Para criar o nosso primeiro form devemos inicialmente fazer com que nossa classe herde da classe Zend\Form. Após isso devemos ter em mente alguns métodos presentes na classe Form, como por exemplo, add(), onde passaremos nossos fields, como input, img e etc, ou conjunto de fields chamados de fieldSet.

 

/**
    * Add an element or fieldset
    *
    * If $elementOrFieldset is an array or Traversable, passes the argument on
    * to the composed factory to create the object before attaching it.
    *
    * $flags could contain metadata such as the alias under which to register
    * the element or fieldset, order in which to prioritize it, etc.
    *
    * @param  array|Traversable|ElementInterface $elementOrFieldset
    * @param  array $flags
   *@return \Zend\Form\Fieldset|\Zend\Form\FieldsetInterface|\Zend\Form\FormInterface
*/
   $form->add($elementOrFieldset, array $flags = array())
Outro método importante é o setAttribute(), onde passaremos atributos da tag form, tais como method, id e outros.
/**
    * Set a single element attribute
    *
    * @param  string $key
    * @param  mixed  $value
    * @return Element|ElementInterface
*/
$form->setAttribute($key, $value);
Segue abaixo um exemplo de um form que faz uso desses métodos.
namespace Application\Form;
use Zend\Form;
class MyForm extends Form {
      function __contruct() {
          $this->setAttribute(‘method’, ‘post’);
          $this->setAttribute(‘id’, ‘my-form’);
          $this->add(
           array(
               ‘name’ => ‘sex’,
               ‘type’ => ‘Zend\Form\Element\Select’,
               ‘options’ => array(
                   ‘label’ => ‘Sex:’,
                   “value_options” => array(
                                                 “” => “- Choose your sex -“,
                                                 “0” => “Male”,
                                                 “1” => “Female”,
                                            ),
               ),
               ‘attributes’ => array(
                   ‘style’ => ‘width: 350px’
               )
           )
       );
       $this->add(
           array(
               ‘name’ => ‘name’,
               ‘options’ => array(
                   ‘label’ => ‘Name:’
               ),
               ‘attributes’ => array(
                   ‘class’ => ‘biggest’,
               )
           )
       );
       $this->add(
           array(
               ‘name’ => ‘btnsubmit’,
               ‘options’ => array(
                   ‘label’ => ‘Submit’
               ),
               ‘attributes’ => array(
                   ‘class’ => ‘btn’,
                   ‘type’ => ‘submit’
               )
           )
       );
     }
}
Exibindo o Form na View
Nosso pequeno formulário está pronto, agora podemos exibí-lo. Mas antes disso vamos instância-lo em um controller qualquer e enviá-lo para a view.
class ExampleController extends AbstractActionController
{
 public function indexAction() {
     $form = new Form\MyForm
     return array(‘form’ => $form);
 }
}
Agora na view o código fica dessa maneira:
      
               $form->prepare();
               echo $this->form()->openTag($form);
               echo $this->formRow($form->get(‘name’));
               echo $this->formRow($form->get(‘sex’));
      ?>

               formButton($form->get(‘btnsubmit’)); ?>
               form()->closeTag(); ?>
      
Primeiro ponto a ser visto é que estamos chamando o método prepare() do nosso form. O que esse método faze é dar certeza ao objeto que está tudo pronto para ser usado, como por exemplo, os filtros de validação, que veremos mais a frente, mensagens de erros e os próprios campos.
Após isso, temos o ViewHelper Form tendo seu método openTag() sendo chamado e passamos para ele nosso objeto $form. O resultado desse método é a tag sendo gerada com os atributos que criamos, como por exemplo, method=“post” e id=“my-form”.
Outro ViewHelper sendo chamado é o FormRow, responsável por exibir na tela corretamente em modo de linha todos os nossos fields. Para esse ViewHelper estamos passando cada campo de nosso formulário através do método get(nomeDoCampo) do objeto formulário, que será transformado em uma tag html pelo ViewHelper.
Um terceiro ViewHelper é o FormButton que age da mesma maneira do FormRow. E para concluir, temos o método closeTag() do ViewHelper form(), que, nada mais do que óbio, gera a tag html de fechamento de um form ().
Elemento CSRF
O elemento CSRF é um elemento de segurança que ao ser exibido, preferencialmente em modo “hidden”, gera um código e será enviado junto com os outros dados digitados pelo usuário quando houver submissão.
Ao verificarmos se os dados dentro do formulário estão válidos, haverá uma verificação desse código de segurança, e caso ele não exista ou seja diferente do esperado seu formulário não passará na validação.
Esse elemento impede que formulários falsos e maliciosos sejam criados e apontem seus posts para nossa aplicação, gerando assim inserções ou alterações sem segurança alguma. Com esse código, torna-se impossível ser aceito uma submissão que não seja do nosso próprio formulário.
Abaixo o nosso exemplo de formulário, mas agora com o elemento CSRF.
namespace Application\Form;
use Zend\Form;
class MyForm extends Form {
      function __contruct() {
          $this->setAttribute(‘method’, ‘post’);
          $this->setAttribute(‘id’, ‘my-form’);
          $this->add(
           array(
               ‘name’ => ‘sex’,
               ‘type’ => ‘Zend\Form\Element\Select’,
               ‘options’ => array(
                   ‘label’ => ‘Sex:’,
                   “value_options” => array(
                                                 “” => “- Choose your sex -“,
                                                 “0” => “Male”,
                                                 “1” => “Female”,
                                            ),
               ),
               ‘attributes’ => array(
                   ‘style’ => ‘width: 350px’
               )
           )
       );
       $this->add(
           array(
               ‘name’ => ‘name’,
               ‘options’ => array(
                   ‘label’ => ‘Name:’
               ),
               ‘attributes’ => array(
                   ‘class’ => ‘biggest’,
               )
           )
       );
       $this->add(
           array(
               ‘name’ => ‘btnsubmit’,
               ‘options’ => array(
                   ‘label’ => ‘Submit’
               ),
               ‘attributes’ => array(
                   ‘class’ => ‘btn’,
                   ‘type’ => ‘submit’
               )
           )
       );
       $this->add(
           array(
               ‘type’ => ‘Zend\Form\Element\Csrf’,
               ‘name’ => ‘security’,
           )
       );
     }
}
Para exibí-lo na view basta usarmos o ViewHelper FormHidden, que escreverá a tag do nosso elemento em um campo hidden, ou seja, de modo invisível aos usuários. Veja abaixo.
      
               $form->prepare();
               echo $this->form()->openTag($form);
               echo $this->formRow($form->get(‘name’));
               echo $this->formRow($form->get(‘sex’));
              echo $this->formHidden($form->get(‘security’));
      ?>

               formButton($form->get(‘btnsubmit’)); ?>
      
      form()->closeTag(); ?>
ValidationGroup
Porém, precisamos informar ao form que ele deve verificar o nosso campo security, ou seja, devemos colocá-lo no grupo de campos que serão validados pelo formulário. E sendo assim, temos o chamado ValidationGroup.
A classe form tem um método chamado setValidationGroup(array), que recerá um vetor contendo o nome dos campos que serão verificados quando fizermos $form->isValid(). Segue abaixo o exemplo.


namespace Application\Form;
use Zend\Form;
class MyForm extends Form {
      function __contruct() {
          $this->setAttribute(‘method’, ‘post’);
          $this->setAttribute(‘id’, ‘my-form’);
          //..Add fields with $this->add()
          $this->setValidationGroup(
              array(
                  ‘security’  
              )
          );
     }
}
Uma outra e importante informação é que campos que não forem informados no ValidationGroup não estarão no POST de um formulário. Por isso, quando pensar em Validation Group, pense em campos que serão validados e campos que deverão estar no POST de submissão.
InputFilter
E se quiséssemos fazer com que nossos campos sexo e nome sejam também validados pelo form? Se inserirmos ele no ValidationGroup, então será validado, mas o que será verificado se até agora não específicamos nada? A solução para essas questões vem do uso do InputFilter
Como serão as validações de cada campo, como por exemplo, tamanho do dado, se é obrigatório ou não e outros, devem ser reunidos em um InputFilter. E tudo começa com a ideia de nossa classe MyForm implementando a interface InputFilterAwareInterface.
Se isso ocorresse, a classe MyForm deveria implementar o método setInputFilter(InputFilterInterface $inputFilter) e um atributo que referencie o InputFilter, porém a classe Form já possui essa interface implementada, métodos e atributos existentes. Além disso, a classe Form possui segundo e próprio método para trabalharmos com InputFilter chamado setInputFilter(InputFilterInterface $inputFilter).
Um outro detalhe importante é que os InputFilters são criados à partir de uma factory de inputs chamado Zend\InputFilter\Factory. Essa factory possui um método chamado createInputFilter(array) onde passaremos um vetor com nossos filtros.


namespace Application\Form;
use Zend\Form;
class MyForm extends Form {
      function __contruct() {
          $this->setAttribute(‘method’, ‘post’);
          $this->setAttribute(‘id’, ‘my-form’);
          //..Add fields with $this->add()
          $this->setInputFilter(
              new Factory()->createInputFilter(
                  array(
                       ‘sex’ => array (
                            ‘required’ => true
                       ),
                       ‘name’ => array (
                            ‘allow_empty’ => false
                       ),
                  )
              )
          );
          $this->setValidationGroup(
              array(
                  ‘security’,
                  ‘sex’,
                  ‘name’,
              )
          );
     }
}
Após nosso InputFilter pronto, não podemos esquecer de inserir nossos campos no ValidationGroup, como fizemos. Assim, temos a combinação de validações em cada campo e os campos que deverão ser validados.
Repare que a biblioteca do framework já possui alguns validators e estamos utilizado-os em nosso InputFilter, como por exemplo, o required e allow_empty. Mas e se ocorresse de precisarmos de um tipo de filtro ou validação que não existe na biblioteca? Para isso podemos criar nossos próprios validators.
Custom Validator
Validators são classes que serão usadas para verificar se os valores contidos em cada campo estão de acordo com regras pré-estipuladas. A biblioteca do framework já possui alguns validators prontos para uso, mas as vezes é necessário implementarmos os nossos.
Um validator qualquer deve sempre herdar da classe \Zend\Validator\AbstractValidator e consequentemente implementar o método isValid($value). Esse método que será chamado pelo framework quando for verificar a validade do campo caso ele esteja no ValidationGroup e passando como parâmetro o valor que está no campo. Vamos ver um exemplo de um validator customizado.


namespace Application\Form\Validator
use \Zend\Validator\AbstractValidator
class MyValidator extends AbstractValidator {
    
   /**
    * Returns true if and only if $value meets the validation requirements
    *
    * If $value fails validation, then this method returns false, and
    * getMessages() will return an array of messages that explain why the
    * validation failed.
    *
    * @param  mixed $value
    * @return bool
    * @throws Exception\RuntimeException If validation of $value is impossible
    */
   public function isValid($value)
   {
       if (empty($value)) {
           return false;
       }
       return true;
   }
}
Mensagens de erro
Nosso validator verifica se o valor é falso, 0, null ou “”(vazio) através do método empty(), e caso seja, ele retornará falso e fará consequentemente com que o método isValid() do formulário retorne falso mesmo que outros validators tenha resultado em verdadeiro.
Os validators também permitem que você retorne um mensagem de erro, que por padrão aparecerá abaixo do campo e em cores vermelhas. Para que isso ocorra devemos primeiros criar as mensagens sobrescrevendo o atributo $messageTemplates passando um vetor contendo mensagens, que no nosso caso só será uma: “Este campo não pode ser vazio!”.
Criada nossa mensagem podemos executá-la quando quisermos através do método error() da classe AbstractValidator e passando como parâmetro a key do vetor referente a mensagem que gostariamos de exibir. Sendo assim ficaria assim a exibição de erros.
namespace Application\Form\Validator
use \Zend\Validator\AbstractValidator
class MyValidator extends AbstractValidator {
   const IS_EMPTY    = ‘isEmpty’;
   
  /**
   * @var array
   */
   protected $messageTemplates = array(
       self::IS_EMPTY            => “Este campo não pode ser vazio!”,
   );
   /**
    * Returns true if and only if $value meets the validation requirements
    *
    * If $value fails validation, then this method returns false, and
    * getMessages() will return an array of messages that explain why the
    * validation failed.
    *
    * @param  mixed $value
    * @return bool
    * @throws Exception\RuntimeException If validation of $value is impossible
    */
   public function isValid($value)
   {
       if (empty($value)) {
           $this->error(self::IS_EMPTY);
           return false;
       }
       return true;
   }
}
Criado nosso validator, podemos inserí-lo agora no InputFilter.
namespace Application\Form;
use Zend\Form;
class MyForm extends Form {
      function __contruct() {
          $this->setAttribute(‘method’, ‘post’);
          $this->setAttribute(‘id’, ‘my-form’);
          //..Add fields with $this->add()
          $myValidator = new Validator\MyValidator();
          $this->setInputFilter(
              new Factory()->createInputFilter(
                  array(
                       ‘sex’ => array (
                            ‘required’ => true,
                            ‘validators’ => array(
                                 $myValidator
                            )
                       ),
                       ‘name’ => array (
                            ‘allow_empty’ => false,
                            ‘validators’ => array(
                                 array(‘name’  =>  ‘Application\Validator\Form\MyValidator’)
                            )
                       ),
                  )
              )
          );
          $this->setValidationGroup(
              array(
                  ‘security’,
                  ‘sex’,
                  ‘name’,
              )
          );
     }
}


Veja que isso pode ser feito de duas maneira, ou diretamente, que é recomendado quando você tem um validator que exige algum tipo de parâmetro no construtor, ou por modo indireto, fica factory.
Criando e Validando o Form em um Controller
class ExampleController extends AbstractActionController
{
 public function indexAction() {
     $form = new Form\MyForm;
     $request = $this->getRequest();
     if($request->isPost()) {
         $form->setData($request->getPost());
         if($form->isValid()) {
              //…
         }
     }
     
     return array(‘form’ => $form);
 }
}
Perceba que caso o usuário esteja fazendo um POST, nos iremos pegar os valores que estão no POST e inserir no formulário através do método setData(), que espera como parâmetro um vetor de informações.
Com isso, nosso formulário está com seus campos preenchidos e prontos para serem validados pelo método isValid(), que irá capturar o InputFilter do formulário, passar para ele os valores que estão preenchendo os campos e verificar se estão corretos.
Note também que mesmo que não estejam validos, o usuário não precisará redigitar as informações nos campos, pois elas se manterão graças ao setData recebendo o POST.
setData()
O método para se popular um formulário com um vetor de valores é através do método setData(). Esse método relacionará as keys do vetor com nome dos campos e copiará os valores do vetor para os campos. Lembrando que o mesmo pode acontecer através do bind(), porém, não será com um vetor, mas com um objeto. Vamos ver um exemplo.


$form->setData(
    array(
        ‘name’ => ‘Tássio’
        ‘surname’ => ‘Auad’
    )
)
Quando exibirmos esse formulário em uma view, o campo name estará preenchido com o valor ‘Tássio’ e o campo surname, com o valor ‘Auad’.
isValid()
Tentando descrever o que basicamente acontece dentro do isValid() para facilitar a visão de formulários, pois tudo gira entorno desse método, vamos criar uma algoritmo.
Captura InputFilter da entidade. Caso não haja, captura o InputFilter do Form. Caso não haja, instancia um InputFilter.
Envia os dados do form para dentro do InputFilter
Envia o ValidationGroup para dentro do InputFilter
Executa o método isValid() do Input Filter
Se for válido, popula a entidade com os dados do form
Veja que é a mesma coisa que:
$inputFilter = $form->getInputFilter();
$inputFilter->setData($form->getData());
$inputFilter->setValidationGroup($form->getValidationGroup());
if($inputFilter->isValid()) {
         $object = new Entity\MyEntity();
         $hydrate = new Zend\Stdlib\Hydrator\ClassMethods(true);
         $hydrate->hydrate($row->getArrayCopy(), $objeto);
}
Ou:
$object = new Entity\MyEntity();
$inputFilter = $object>getInputFilter();
$inputFilter->setData($form->getData());
$inputFilter->setValidationGroup($form->getValidationGroup());
if($inputFilter->isValid()) {
         $hydrate = new Zend\Stdlib\Hydrator\ClassMethods(true);
         $hydrate->hydrate($row->getArrayCopy(), $objeto);
}

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s