Development

Documentation/pt_BR/forms_in_action/1.2/01-Validacao-de-Formulario (diff)

You must first sign up to be able to contribute.

Changes from Version 1 of Documentation/pt_BR/forms_in_action/1.2/01-Validacao-de-Formulario

Show
Ignore:
Author:
raphox (IP: 189.27.72.129)
Timestamp:
02/09/09 23:20:05 (9 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Documentation/pt_BR/forms_in_action/1.2/01-Validacao-de-Formulario

    v0 v1  
     1{{{ 
     2#!WikiMarkdown 
     3 
     4Capítulo 2 - Validação de formulários 
     5=========================== 
     6 
     7No capítulo 1 nos aprendemos como criar e exibir um formulário básico de contato. Neste capítulo iremos aprender como gerenciar validação de formulário. 
     8 
     9Antes de começarmos 
     10--------------- 
     11 
     12O formulário de contato no capítulo 1 não é completamente funcional ainda. O que acontece se um usuário submite um endereço de email inválido or se a mensagem que submetida for vazia? Neste caso, nos gostariamos de mostrar mensagens de erro para requer ao usuário a entrada correta, como mostar a Figura 2-1. 
     13 
     14Figura 2-1 - Exibindo mensagens de erro. 
     15 
     16![Displaying Error Messages](/images/forms_book/en/02_01.png "Displaying Error Messages") 
     17 
     18Aqui esta as regras de validação de implemento para o fomulário de contato: 
     19 
     20  * 'name'   : opcional 
     21  * 'email'  : obrigatório, o valor deve ser um endereço de email válido 
     22  * 'subject': obrigatório, o valor selecionado deve ser válido de uma lista de valores. 
     23  * `message`: obrigatório, o tamanho da mensagem deve conter no mínimo 4 caracteres. 
     24 
     25>**Note** 
     26>Porque nś precisamos validar o campo 'subject'? A tag `<select>` já esta limitando o usuário com valores pré-definidos. Uma parte dos usuários poem apenas uma das opções exibidas, mas outros valores podem ser submetdios utilizando ferramentas com o Firefox Developer Toolbar, ou através da simulação de um pedido com ferramentas como 'curl' ou 'wget'. 
     27 
     28Listagem 2-1 mostra a template que usamos no capítulo 1. 
     29 
     30Listagem 2-1 - A template do formulário 'Contact' 
     31 
     32    [php] 
     33    // apps/frontend/modules/contact/templates/indexSucces.php 
     34    <form action="<?php echo url_for('contact/index') ?>" method="POST"> 
     35      <table> 
     36        <?php echo $form ?> 
     37        <tr> 
     38          <td colspan="2"> 
     39            <input type="submit" /> 
     40          </td> 
     41        </tr> 
     42      </table> 
     43    </form> 
     44 
     45Figura 2-2 separa em partes a interação entre a aplicação e o usuário. O primeiro passo mostra o formulário ao usuário. Quando o usuário submete o formulário, no caso da entrada ser válida o usuário é redirecionado para a página de agradecimento, ou se a entrada incluir valores inválidos o formulário é mostrado novamente com mensagens de erros. 
     46 
     47Figura 2-2 - Interação entre a Aplicação e o Usuário 
     48 
     49![Interaction between the Application and the User](/images/forms_book/en/02_02.png "Interaction between the Application and the User") 
     50 
     51Validaddores 
     52---------- 
     53 
     54Um formulário Symfony é foramdo de campos. Cada campo po ser indenficado por um nomem único com nós oberservamos no capítulo 1. Nós conectamos um widget para cada campo na ordem de amostragem para o usuário, agora vamos ver como nós pode aplicar regras de validação para cada um dos campos. 
     55 
     56### A classe `sfValidatorBase` 
     57 
     58A validação de cada campo é feita por objetos herdados da classe 'sfValidatorBase'. Na ordem de validação do formulário de contato, nós devemos definir objetos de validação para cada um dos quatro campos: 'name', 'email', 'subjetc' e 'message'. Listagem 2-2 mostra a implementado destes validadores na classe do formulário utilizando o método 'setValidators()'. 
     59 
     60Listagem 2-2 - Adicionando validadores para classe 'ContactForm' 
     61 
     62    [php] 
     63    // lib/form/ContactForm.class.php 
     64    class ContactForm extends sfForm 
     65    { 
     66      protected static $subjects = array('Subject A', 'Subject B', 'Subject C'); 
     67       
     68      public function configure() 
     69      { 
     70        $this->setWidgets(array( 
     71          'name'    => new sfWidgetFormInput(), 
     72          'email'   => new sfWidgetFormInput(), 
     73          'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)), 
     74          'message' => new sfWidgetFormTextarea(), 
     75        )); 
     76        $this->widgetSchema->setNameFormat('contact[%s]'); 
     77 
     78        $this->setValidators(array( 
     79          'name'    => new sfValidatorString(array('required' => false)), 
     80          'email'   => new sfValidatorEmail(), 
     81          'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     82          'message' => new sfValidatorString(array('min_length' => 4)), 
     83        )); 
     84      } 
     85    } 
     86 
     87Nós utilizamos três validadores distintos: 
     88 
     89  * `sfValidatorString`: valida um string 
     90  * `sfValidatorEmail` : valida um email 
     91  * `sfValidatorChoice`: valida a valor de entrada vindo de uma lista pré-definida de opções 
     92 
     93Cada validador recebe uma lista de opções como primeior argumento. Como os widgets, alguns destas opções são obrigatórias, outras não. Por exemplo, o validador 'sfValidatorChoice' recebe uma opção obrigatória, 'choices' (escolhas). Cada validador pode também receber as opções 'required' (requerido) e 'trim' (preparo), defindos por padrão na classe 'sfValidaroBase': 
     94 
     95  | **Opção**  | **Valor Padrão** | **Descrição** 
     96  | ----------- | ----------------- | --------------- 
     97  | required    | `true`            | Especifica se o campo é obrigatório 
     98  | trim        | `false`           | Remove automáticamente espaços em branco no iníco e no final da string antes de ser feita a validação. 
     99 
     100Vamos ver as opções disponíveis para os validores que acabamos de utilizar. 
     101 
     102  | **Validador**     | **Opções obrigatórias** | **Opções opcionais** | 
     103  | ----------------- | --------------------- | -------------------- | 
     104  | sfValidatorString |                       | `max_length`         | 
     105  |                   |                       | `min_length`         | 
     106  | sfValidatorEmail  |                       | `pattern`            | 
     107  | sfValidatorChoice | `choices`             |                      | 
     108 
     109Se você tentar submeter o formulário com valores inválidos, você não ver nenhuma mudança no comportamento. Nós devemos atualizar o modulo 'contact' para validar os valores submetidos, como mostra a listagem 2-3. 
     110 
     111Listagem 2-3 - Implementado Validação no Modulo 'contact' 
     112 
     113    [php] 
     114    class contactActions extends sfActions 
     115    { 
     116      public function executeIndex($request) 
     117      { 
     118        $this->form = new ContactForm(); 
     119 
     120        if ($request->isMethod('post')) 
     121        { 
     122          $this->form->bind($request->getParameter('contact')); 
     123          if ($this->form->isValid()) 
     124          { 
     125            $this->redirect('contact/thankyou?'.http_build_query($this->form->getValues())); 
     126          } 
     127        } 
     128      } 
     129 
     130      public function executeThankyou() 
     131      { 
     132      } 
     133    } 
     134 
     135A listagem 2-3 introduz você a muitos novos conceitos: 
     136 
     137  * No caso da requisição 'GET', o formulário é inicializado e passado à template para ser excibido ao usuário. O formulário esta entaão em um **estado inicial**: 
     138 
     139        [php] 
     140        $this->form = new ContactForm(); 
     141 
     142  * Quando o usuário submete o formulário com uma requisição 'POST', o method 'bind()' junta o formulário com os dados de entrada do usuário e dispara o mecanismod de validação. O formulário então muda para um **estado de 'bound' (intermediário)** 
     143 
     144        [php] 
     145        if ($request->isMethod('post')) 
     146        { 
     147          $this->form->bind($request->getParameter('contact')); 
     148 
     149  * Uma fez o formulário em estado intermediário, é possível checar a validade utilizando o método 'isValid()': 
     150 
     151      * Se o retorn for 'true':, o formulário é valido e o usuário pode ser redirecionado para página de agradecimentos. 
     152 
     153            [php] 
     154            if ($this->form->isValid()) 
     155            { 
     156              $this->redirect('contact/thankyou?'.http_build_query($this->form->getValues())); 
     157            } 
     158 
     159      * Se não, a template 'indexSuccess' é exibida como inicialmente. O processo de validação adiciona as mensagens de erro dentro do formulário para ser exibida para o usuário. 
     160 
     161>**Note** 
     162>Quando um formulário está em um estado inicial, o método 'isValid()' sempres retorna 'false' e o método 'getValues()' sempre retornará um array vazio. 
     163 
     164A Figura 2-3 mostra o código que é executado durante a interação entre a aplicação e o usuário. 
     165 
     166Figura 2-3 - Código executado durante a interação entre a aplicacao e o usuário 
     167 
     168![Code executed during the Interaction between the Application and the User](/images/forms_book/en/02_03.png "Code executed during the Interaction between the Application and the User") 
     169 
     170### O propósito dos validadores 
     171 
     172Possívelmente você notou que durante o redirecionamento para a página de agradecimento, nos não estamos utilizando '$request->getParameter('contact')' mas '$this->form->getValues()'. De fato, `$request->getParameter('contact')` retorna os dados do usuário enquanto `$this->form->getValues()` retorna os dados validados. 
     173 
     174Se o formulário é valido, porquê razão aquelas duas declarações não podem ser idênticas? Cada validador verdadeiramente tem duas tarefas: um **validadtion task**, mas também um **cleaning task** (validar e limpar). O método 'getValues()' é, de fato, a devolução dos dados validados e limpos. 
     175 
     176O processo de limpeza tem duas principais ações: **normalização** and **conversão** dos dados de entrada. 
     177 
     178Nos já vimos um caso de normalização com a opção 'trim'. Mas a ação de normalização é muito mais importante para um campo de data por exemplo. O `sfValidatorDate` valida uma data. Este validador recebe muitos formatos de entrada (um timestam, um formato baseado em expressão regular, ...) Ao em vez de simplismente devolver o valor de entrada, ele converte para um formato padrão na forma de 'Y-m-d H:i:s'. Por esta razão, o desenvolvedor está garantido de receber formatos stáveis, apesar da qualidade do formato de entrada. O sistema oferece muita flexibilidade para o usuário, and assegura consistencia para o desenvolvedor. 
     179 
     180Agora considere uma ação de conversão, como um upload de arquivo. Uma validação de arquivo pode ser feita utilizando o 'sfValidaorFile'. Uma vez o arquivo carregado, em vez de retornar o nome do arquivo, o validador retorna um objeto 'sfVAlidatedFile', tornando mais fácil lidar com as informações do arquivo. Nós veremos depois neste capítulo com utilizar este validador. 
     181 
     182>**Tip** 
     183>O método `getValues()` retor um array com todos os dados validados e limpos. Mas como as vezes é útil recuperar apenas um valor, há também method 'getValue()': $email = $this->form->getValue('email'). 
     184 
     185### Formulário inválido 
     186 
     187Toda vez que há um campo inválido no formulário, o template 'indexSucess' é exibido. Figura 2-4 mostra o que nós recebemos quando nós enviamos um formulário com dados inválidos. 
     188 
     189Figura 2-4 - Formulário inválido 
     190 
     191![Invalid Form](/images/forms_book/en/02_04.png "Invalid Form") 
     192 
     193A chamada para declaração '<?php echo $form ?>' leva automicamente em consideração as mensagens de erros associados ao campos, e preencherá automáticamento os dados limpos da entrada do usuário. 
     194 
     195Quando um formulário está vinculado a dados externos através do method 'bind()', o formulário muda para um estado intermediário e as seguintes ações são desparadas: 
     196 
     197  * O processo de validação é executado 
     198 
     199  * As mensagens de erros são armazenadas no formulário em ordem para serem apresentadas para a template 
     200 
     201  * Os valores padrões do formulário são substituidos pelos dados limpos do usuário 
     202 
     203As informações necessários para apresentar as mensagens de erro ou os dados do usuário, são facilmente acessadas utilizando a variável 'form' na template. 
     204 
     205>**Atenção** 
     206>Com vimos no capítulo 1, nós podemos passar valores padrões para o constructro da classe do form. Após a submissão dum formulário inválido, estes valores padrões são substituidos pelos valores submetidos, de formar que o usuário possa corrigir os seus errors. Então, nunca utilize os dados de entrada como um valor padrão como neste exemplo: '$this->setDefaults($request->getParameter('contact'))'.. 
     207 
     208Personalização de validadores 
     209----------------------- 
     210 
     211### Cusomizando mensagem de erros 
     212 
     213Como você deve ter notado na Figura 2-4, mensagens de erro não são muito úteis. Vamos ver como fazer então para ser mais intuitiva. 
     214 
     215Cada valida pode adicionar erros no formulário. Um erro consiste de um código e uma mensagem. Todo validador tem pelo menos o 'required' (requerido) e 'invalid' (inválido) erros definidos no `sfValidatorBase`: 
     216 
     217  | **Código**     | **Mensagem**     | **Descrição** 
     218  | ------------ | --------------- | --------------- 
     219  | required     | `Required.`     | o campo é obrigatório e o valor é vazio 
     220  | invalid      | `Invalid.`      | O campo é inválido 
     221 
     222Aqui estão os códigos de erros associados aos validadores já utilizados: 
     223 
     224  | **Validador**     | **Código do erro** | 
     225  | ----------------- | --------------- | 
     226  | sfValidatorString | `max_length`    | 
     227  |                   | `min_length`    | 
     228  | sfValidatorEmail  |                 | 
     229  | sfValidatorChoice |                 | 
     230 
     231Customizing error messages can be done by passing a second argument when creating the validation objects. A Listagem 2-4 customiza várias menssagens de erro e a Figura 2-5 mostra menssagens de erro customizadas em ação. 
     232 
     233Lsitagem 2-4 - Customizando mensagens de erro 
     234 
     235    [php] 
     236    class ContactForm extends sfForm 
     237    { 
     238      protected static $subjects = array('Subject A', 'Subject B', 'Subject C'); 
     239       
     240      public function configure() 
     241      { 
     242        // ... 
     243 
     244        $this->setValidators(array( 
     245          'name'    => new sfValidatorString(array('required' => false)), 
     246          'email'   => new sfValidatorEmail(array(), array('invalid' => 'The email address is invalid.')), 
     247          'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     248          'message' => new sfValidatorString(array('min_length' => 4), array('required' => 'The message field is required.')), 
     249        )); 
     250      } 
     251    } 
     252 
     253Figura 2-5 - Mensagens de erro customizadas 
     254 
     255![Customized Error Messages](/images/forms_book/en/02_05.png "Customized Error Messages") 
     256 
     257A Figura 2-6 mostra a mensagem de erro que você recebe se tentar submeter uma mensagem muito curta (nos atribuimos o minímo de 4 caracteres). 
     258 
     259Figura 2-6 - Mensagem de erro para string muito curta 
     260 
     261![Too short Message Error](/images/forms_book/en/02_06.png "Too short Message Error") 
     262 
     263A mensagem de erro padrão associada a este código ('min_lenght') é diferente da mensagem que nos já vimos antes, uma vez implementado dois valores dinâmicos: o usuário insere o valor ('foo') e o minímo de caracteres permitidos para esse campo é ('4'). A Listagem 2-5 customiza esta mensagem utilizando estes valores dinâmicos e a Figura 2-7 mostra o resultado. 
     264 
     265Listagem 2-5 - Custommizando a mensagem de erro com valores dinâmicos 
     266 
     267    [php] 
     268    class ContactForm extends sfForm 
     269    { 
     270      public function configure() 
     271      { 
     272        // ... 
     273 
     274        $this->setValidators(array( 
     275          'name'    => new sfValidatorString(array('required' => false)), 
     276          'email'   => new sfValidatorEmail(array(), array('invalid' => 'Email address is invalid.')), 
     277          'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     278          'message' => new sfValidatorString(array('min_length' => 4), array( 
     279            'required'   => 'The message field is required', 
     280            'min_length' => 'The message "%value%" is too short. It must be of %min_length% characters at least.', 
     281          )), 
     282        )); 
     283      } 
     284    } 
     285 
     286Figura 2-7 - Customizando mensagens de erro com valores dinâmicos 
     287 
     288![Customized Error Messages with Dynamic Values](/images/forms_book/en/02_07.png "Customized Error Messages with Dynamic Values") 
     289 
     290Cada mensagem de erro pode utilizar valores dinâmicos, juntando o nome do valor com o caracter porcentagem (`%`). Os valores acessíveis são geralmente dados de entrada do usuário e valores da opção do validator relacionados ao erro. 
     291 
     292>**Tip** 
     293>Se você quer recaptular todos os código de erros, options, and mensagens padrão de um validador, por favor recorra a documentação da API online ([http://www.symfony-project.org/api/1_2/](http://www.symfony-project.org/api/1_2/)). Cada código, optição e mensagem de erro esta detalhado lá, junto com seus valores padrão (por exmeplo, o validador sfValidatorString` API esta disponível em [http://www.symfony-project.org/api/1_1/sfValidatorString](http://www.symfony-project.org/api/1_1/sfValidatorString)). 
     294 
     295Validaores de segurança 
     296------------------- 
     297 
     298Por padrão, um formulário é valido apenas se todos os campos submetido pelo usuário tiver um validador. Isto garante que cada campo tenha um regra de validação e que não seja possível injetar valores para campos que não estejão definidos no formulário.  
     299 
     300Para ajudar a entender esta regra de segura, vamos considerar um objeto usuário com mostra a Listagem 2-6. 
     301 
     302Listagem 2-6 - A classe 'User' 
     303 
     304    [php] 
     305    class User 
     306    { 
     307      protected 
     308        $name = '', 
     309        $is_admin = false; 
     310 
     311      public function setFields($fields) 
     312      { 
     313        if (isset($fields['name'])) 
     314        { 
     315          $this->name = $fields['name']; 
     316        } 
     317 
     318        if (isset($fields['is_admin'])) 
     319        { 
     320          $this->is_admin = $fields['is_admin']; 
     321        } 
     322      } 
     323 
     324      // ... 
     325    } 
     326 
     327Um objeto `User` é composto por duas propriedades, a nome de usuário ('name'), e a booleana que armazera o status administrador ('is_admin'). O método `setFields()` atualiza ambas propriédades. A Listagem 2-7 mostra o fromulário relaciona a classe 'User', possibilitando o usuário modificar a propriedade 'name' apenas. 
     328 
     329Listagem 2-7 - Formulário `User` 
     330 
     331    [php] 
     332    class UserForm extends sfForm 
     333    { 
     334      public function configure() 
     335      { 
     336        $this->setWidgets(array('name' => new sfWidgetFormInputString())); 
     337        $this->widgetSchema->setNameFormat('user[%s]'); 
     338 
     339        $this->setValidators(array('name' => new sfValidatorString())); 
     340      } 
     341    } 
     342 
     343A Listagem 2-8 mostra uma implementação do modulo 'user' utilizando o formulário previamente definido premitindo o usuário modificar o campo nome. 
     344 
     345Listagem 2-8 - Implementação do Modulo `user` 
     346 
     347    [php] 
     348    class userActions extends sfActions 
     349    { 
     350      public function executeIndex($request) 
     351      { 
     352        $this->form = new UserForm(); 
     353 
     354        if ($request->isMethod('post')) 
     355        { 
     356          $this->form->bind($request->getParameter('user')); 
     357          if ($this->form->isValid()) 
     358          { 
     359            $user = // retrieving the current user 
     360 
     361            $user->setFields($this->form->getValues()); 
     362 
     363            $this->redirect('...'); 
     364          } 
     365        } 
     366      } 
     367    } 
     368 
     369Sem nenhum proteção, se o usuário submeter um formulário com um valor para o campo 'name', e também para o 'is_admin', então nosso código esta vunerável. Isto é facilmente efetuado utilizando uma ferrament como Firebug. De fato, o valor 'is_admin' é sempre válido, por que o campo não tem nenhum validador associado a ele no formulário. Seja qual for o valor, o método 'setFields()' atualizará não apenas a propriedade 'name', mas também a propriedade 'is_admin'. 
     370 
     371se você testar este código passando um valor para ambos campos 'name' e 'is_admin', você receberá um mensagem de erro global "Extra field name" (Nome de campo extra), como mostrado na figura 2-8. O sistem gerou um erro porque alguns campos submetidos não tinha qualquer validador associado a si próprios; o campo 'is_admin' não foi definido no formulário 'UserForm'. 
     372 
     373Figura 2-8 - Erro Validor Faltando 
     374 
     375![Missing Validator Error](/images/forms_book/en/02_08.png "Missing Validator Error") 
     376 
     377Todos os validadores que vimos ate agora geram errors associados a campos. De onde vem este error global? Quando nos usamos o método 'setValidators()', o Symfony cria um objeto 'sfValidatorSchema'. O `sfValidatorSchema` define uma coleção de validadores. A chamada para `setValidators()` é equivalente ao seguinte código: 
     378 
     379    [php] 
     380    $this->setValidatorSchema(new sfValidatorSchema(array( 
     381      'email'   => new sfValidatorEmail(), 
     382      'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     383      'message' => new sfValidatorString(array('min_length' => 4)), 
     384    ))); 
     385 
     386O `sfValidatorSchema` tem duas regras de validação ativadas por padrão para proteger a coleção de validadores. Estas regras podem ser configuras com as opções `allow_extra_fields` e `filter_extra_fields`. 
     387 
     388A opção `allow_extra_fields`, que é definida como 'false' por padrão, verifica que cada dado de entrada tem um validador. Se não, um erro global "Extra field name." é gerado, como mostrado o exemplo anterior. Ao desenvolver, isto permite que os desenvolvedores sejam alertado se esquecer de expedificar a validação de um campo. 
     389 
     390Vamos voltar para o formulário de contato. Vamos trocar a regra de validação, trocando o campo 'name' por um campo obrigatório. Uma vez que o valor da opção 'require' é 'true', poderiamos mudar o validor do campo 'name' para:  
     391 
     392    [php] 
     393    $nameValidator = new sfValidatorString(); 
     394 
     395Este validador não tem impacto, uma vez que não tem a opção 'min_length' nem a 'max_lenght'. Neste caso, poderiamos também substituií-lo por um validador 'empty': 
     396 
     397    [php] 
     398    $nameValidator = new sfValidatorPass(); 
     399 
     400Em vez que definir um validdor 'empty', poderiamos nos livra dele, mas a proteção padrão que vimos anteriormente nos empede de nos livrarmos dele. A listagem 2-9 mostra como desabilitar a proteção utilizando a opção 'allow_extra_fields'. 
     401 
     402Listagem 2-9 - Desabilitando a protção `allow_extra_fields` 
     403 
     404    [php] 
     405    class ContactForm extends sfForm 
     406    { 
     407      public function configure() 
     408      { 
     409        // ... 
     410 
     411        $this->setValidators(array( 
     412          'email'   => new sfValidatorEmail(), 
     413          'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     414          'message' => new sfValidatorString(array('min_length' => 4)), 
     415        )); 
     416 
     417        $this->validatorSchema->setOption('allow_extra_fields', true); 
     418      } 
     419    } 
     420 
     421Voce agora deve ser capaz de validar o formulário como mostra a Figura 2-9. 
     422 
     423Figra 2-9 - Validatando com `allow_extra_fields` atribuida com `true` 
     424 
     425![Validating with `allow_extra_fields` set to `true`](/images/forms_book/en/02_09.png "Validating with `allow_extra_fields` set to `true`") 
     426 
     427Se você tiver um olhar mais atento, você irá notar que, mesmo se o formulário for válido, o valor do campo `name` está vazio na página de agradecimento, apesar de qualquer valor que foi apresentado. De fato, o valor ainda não foi atribuido ao array  reenviado pelo '$this->fomr->getValues()'. Desabilitando a opção `allow_extra_fields`, vamos nos livrar do erro devido a falta do validaor, mas a opção `filter_extra_fields`, a qual esta atribuida como `true` por padrão, filtra esses valores, retirando-os dos valores validados. Claro que é possível alterar este comportamento, como mostrado na Listagem 2-10. 
     428 
     429Listagem 2-10 - Desabilitando a proteção `filter_extra_fields` 
     430 
     431    [php] 
     432    class ContactForm extends sfForm 
     433    { 
     434      public function configure() 
     435      { 
     436        // ... 
     437 
     438        $this->setValidators(array( 
     439          'email'   => new sfValidatorEmail(), 
     440          'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     441          'message' => new sfValidatorString(array('min_length' => 4)), 
     442        )); 
     443 
     444        $this->validatorSchema->setOption('allow_extra_fields', true); 
     445        $this->validatorSchema->setOption('filter_extra_fields', false); 
     446      } 
     447    } 
     448 
     449Você agora de ser capaz de validar seu formulário e recuperar o valor de entrada na sua página de agradecimento. 
     450 
     451Veremos no capítulo 4 que esta proteção pode ser utilizada com seguranção em objetos serialiazdos do Propel vindo de valores de formulário. 
     452 
     453Validadores Lógicos 
     454------------------ 
     455 
     456Vários validadores podem ser definidos para apenas um campo utlizando validadores lógicos: 
     457 
     458  * `sfValidatorAnd`: Para ser válido, o campo tem de passar por todos os validadores 
     459   
     460  * `sfValidatorOr` : Para ser válido, o campo tem de passar por ao menos um validador 
     461 
     462O construtor de um operador lógico requer uma lista de validores como seu primeiro arqumento. A Listagem 2-11 utiliza o `sfValidatorAnd` para associar dois validores exigidos pelo campo 'name'. 
     463 
     464Listagem 2-11 - Utilizando o validor 'sfValidatorAnd' 
     465 
     466    [php] 
     467    class ContactForm extends sfForm 
     468    { 
     469     public function configure() 
     470     { 
     471        // ... 
     472 
     473        $this->setValidators(array( 
     474          // ... 
     475          'name' => new sfValidatorAnd(array( 
     476            new sfValidatorString(array('min_length' => 5)), 
     477            new sfValidatorRegex(array('pattern' => '/[\w- ]+/')), 
     478          )), 
     479        )); 
     480      } 
     481    } 
     482 
     483Ao submeter o formulário, o valor de entrada do campo 'name' deve ter pelo menos 5 caracters **and** e corresponder com a empressão regular (`[\w- ]+`). 
     484 
     485Como validores lógicos são validores de si mesmos, eles podem ser combinados para definir avançadas expressões lógicas como mostrado na Listagem 2-12. 
     486 
     487Listagem 2-12 - Cobinando vários operadores lógicos 
     488 
     489    [php] 
     490    class ContactForm extends sfForm 
     491    { 
     492     public function configure() 
     493     { 
     494        // ... 
     495 
     496        $this->setValidators(array( 
     497          // ... 
     498          'name' => new sfValidatorOr(array( 
     499            new sfValidatorAnd(array( 
     500              new sfValidatorString(array('min_length' => 5)), 
     501              new sfValidatorRegex(array('pattern' => '/[\w- ]+/')), 
     502            )), 
     503            new sfValidatorEmail(), 
     504          )), 
     505        )); 
     506      } 
     507    } 
     508 
     509Validadores Globais 
     510----------------- 
     511 
     512Cada validador que vimos até agora são associados a um campo em espécifico e nos permite validar um valor por vez. Por padrão, eles se comportam ignorando outros dados apresentados pelo usário, mas as vezes a validação de um campo depende do contexto e depende de muitos outros valores do campo. Por exemplo, um validor global é necessário quando duas senha devem ser iguais, or quando uma data de início de ser anterior a data final. 
     513 
     514Em ambos os caso, nos precisamos utilizar validores globais pra validar os dados inseridos pelo usuário em seu contexto. Nós podemos inserir um validador global antes ou depois da validação do campo através da utilização de um pre-validator ou um post-validator respectivamente. Normalmente é melhor utilizar um post-validator, porque o valor já validada e limpar, ou seja, em formato normalizado. A Listagem 2-13 mostra como implementar a comparação de duas senha utilizando o validador `sfValidatorSchemaCompare`. 
     515 
     516Listagem 2-13 - Utilizando o Validador `sfValidatorSchemaCompare` 
     517 
     518    [php] 
     519    $this->validatorSchema->setPostValidator(new sfValidatorSchemaCompare('password', sfValidatorSchemaCompare::EQUAL, 'password_again')); 
     520 
     521A partir do Syfmony 1.2, você também pode utilizar operadores "natural" do PHP ao invez da constante de classe `sfValidatorSchemaCompare`. O exemplo anterior é equivalente a: 
     522 
     523    [php] 
     524    $this->validatorSchema->setPostValidator(new sfValidatorSchemaCompare('password', '==', 'password_again')); 
     525 
     526>**Tip** 
     527>A clasee `sfValidatorSchemaCompare` herdade do validador `sfValidatorSchema`, como todos os validadores globais. `sfValidatorSchema` é ela própria um validor global, uma vez que valida todos os dados insedos pelo usuário, passando para outros validadores a validação de cada campo. 
     528 
     529A Listagem 2-14 mostra como utilizar um simples validador para validarq que uma data inicial é antes de uma data final, customizando a mensagem de erro. 
     530 
     531Listagem 2-14 - Utilizando o validador `sfValidatorSchemaCompare` 
     532 
     533    [php] 
     534    $this->validatorSchema->setPostValidator( 
     535      new sfValidatorSchemaCompare('start_date', sfValidatorSchemaCompare::LESS_THAN_EQUAL, 'end_date', 
     536        array(), 
     537        array('invalid' => 'The start date ("%left_field%") must be before the end date ("%right_field%")') 
     538      ) 
     539    ); 
     540 
     541Utilizanod um post-validador grante que a comparação de duas datas serão precisas. Seja qual foi o formato de entrado, a validação dos campo 'start_date' e 'end_date' irá sempre ser convertido para valores em formato compátivel com (`Y-m-d H:i:s` por padrão). 
     542 
     543Por padrão, pre-validators and post-validators return erros globais para o formulário. Entretanto, alguns deles podem associar um erro para um campo específico. Por exemplo, a opção 'throw_global_error' do validador 'sfVAlidatorSchemaCompare' pode escolher entre um glogal error (Figura 2-10) ou um erro associado ao primeiro campo (Figure 2-11). A Listagem 2-15 mostra como utilizar a opção `throw_global_error`. 
     544 
     545Listagem 2-15 - Utilizando a opção `throw_global_error` 
     546 
     547    [php] 
     548    $this->validatorSchema->setPostValidator( 
     549      new sfValidatorSchemaCompare('start_date', sfValidatorSchemaCompare::LESS_THAN_EQUAL, 'end_date', 
     550        array('throw_global_error' => true), 
     551        array('invalid' => 'The start date ("%left_field%") must be before the end date ("%right_field%")') 
     552      ) 
     553    ); 
     554 
     555Figura 2-10 - Erro Global para um Validador Global 
     556 
     557![Global Error for a global Validator](/images/forms_book/en/02_10.png "Global Error for a Global Validator") 
     558 
     559Figura 2-11 - Erro Local para um Validador Global 
     560 
     561![Local Error for a global Validator](/images/forms_book/en/02_11.png "Local Error for a Global Validator") 
     562 
     563Finalmente, utilizando um validador lógico lhe permite combinar vários post-validators como mostra a Listagem 2-16. 
     564 
     565Listagem 2-16 - Combinando vários Post-Validators com um Validador lógico 
     566 
     567    [php] 
     568    $this->validatorSchema->setPostValidator(new sfValidatorAnd(array( 
     569      new sfValidatorSchemaCompare('start_date', sfValidatorSchemaCompare::LESS_THAN_EQUAL, 'end_date'), 
     570      new sfValidatorSchemaCompare('password', sfValidatorSchemaCompare::EQUAL, 'password_again'), 
     571    ))); 
     572 
     573Upload de arquivo 
     574----------- 
     575 
     576Lidar com upload de arquivo, como em todas as linguagens orientadas da web, envolve manipulão de código HTML e no lado do servidor recuperação de arquivo. Nesta seção veremos as ferramente de formulário que o framework tem a oferecer para tornar sua vida mais fácil. Nós veremos também como não cair em armadilhas comuns. 
     577 
     578Vamos mudar o formulário de contado para permitiar anexar um arquivo a mensagem a ser enviada. Para fazer isto, iremos adicionar um campo 'file' como mostrado na Listagem 2-17. 
     579 
     580Listagem 2-17 - Adiconando um Campo 'file' no formulario 'ContactForm' 
     581 
     582    [php] 
     583    // lib/form/ContactForm.class.php 
     584    class ContactForm extends sfForm 
     585    { 
     586      protected static $subjects = array('Subject A', 'Subject B', 'Subject C'); 
     587 
     588      public function configure() 
     589      { 
     590        $this->setWidgets(array( 
     591          'name'    => new sfWidgetFormInput(), 
     592          'email'   => new sfWidgetFormInput(), 
     593          'subject' => new sfWidgetFormSelect(array('choices' => self::$subjects)), 
     594          'message' => new sfWidgetFormTextarea(), 
     595          'file'    => new sfWidgetFormInputFile(), 
     596        )); 
     597        $this->widgetSchema->setNameFormat('contact[%s]'); 
     598 
     599        $this->setValidators(array( 
     600          'name'    => new sfValidatorString(array('required' => false)), 
     601          'email'   => new sfValidatorEmail(), 
     602          'subject' => new sfValidatorChoice(array('choices' => array_keys(self::$subjects))), 
     603          'message' => new sfValidatorString(array('min_length' => 4)), 
     604          'file'    => new sfValidatorFile(), 
     605        )); 
     606      } 
     607    } 
     608 
     609Quando há um widget sfWidgetFormInputFile` em um formulário que permite o upload de um arquivo, precisamos também adicionar um attributo 'enctype' ao formulário como é mostrado na Listagem 2-18. 
     610 
     611Listagem 2-18 - Modificando a template para ter o campo 'file' em seu contexto. 
     612 
     613    [php] 
     614    <form action="<?php echo url_for('contact/index') ?>" method="POST" enctype="multipart/form-data"> 
     615      <table> 
     616        <?php echo $form ?> 
     617        <tr> 
     618          <td colspan="2"> 
     619            <input type="submit" /> 
     620          </td> 
     621        </tr> 
     622      </table> 
     623    </form> 
     624 
     625>**Note** 
     626>Se você gerar dinâmicamente a template associado ao formulário, o método 'isMultipart()' do objeto do formulário returnará 'true', é necessário do atributo 'enctype'. 
     627 
     628Informação sobre arquivos carregados não são armazenadas com aos demais valores submetidos no PHP. Em seguida é necessário modificar a chamado do metodo 'bind()' para passar esta informação como um segundo arqumento, como mostrado na listagem 2-19. 
     629 
     630Listagem 2-19 - Passando arquivos carregados para o método 'bind()' 
     631 
     632    [php] 
     633    class contactActions extends sfActions 
     634    { 
     635      public function executeIndex($request) 
     636      { 
     637        $this->form = new ContactForm(); 
     638 
     639        if ($request->isMethod('post')) 
     640        { 
     641          $this->form->bind($request->getParameter('contact'), $request->getFiles('contact')); 
     642          if ($this->form->isValid()) 
     643          { 
     644            $values = $this->form->getValues(); 
     645            // do something with the values 
     646 
     647            // ... 
     648          } 
     649        } 
     650      } 
     651 
     652      public function executeThankyou() 
     653      { 
     654      } 
     655    } 
     656 
     657Agora que o formulário esta completamente funcional, ainda precisamos alterar a ação para armazer o arquivo carregado em disco. Como observamos no começo deste arquivo, o 'sfVAlidadorFile' converte as informações relacionadas de um arquivo carregado para um objeto 'sfValidatedFile'. A Listagem 2-20 mostra como lidar com esse objeto para armazer o arquivo no diretório 'web/uploads'. 
     658 
     659Listagem 2-20 - Utilizando o objeto `sfValidatedFile` 
     660 
     661    [php] 
     662    if ($this->form->isValid()) 
     663    { 
     664      $file = $this->form->getValue('file'); 
     665 
     666      $filename = 'uploaded_'.sha1($file->getOriginalName()); 
     667      $extension = $file->getExtension($file->getOriginalExtension()); 
     668      $file->save(sfConfig::get('sf_upload_dir').'/'.$filename.$extension); 
     669 
     670      // ... 
     671    } 
     672 
     673A table a seguir lista todos os methdos do objeto 'sfVAlidatedFile': 
     674 
     675  | **Método**             | **Descrição** 
     676  | ---------------------- | --------------- 
     677  | save()                 | Sava o arquivo carregado 
     678  | isSaved()              | Retorna 'true' se o arquivo foi salvo 
     679  | getSavedName()         | Retorno o nome do arquivo salvo 
     680  | getExtension()         | Return a extensão do arquivo, de acordo com o mime type 
     681  | getOriginalName()      | Retorno o nome do arquivo carregado 
     682  | getOriginalExtension() | Retorna a extensão do nome do arquivo carregado  
     683  | getTempName()          | Retorna o caminho do arquivo temporário 
     684  | getType()              | Retorna o mime type do arquivo 
     685  | getSize()              | Retorna o tamanho do arquivo 
     686 
     687>**Tip** 
     688>O mime type fornecido pelo navegador durante o carregamento do arquivo não é confiável. A fim de garantir uma máxima segurança, as funções 'finfo_open' and 'mime_content_type' e a ferramenta 'file' é utilizada durante a validação do arquivo. Como último recuros, se qualquer função não consiguir advinhar o mime type, ou se o sistema não prevê-lo, o browser mime type é é tida como valor. Para adicionar or alterar a função que advinha o mime type, basta passar a opção 'mime_type_guessers' para o construtor 'sfVAlidatorFile'. 
     689 
     690}}}