Formulários Usados Sozinhos
Os Nette Forms facilitam muito a criação e o processamento de formulários web. Pode usá-los nas suas aplicações de forma totalmente independente do restante do framework, como mostraremos neste capítulo.
No entanto, se usa Nette Application e presenters, o guia para uso em presenters é para si.
Primeiro formulário
Vamos tentar escrever um formulário de registo simples. O código será o seguinte (código completo):
Podemos renderizá-lo facilmente:
e no navegador ele será exibido assim:

O formulário é um objeto da classe Nette\Forms\Form
(a classe Nette\Application\UI\Form
é usada
em presenters). Adicionamos a ele os chamados controlos nome, senha e um botão de envio.
E agora vamos dar vida ao formulário. Perguntando $form->isSuccess()
, descobrimos se o formulário foi
enviado e se foi preenchido de forma válida. Se sim, exibimos os dados. Após a definição do formulário, adicionamos:
O método getValues()
retorna os dados enviados na forma de um objeto ArrayHash. Mostraremos como alterar isso mais tarde. O objeto $data
contém as chaves name
e
password
com os dados que o utilizador preencheu.
Normalmente, enviamos os dados diretamente para processamento posterior, que pode ser, por exemplo, inserção no banco de
dados. No entanto, durante o processamento, pode ocorrer um erro, por exemplo, o nome de utilizador já está em uso. Nesse
caso, passamos o erro de volta para o formulário usando addError()
e o deixamos renderizar novamente, junto com a
mensagem de erro.
Após processar o formulário, redirecionamos para a próxima página. Isso evita o reenvio indesejado do formulário pelo botão atualizar, voltar ou movendo-se no histórico do navegador.
O formulário é enviado por padrão pelo método POST para a mesma página. Ambos podem ser alterados:
E isso é basicamente tudo :-) Temos um formulário funcional e perfeitamente seguro.
Tente adicionar também outros controlos de formulário.
Acesso aos controlos
Chamamos o formulário e os seus controlos individuais de componentes. Eles formam uma árvore de componentes, onde a raiz é o formulário. Podemos aceder aos controlos individuais do formulário desta forma:
Os controlos são removidos usando unset:
Regras de validação
A palavra válido foi mencionada, mas o formulário ainda não possui regras de validação. Vamos corrigir isso.
O nome será obrigatório, então marcamo-lo com o método setRequired()
, cujo argumento é o texto da mensagem
de erro que será exibida se o utilizador não preencher o nome. Se o argumento não for fornecido, a mensagem de erro padrão
será usada.
Tente enviar o formulário sem preencher o nome e verá que uma mensagem de erro será exibida e o navegador ou servidor o rejeitará até que preencha o campo.
Ao mesmo tempo, não enganará o sistema digitando, por exemplo, apenas espaços no campo. De jeito nenhum. Nette remove automaticamente os espaços à esquerda e à direita. Experimente. É algo que deveria sempre fazer com cada input de linha única, mas muitas vezes é esquecido. Nette faz isso automaticamente. (Pode tentar enganar o formulário e enviar uma string de várias linhas como nome. Mesmo aqui, Nette não se deixa enganar e transforma as quebras de linha em espaços.)
O formulário é sempre validado no lado do servidor, mas também é gerada uma validação JavaScript, que ocorre
instantaneamente e o utilizador é informado sobre o erro imediatamente, sem a necessidade de enviar o formulário ao servidor.
Isso é feito pelo script netteForms.js
. Insira-o na página:
Se olhar o código-fonte da página com o formulário, poderá notar que Nette insere os controlos obrigatórios em elementos
com a classe CSS required
. Tente adicionar a seguinte folha de estilo ao template e o rótulo „Nome“ ficará
vermelho. Desta forma, marcamos elegantemente os controlos obrigatórios para os utilizadores:
Adicionamos outras regras de validação com o método addRule()
. O primeiro parâmetro é a regra, o segundo
é novamente o texto da mensagem de erro e pode haver ainda um argumento da regra de validação. O que isso significa?
Vamos estender o formulário com um novo campo opcional „idade“, que deve ser um número inteiro
(addInteger()
) e, além disso, dentro de um intervalo permitido ($form::Range
). E aqui usaremos
o terceiro parâmetro do método addRule()
, pelo qual passamos o intervalo desejado ao validador como um par
[de, até]
:
Se o utilizador não preencher o campo, as regras de validação não serão verificadas, pois o controlo é opcional.
Aqui surge espaço para uma pequena refatoração. Na mensagem de erro e no terceiro parâmetro, os números são listados em
duplicidade, o que não é ideal. Se estivéssemos a criar formulários multilíngues e
a mensagem contendo números fosse traduzida para vários idiomas, uma eventual alteração dos valores seria dificultada. Por
esse motivo, é possível usar os placeholders %d
e Nette preencherá os valores:
Voltemos ao controlo password
, que também tornaremos obrigatório e ainda verificaremos o comprimento mínimo da
senha ($form::MinLength
), novamente usando o placeholder:
Adicionamos ao formulário também o campo passwordVerify
, onde o utilizador digita a senha novamente, para
verificação. Usando regras de validação, verificamos se ambas as senhas são iguais ($form::Equal
). E como
parâmetro, damos uma referência à primeira senha usando colchetes:
Usando setOmitted()
, marcamos o controlo cujo valor realmente não nos importa e que existe apenas para fins de
validação. O valor não é passado para $data
.
Com isso, temos um formulário totalmente funcional com validação em PHP e JavaScript. As capacidades de validação de Nette são muito mais amplas, é possível criar condições, exibir e ocultar partes da página com base nelas, etc. Aprenderá tudo no capítulo sobre validação de formulários.
Valores padrão
Normalmente, definimos valores padrão para os controlos do formulário:
Muitas vezes, é útil definir valores padrão para todos os controlos simultaneamente. Por exemplo, quando o formulário é usado para editar registos. Lemos o registo do banco de dados e definimos os valores padrão:
Chame setDefaults()
após a definição dos controlos.
Renderização do formulário
Por padrão, o formulário é renderizado como uma tabela. Os controlos individuais cumprem a regra básica de
acessibilidade – todos os rótulos são escritos como <label>
e vinculados ao controlo de formulário
correspondente. Ao clicar no rótulo, o cursor aparece automaticamente no campo do formulário.
Podemos definir atributos HTML arbitrários para cada controlo. Por exemplo, adicionar um placeholder:
Existem realmente muitas maneiras de renderizar um formulário, então há um capítulo separado sobre renderização dedicado a isso.
Mapeamento para classes
Voltemos ao processamento dos dados do formulário. O método getValues()
retornou-nos os dados enviados como um
objeto ArrayHash
. Como é uma classe genérica, algo como stdClass
, sentiremos falta de certo conforto
ao trabalhar com ela, como sugestões de propriedades em editores ou análise estática de código. Isso poderia ser resolvido
tendo uma classe específica para cada formulário, cujas propriedades representam os controlos individuais. Por exemplo:
Alternativamente, pode usar o construtor:
As propriedades da classe de dados também podem ser enums e serão mapeadas automaticamente.
Como dizer ao Nette para nos retornar os dados como objetos desta classe? Mais fácil do que pensa. Basta fornecer o nome da classe ou o objeto a ser hidratado como parâmetro:
Também é possível fornecer 'array'
como parâmetro e, em seguida, os dados serão retornados como
um array.
Se os formulários formarem uma estrutura multinível composta por contêineres, crie uma classe separada para cada um:
O mapeamento então reconhece pelo tipo da propriedade $person
que deve mapear o contêiner para a classe
PersonFormData
. Se a propriedade contiver um array de contêineres, especifique o tipo array
e passe a
classe para mapeamento diretamente para o contêiner:
Pode gerar o design da classe de dados do formulário usando o método
Nette\Forms\Blueprint::dataClass($form)
, que o exibirá na página do navegador. Em seguida, basta clicar para
selecionar o código e copiá-lo para o projeto.
Múltiplos botões
Se o formulário tiver mais de um botão, geralmente precisamos distinguir qual deles foi pressionado. Essa informação é
retornada pelo método isSubmittedBy()
do botão:
Não pule a verificação $form->isSuccess()
, ela verifica a validade dos dados.
Quando o formulário é enviado pressionando a tecla Enter, é considerado como se tivesse sido enviado pelo primeiro botão.
Proteção contra vulnerabilidades
O Nette Framework dá grande ênfase à segurança e, portanto, cuida meticulosamente da boa segurança dos formulários.
Além de proteger os formulários contra ataques Cross Site Scripting (XSS) e Cross-Site Request Forgery (CSRF), ele realiza muitas pequenas medidas de segurança com as quais já não precisa de se preocupar.
Por exemplo, ele filtra todos os caracteres de controlo das entradas e verifica a validade da codificação UTF-8, para que os dados do formulário estejam sempre limpos. Para caixas de seleção e listas de rádio, ele verifica se os itens selecionados eram realmente das opções oferecidas e se não houve falsificação. Já mencionamos que, para entradas de texto de linha única, ele remove os caracteres de fim de linha que um invasor poderia ter enviado. Para entradas de várias linhas, ele normaliza os caracteres de fim de linha. E assim por diante.
Nette resolve para si riscos de segurança que muitos programadores nem sabem que existem.
O ataque CSRF mencionado consiste no facto de que o invasor atrai a vítima para uma página que, discretamente no navegador da vítima, executa uma requisição ao servidor no qual a vítima está logada, e o servidor acredita que a requisição foi executada pela vítima por sua própria vontade. Portanto, Nette impede o envio de formulários POST de outro domínio. Se, por algum motivo, quiser desativar a proteção e permitir o envio de formulários de outro domínio, use:
Esta proteção usa um cookie SameSite chamado _nss
. Portanto, crie o objeto do formulário antes de enviar a
primeira saída, para que o cookie possa ser enviado.
A proteção usando o cookie SameSite pode não ser 100% confiável, por isso é aconselhável ativar também a proteção por token:
Recomendamos proteger desta forma os formulários na parte administrativa do site, que alteram dados sensíveis na aplicação.
O framework defende-se contra o ataque CSRF gerando e verificando um token de autorização, que é armazenado na sessão.
Portanto, é necessário ter a sessão aberta antes de exibir o formulário. Na parte administrativa do site, a sessão
geralmente já está iniciada devido ao login do utilizador. Caso contrário, inicie a sessão com o método
Nette\Http\Session::start()
.
Então, passamos por uma rápida introdução aos formulários em Nette. Tente dar uma olhada no diretório examples na distribuição, onde encontrará mais inspiração.