Nette Documentation Preview

syntax
Validação de Formulários
************************


Controles requeridos .[#toc-required-controls]
==============================================

Os controles são marcados conforme necessário com o método `setRequired()`, cujo argumento é o texto da [mensagem de erro |#Error Messages] que será exibida caso o usuário não a preencha. Se nenhum argumento for apresentado, é usada a mensagem de erro padrão.

```php
$form->addText('name', 'Name:')
	->setRequired('Please fill your name.');
```


Regras .[#toc-rules]
====================

Acrescentamos regras de validação aos controles com o método `addRule()`. O primeiro parâmetro é a regra, o segundo é a [mensagem de erro |#Error Messages], e o terceiro é o argumento da regra de validação.

```php
$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password must be at least %d characters', 8);
```

**As regras de validação são verificadas somente se o usuário tiver preenchido o elemento.

O Nette vem com várias regras predefinidas cujos nomes são constantes da classe `Nette\Forms\Form`. Podemos aplicar essas regras a todos os elementos:

| constante | descrição | argumentos
|-------
| `Required` | alias de `setRequired()` | -
| `Filled` | alias de `setRequired()` | -
| `Blank` | não deve ser preenchido | -
| `Equal` | o valor é igual ao parâmetro | `mixed`
| `NotEqual` | o valor não é igual ao parâmetro | `mixed`
| `IsIn` | o valor é igual a algum elemento da matriz | `array`
| `IsNotIn` | valor não é igual a nenhum elemento da matriz | `array`
| `Valid` | validação dos passes de entrada (para [condições |#conditions]) | -


Entradas de texto
-----------------

Para os elementos `addText()`, `addPassword()`, `addTextArea()`, `addEmail()`, `addInteger()`, `addFloat()`, algumas das regras a seguir também podem ser aplicadas:

| `MinLength` | comprimento mínimo das cordas | `int`
| `MaxLength` | comprimento máximo das cordas | `int`
| `Length` | comprimento no alcance ou comprimento exato | par `[int, int]` ou `int`
| `Email` | endereço de e-mail válido | -
| `URL` | URL válida | -
| `Pattern` | corresponde ao padrão regular | `string`
| `PatternInsensitive` | como `Pattern`, mas não sensível a maiúsculas e minúsculas | `string`
| `Integer` | integer | -
| `Numeric` | alias de `Integer` | -
| `Float` | número inteiro ou de ponto flutuante | -
| `Min` | mínimo do valor inteiro | `int\|float`
| `Max` | máximo do valor inteiro | `int\|float`
| `Range` | valor na faixa | par `[int\|float, int\|float]`

As regras `Integer`, `Numeric` a `Float` convertem automaticamente o valor em inteiro (ou float, respectivamente). Além disso, a regra `URL` também aceita um endereço sem esquema (por exemplo `nette.org`) e completa o esquema (`https://nette.org`).
As expressões em `Pattern` e `PatternInsensitive` devem ser válidas para todo o valor, ou seja, como se estivesse embrulhado nos caracteres `^` and `$`.


Número de itens .[#toc-number-of-items]
---------------------------------------

Para os elementos `addMultiUpload()`, `addCheckboxList()`, `addMultiSelect()` você também pode usar as seguintes regras para limitar o número de itens selecionados ou arquivos carregados:

| `MinLength` | número mínimo | `int`
| `MaxLength` | número máximo | `int`
| `Length` | número no intervalo ou número exato | pares `[int, int]` ou `int`


Upload de arquivos
------------------

Para controles `addUpload()`, `addMultiUpload()` as seguintes regras também podem ser usadas:

| `MaxFileSize` | tamanho máximo do arquivo em bytes | `int`
| `MimeType` | tipo MIME, aceita wildcards (`'video/*'`) | `string\|string[]`
| `Image` | o arquivo carregado é JPEG, PNG, GIF, WebP | -
| `Pattern` | o nome do arquivo corresponde à expressão regular | `string`
| `PatternInsensitive` | como `Pattern`, mas não sensível a maiúsculas e minúsculas | `string`

Os sites `MimeType` e `Image` requerem extensão PHP `fileinfo`. Se um arquivo ou imagem é do tipo requerido é detectado por sua assinatura. A integridade do arquivo inteiro não é verificada. Você pode descobrir se uma imagem não está corrompida, por exemplo, ao tentar [carregá-la |http:request#toImage].


Mensagens de erro .[#toc-error-messages]
========================================

Todas as regras predefinidas, exceto `Pattern` e `PatternInsensitive`, têm uma mensagem de erro padrão, portanto, ela é omitida. Entretanto, ao passar e formular todas as mensagens personalizadas, você tornará o formulário mais fácil de usar.

Você pode alterar as mensagens padrão em [configuração |forms:configuration], modificando os textos na matriz `Nette\Forms\Validator::$messages` ou usando o [tradutor |rendering#translating].

Os seguintes wildcards podem ser usados no texto das mensagens de erro:

| `%d` | substitui gradualmente as regras após os argumentos
| `%n$d` | substitui com o n-ésimo argumento de regra
| `%label` | substitui com etiqueta de campo (sem dois pontos)
| `%name` | substitui pelo nome do campo (ex: `name`)
| `%value` | substitui pelo valor inserido pelo usuário

```php
$form->addText('name', 'Name:')
	->setRequired('Please fill in %label');

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'at least %d and no more than %d', [5, 10]);

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'no more than %2$d and at least %1$d', [5, 10]);
```


Condições .[#toc-conditions]
============================

Além das regras de validação, podem ser estabelecidas condições. Elas são muito parecidas com regras, mas usamos `addRule()` em vez de `addCondition()` e, claro, deixamos isso sem uma mensagem de erro (a condição só pede):

```php
$form->addPassword('password', 'Password:')
	// se a senha não for maior do que 8 caracteres ...
	->addCondition($form::MaxLength, 8)
		// ... então ele deve conter um número
		->addRule($form::Pattern, 'Deve conter número', '.*[0-9].*');
```

A condição pode ser ligada a um elemento diferente do atual usando `addConditionOn()`. O primeiro parâmetro é uma referência ao campo. No caso seguinte, o e-mail só será necessário se a caixa de seleção estiver marcada (ou seja, seu valor é `true`):

```php
$form->addCheckbox('newsletters', 'send me newsletters');

$form->addEmail('email', 'Email:')
	// se a caixa de seleção estiver marcada ...
	->addConditionOn($form['newsletters'], $form::Igual, verdadeiro)
		// ... exigir e-mail
		->setRequired('Preencha seu endereço de e-mail');
```

As condições podem ser agrupadas em estruturas complexas com os métodos `elseCondition()` e `endCondition()`.

```php
$form->addText(/* ... */)
	->addCondition(/* ... */) // se a primeira condição for cumprida
		->addConditionOn(/* ... */) // e a segunda condição em outro elemento também
			->addRule(/* ... */) // exigem esta regra
		->elseCondition() // se a segunda condição não for cumprida
			->addRule(/* ... */) // exigem estas regras
			->addRule(/* ... */)
		->endCondition() // voltamos à primeira condição
		->addRule(/* ... */);
```

Em Nette, é muito fácil reagir ao cumprimento ou não de uma condição no lado JavaScript usando o método `toggle()`, veja [Dynamic JavaScript |#Dynamic JavaScript].


Referências entre controles .[#toc-references-between-controls]
===============================================================

A regra ou argumento de condição pode ser uma referência a outro elemento. Por exemplo, você pode validar dinamicamente que o `text` tem tantos caracteres quanto o valor do campo `length`:

```php
$form->addInteger('length');
$form->addText('text')
	->addRule($form::Length, null, $form['length']);
```


Regras e condições personalizadas .[#toc-custom-rules-and-conditions]
=====================================================================

Às vezes, chegamos a uma situação em que as regras de validação incorporadas em Nette não são suficientes e precisamos validar os dados do usuário à nossa própria maneira. Em Nette isto é muito fácil!

Você pode passar qualquer ligação de retorno como primeiro parâmetro para os métodos `addRule()` ou `addCondition()`. A chamada de retorno aceita o próprio elemento como o primeiro parâmetro e retorna um valor booleano indicando se a validação foi bem sucedida. Ao adicionar uma regra usando `addRule()`, argumentos adicionais podem ser passados, e estes são então passados como o segundo parâmetro.

O conjunto personalizado de validadores pode assim ser criado como uma classe com métodos estáticos:

```php
class MyValidators
{
	// testa se o valor é divisível pelo argumento
	public static function validateDivisibility(BaseControl $input, $arg): bool
	{
		return $input->getValue() % $arg === 0;
	}

	public static function validateEmailDomain(BaseControl $input, $domain)
	{
		// validadores adicionais
	}
}
```

O uso é então muito simples:

```php
$form->addInteger('num')
	->addRule(
		[MyValidators::class, 'validateDivisibility'],
		'The value must be a multiple of %d',
		8,
	);
```

Regras de validação personalizadas também podem ser adicionadas ao JavaScript. A única exigência é que a regra deve ser um método estático. Seu nome para o validador JavaScript é criado concatenando o nome da classe sem contrabarra `\`, the underscore `_`, e o nome do método. Por exemplo, escreva `App\MyValidators::validateDivisibility` como `AppMyValidators_validateDivisibility` e adicione-o ao objeto `Nette.validators`:

```js
Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
	return val % args === 0;
};
```


Evento sobreValidar .[#toc-event-onvalidate]
============================================

Após o envio do formulário, a validação é feita verificando as regras individuais adicionadas por `addRule()` e depois ligando para o [evento |nette:glossary#Events] `onValidate`. Seu manipulador pode ser usado para validação adicional, normalmente para verificar a combinação correta de valores em múltiplos elementos do formulário.

Se um erro for detectado, ele é passado para o formulário usando o método `addError()`. Isto pode ser chamado em um elemento específico ou diretamente no formulário.

```php
protected function createComponentSignInForm(): Form
{
	$form = new Form;
	// ...
	$form->onValidate[] = [$this, 'validateSignInForm'];
	return $form;
}

public function validateSignInForm(Form $form, \stdClass $data): void
{
	if ($data->foo > 1 && $data->bar > 5) {
		$form->addError('This combination is not possible.');
	}
}
```


Erros de processamento .[#toc-processing-errors]
================================================

Em muitos casos, descobrimos um erro quando estamos processando um formulário válido, por exemplo, quando escrevemos uma nova entrada no banco de dados e encontramos uma chave duplicada. Neste caso, passamos o erro de volta para o formulário usando o método `addError()`. Isto pode ser chamado tanto em um item específico ou diretamente no formulário:

```php
try {
	$data = $form->getValues();
	$this->user->login($data->username, $data->password);
	$this->redirect('Home:');

} catch (Nette\Security\AuthenticationException $e) {
	if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
		$form->addError('Invalid password.');
	}
}
```

Se possível, recomendamos adicionar o erro diretamente ao elemento do formulário, pois ele aparecerá ao lado dele ao utilizar o renderizador padrão.

```php
$form['date']->addError('Sorry, this date is already taken.');
```

Você pode ligar para `addError()` repetidamente para passar múltiplas mensagens de erro a um formulário ou elemento. Você as recebe com `getErrors()`.

Observe que `$form->getErrors()` retorna um resumo de todas as mensagens de erro, mesmo aquelas transmitidas diretamente a elementos individuais, e não apenas diretamente ao formulário. As mensagens de erro passadas apenas para o formulário são recuperadas via `$form->getOwnErrors()`.


Modificando valores de entrada .[#toc-modifying-input-values]
=============================================================

Usando o método `addFilter()`, podemos modificar o valor inserido pelo usuário. Neste exemplo, toleraremos e removeremos espaços no código postal:

```php
$form->addText('zip', 'Postcode:')
	->addFilter(function ($value) {
		return str_replace(' ', '', $value); // remover espaços do código postal
	})
	->addRule($form::Pattern, 'O código postal não tem cinco dígitos', '\d{5}');
```

O filtro é incluído entre as regras e condições de validação e, portanto, depende da ordem dos métodos, ou seja, o filtro e a regra são chamados na mesma ordem que é a ordem dos métodos `addFilter()` e `addRule()`.


Validação JavaScript .[#toc-javascript-validation]
==================================================

A linguagem das regras e condições de validação é poderosa. Embora todas as construções funcionem tanto no lado do servidor quanto no lado do cliente, em JavaScript. As regras são transferidas em atributos HTML `data-nette-rules` como JSON.
A validação em si é manipulada por outro script, que anilha todos os eventos `submit` do formulário, itera sobre todas as entradas e executa as respectivas validações.

Este roteiro é `netteForms.js`, que está disponível em várias fontes possíveis:

Você pode incorporar o script diretamente na página HTML a partir do CDN:

```latte
<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>
```

Ou copiar localmente para a pasta pública do projeto (por exemplo, de `vendor/nette/forms/src/assets/netteForms.min.js`):

```latte
<script src="/path/to/netteForms.min.js"></script>
```

Ou instalar via [npm |https://www.npmjs.com/package/nette-forms]:

```shell
npm install nette-forms
```

E depois carregar e correr:

```js
import netteForms from 'nette-forms';
netteForms.initOnLoad();
```

Alternativamente, você pode carregá-lo diretamente da pasta `vendor`:

```js
import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();
```


JavaScript dinâmico .[#toc-dynamic-javascript]
==============================================

Você só quer mostrar os campos de endereço se o usuário optar por enviar a mercadoria pelo correio? Não há problema. A chave é um par de métodos `addCondition()` & `toggle()`:

```php
$form->addCheckbox('send_it')
	->addCondition($form::Equal, true)
		->toggle('#address-container');
```

Este código diz que quando a condição for preenchida, ou seja, quando a caixa de seleção for marcada, o elemento HTML `#address-container` estará visível. E vice versa. Assim, colocamos os elementos do formulário com o endereço do destinatário em um container com essa identificação, e quando a caixa de seleção é clicada, eles são escondidos ou mostrados. Isto é tratado pelo script `netteForms.js`.

Qualquer seletor pode ser passado como argumento para o método `toggle()`. Por razões históricas, uma cadeia alfanumérica sem outros caracteres especiais é tratada como um elemento de identificação, o mesmo que se fosse precedida pelo `#` character. The second optional parameter allows us to reverse the behavior, i.e. if we used `toggle('#address-container', false)`, o elemento só seria exibido se a caixa de seleção fosse desmarcada.

A implementação padrão do JavaScript muda a propriedade `hidden` para os elementos. Entretanto, podemos mudar facilmente o comportamento, por exemplo, adicionando uma animação. Basta anular o método `Nette.toggle` em JavaScript com uma solução personalizada:

```js
Nette.toggle = (selector, visible, srcElement, event) => {
	document.querySelectorAll(selector).forEach((el) => {
		// hide or show 'el' according to the value of 'visible'
	});
};
```


Desabilitando a Validação .[#toc-disabling-validation]
======================================================

Em certos casos, é necessário desativar a validação. Se um botão submeter não deve executar a validação após a submissão (por exemplo *Cancelar* ou *Prever* botão), você pode desabilitar a validação ligando para `$submit->setValidationScope([])`. Você também pode validar o formulário parcialmente, especificando os itens a serem validados.

```php
$form->addText('name')
	->setRequired();

$details = $form->addContainer('details');
$details->addInteger('age')
	->setRequired('age');
$details->addInteger('age2')
	->setRequired('age2');

$form->addSubmit('send1'); // valida o formulário completo
$form->addSubmit('send2')
	->setValidationScope([]); // Não valida nada
$form->addSubmit('send3')
	->setValidationScope([$form['name']]); // valida apenas o campo 'name' (nome)
$form->addSubmit('send4')
	->setValidationScope([$form['details']['age']]); // Valida apenas o campo 'age
$form->addSubmit('send5')
	->setValidationScope([$form['details'])); // valida 'details' container
```

[O evento onValidate |#Event onValidate] no formulário é sempre invocado e não é afetado pelo `setValidationScope`. `onValidate` O evento[onValidate |#Event onValidate] no container é invocado somente quando este container é especificado para validação parcial.

Validação de Formulários

Controles requeridos

Os controles são marcados conforme necessário com o método setRequired(), cujo argumento é o texto da mensagem de erro que será exibida caso o usuário não a preencha. Se nenhum argumento for apresentado, é usada a mensagem de erro padrão.

$form->addText('name', 'Name:')
	->setRequired('Please fill your name.');

Regras

Acrescentamos regras de validação aos controles com o método addRule(). O primeiro parâmetro é a regra, o segundo é a mensagem de erro, e o terceiro é o argumento da regra de validação.

$form->addPassword('password', 'Password:')
	->addRule($form::MinLength, 'Password must be at least %d characters', 8);

**As regras de validação são verificadas somente se o usuário tiver preenchido o elemento.

O Nette vem com várias regras predefinidas cujos nomes são constantes da classe Nette\Forms\Form. Podemos aplicar essas regras a todos os elementos:

constante descrição argumentos
Required alias de setRequired()
Filled alias de setRequired()
Blank não deve ser preenchido
Equal o valor é igual ao parâmetro mixed
NotEqual o valor não é igual ao parâmetro mixed
IsIn o valor é igual a algum elemento da matriz array
IsNotIn valor não é igual a nenhum elemento da matriz array
Valid validação dos passes de entrada (para condições)

Entradas de texto

Para os elementos addText(), addPassword(), addTextArea(), addEmail(), addInteger(), addFloat(), algumas das regras a seguir também podem ser aplicadas:

MinLength comprimento mínimo das cordas int
MaxLength comprimento máximo das cordas int
Length comprimento no alcance ou comprimento exato par [int, int] ou int
Email endereço de e-mail válido
URL URL válida
Pattern corresponde ao padrão regular string
PatternInsensitive como Pattern, mas não sensível a maiúsculas e minúsculas string
Integer integer
Numeric alias de Integer
Float número inteiro ou de ponto flutuante
Min mínimo do valor inteiro int|float
Max máximo do valor inteiro int|float
Range valor na faixa par [int|float, int|float]

As regras Integer, Numeric a Float convertem automaticamente o valor em inteiro (ou float, respectivamente). Além disso, a regra URL também aceita um endereço sem esquema (por exemplo nette.org) e completa o esquema (https://nette.org). As expressões em Pattern e PatternInsensitive devem ser válidas para todo o valor, ou seja, como se estivesse embrulhado nos caracteres ^ and $.

Número de itens

Para os elementos addMultiUpload(), addCheckboxList(), addMultiSelect() você também pode usar as seguintes regras para limitar o número de itens selecionados ou arquivos carregados:

MinLength número mínimo int
MaxLength número máximo int
Length número no intervalo ou número exato pares [int, int] ou int

Upload de arquivos

Para controles addUpload(), addMultiUpload() as seguintes regras também podem ser usadas:

MaxFileSize tamanho máximo do arquivo em bytes int
MimeType tipo MIME, aceita wildcards ('video/*') string|string[]
Image o arquivo carregado é JPEG, PNG, GIF, WebP
Pattern o nome do arquivo corresponde à expressão regular string
PatternInsensitive como Pattern, mas não sensível a maiúsculas e minúsculas string

Os sites MimeType e Image requerem extensão PHP fileinfo. Se um arquivo ou imagem é do tipo requerido é detectado por sua assinatura. A integridade do arquivo inteiro não é verificada. Você pode descobrir se uma imagem não está corrompida, por exemplo, ao tentar carregá-la.

Mensagens de erro

Todas as regras predefinidas, exceto Pattern e PatternInsensitive, têm uma mensagem de erro padrão, portanto, ela é omitida. Entretanto, ao passar e formular todas as mensagens personalizadas, você tornará o formulário mais fácil de usar.

Você pode alterar as mensagens padrão em configuração, modificando os textos na matriz Nette\Forms\Validator::$messages ou usando o tradutor.

Os seguintes wildcards podem ser usados no texto das mensagens de erro:

%d substitui gradualmente as regras após os argumentos
%n$d substitui com o n-ésimo argumento de regra
%label substitui com etiqueta de campo (sem dois pontos)
%name substitui pelo nome do campo (ex: name)
%value substitui pelo valor inserido pelo usuário
$form->addText('name', 'Name:')
	->setRequired('Please fill in %label');

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'at least %d and no more than %d', [5, 10]);

$form->addInteger('id', 'ID:')
	->addRule($form::Range, 'no more than %2$d and at least %1$d', [5, 10]);

Condições

Além das regras de validação, podem ser estabelecidas condições. Elas são muito parecidas com regras, mas usamos addRule() em vez de addCondition() e, claro, deixamos isso sem uma mensagem de erro (a condição só pede):

$form->addPassword('password', 'Password:')
	// se a senha não for maior do que 8 caracteres ...
	->addCondition($form::MaxLength, 8)
		// ... então ele deve conter um número
		->addRule($form::Pattern, 'Deve conter número', '.*[0-9].*');

A condição pode ser ligada a um elemento diferente do atual usando addConditionOn(). O primeiro parâmetro é uma referência ao campo. No caso seguinte, o e-mail só será necessário se a caixa de seleção estiver marcada (ou seja, seu valor é true):

$form->addCheckbox('newsletters', 'send me newsletters');

$form->addEmail('email', 'Email:')
	// se a caixa de seleção estiver marcada ...
	->addConditionOn($form['newsletters'], $form::Igual, verdadeiro)
		// ... exigir e-mail
		->setRequired('Preencha seu endereço de e-mail');

As condições podem ser agrupadas em estruturas complexas com os métodos elseCondition() e endCondition().

$form->addText(/* ... */)
	->addCondition(/* ... */) // se a primeira condição for cumprida
		->addConditionOn(/* ... */) // e a segunda condição em outro elemento também
			->addRule(/* ... */) // exigem esta regra
		->elseCondition() // se a segunda condição não for cumprida
			->addRule(/* ... */) // exigem estas regras
			->addRule(/* ... */)
		->endCondition() // voltamos à primeira condição
		->addRule(/* ... */);

Em Nette, é muito fácil reagir ao cumprimento ou não de uma condição no lado JavaScript usando o método toggle(), veja Dynamic JavaScript.

Referências entre controles

A regra ou argumento de condição pode ser uma referência a outro elemento. Por exemplo, você pode validar dinamicamente que o text tem tantos caracteres quanto o valor do campo length:

$form->addInteger('length');
$form->addText('text')
	->addRule($form::Length, null, $form['length']);

Regras e condições personalizadas

Às vezes, chegamos a uma situação em que as regras de validação incorporadas em Nette não são suficientes e precisamos validar os dados do usuário à nossa própria maneira. Em Nette isto é muito fácil!

Você pode passar qualquer ligação de retorno como primeiro parâmetro para os métodos addRule() ou addCondition(). A chamada de retorno aceita o próprio elemento como o primeiro parâmetro e retorna um valor booleano indicando se a validação foi bem sucedida. Ao adicionar uma regra usando addRule(), argumentos adicionais podem ser passados, e estes são então passados como o segundo parâmetro.

O conjunto personalizado de validadores pode assim ser criado como uma classe com métodos estáticos:

class MyValidators
{
	// testa se o valor é divisível pelo argumento
	public static function validateDivisibility(BaseControl $input, $arg): bool
	{
		return $input->getValue() % $arg === 0;
	}

	public static function validateEmailDomain(BaseControl $input, $domain)
	{
		// validadores adicionais
	}
}

O uso é então muito simples:

$form->addInteger('num')
	->addRule(
		[MyValidators::class, 'validateDivisibility'],
		'The value must be a multiple of %d',
		8,
	);

Regras de validação personalizadas também podem ser adicionadas ao JavaScript. A única exigência é que a regra deve ser um método estático. Seu nome para o validador JavaScript é criado concatenando o nome da classe sem contrabarra \, the underscore _, e o nome do método. Por exemplo, escreva App\MyValidators::validateDivisibility como AppMyValidators_validateDivisibility e adicione-o ao objeto Nette.validators:

Nette.validators['AppMyValidators_validateDivisibility'] = (elem, args, val) => {
	return val % args === 0;
};

Evento sobreValidar

Após o envio do formulário, a validação é feita verificando as regras individuais adicionadas por addRule() e depois ligando para o evento onValidate. Seu manipulador pode ser usado para validação adicional, normalmente para verificar a combinação correta de valores em múltiplos elementos do formulário.

Se um erro for detectado, ele é passado para o formulário usando o método addError(). Isto pode ser chamado em um elemento específico ou diretamente no formulário.

protected function createComponentSignInForm(): Form
{
	$form = new Form;
	// ...
	$form->onValidate[] = [$this, 'validateSignInForm'];
	return $form;
}

public function validateSignInForm(Form $form, \stdClass $data): void
{
	if ($data->foo > 1 && $data->bar > 5) {
		$form->addError('This combination is not possible.');
	}
}

Erros de processamento

Em muitos casos, descobrimos um erro quando estamos processando um formulário válido, por exemplo, quando escrevemos uma nova entrada no banco de dados e encontramos uma chave duplicada. Neste caso, passamos o erro de volta para o formulário usando o método addError(). Isto pode ser chamado tanto em um item específico ou diretamente no formulário:

try {
	$data = $form->getValues();
	$this->user->login($data->username, $data->password);
	$this->redirect('Home:');

} catch (Nette\Security\AuthenticationException $e) {
	if ($e->getCode() === Nette\Security\Authenticator::InvalidCredential) {
		$form->addError('Invalid password.');
	}
}

Se possível, recomendamos adicionar o erro diretamente ao elemento do formulário, pois ele aparecerá ao lado dele ao utilizar o renderizador padrão.

$form['date']->addError('Sorry, this date is already taken.');

Você pode ligar para addError() repetidamente para passar múltiplas mensagens de erro a um formulário ou elemento. Você as recebe com getErrors().

Observe que $form->getErrors() retorna um resumo de todas as mensagens de erro, mesmo aquelas transmitidas diretamente a elementos individuais, e não apenas diretamente ao formulário. As mensagens de erro passadas apenas para o formulário são recuperadas via $form->getOwnErrors().

Modificando valores de entrada

Usando o método addFilter(), podemos modificar o valor inserido pelo usuário. Neste exemplo, toleraremos e removeremos espaços no código postal:

$form->addText('zip', 'Postcode:')
	->addFilter(function ($value) {
		return str_replace(' ', '', $value); // remover espaços do código postal
	})
	->addRule($form::Pattern, 'O código postal não tem cinco dígitos', '\d{5}');

O filtro é incluído entre as regras e condições de validação e, portanto, depende da ordem dos métodos, ou seja, o filtro e a regra são chamados na mesma ordem que é a ordem dos métodos addFilter() e addRule().

Validação JavaScript

A linguagem das regras e condições de validação é poderosa. Embora todas as construções funcionem tanto no lado do servidor quanto no lado do cliente, em JavaScript. As regras são transferidas em atributos HTML data-nette-rules como JSON. A validação em si é manipulada por outro script, que anilha todos os eventos submit do formulário, itera sobre todas as entradas e executa as respectivas validações.

Este roteiro é netteForms.js, que está disponível em várias fontes possíveis:

Você pode incorporar o script diretamente na página HTML a partir do CDN:

<script src="https://unpkg.com/nette-forms@3/src/assets/netteForms.js"></script>

Ou copiar localmente para a pasta pública do projeto (por exemplo, de vendor/nette/forms/src/assets/netteForms.min.js):

<script src="/path/to/netteForms.min.js"></script>

Ou instalar via npm:

npm install nette-forms

E depois carregar e correr:

import netteForms from 'nette-forms';
netteForms.initOnLoad();

Alternativamente, você pode carregá-lo diretamente da pasta vendor:

import netteForms from '../path/to/vendor/nette/forms/src/assets/netteForms.js';
netteForms.initOnLoad();

JavaScript dinâmico

Você só quer mostrar os campos de endereço se o usuário optar por enviar a mercadoria pelo correio? Não há problema. A chave é um par de métodos addCondition() & toggle():

$form->addCheckbox('send_it')
	->addCondition($form::Equal, true)
		->toggle('#address-container');

Este código diz que quando a condição for preenchida, ou seja, quando a caixa de seleção for marcada, o elemento HTML #address-container estará visível. E vice versa. Assim, colocamos os elementos do formulário com o endereço do destinatário em um container com essa identificação, e quando a caixa de seleção é clicada, eles são escondidos ou mostrados. Isto é tratado pelo script netteForms.js.

Qualquer seletor pode ser passado como argumento para o método toggle(). Por razões históricas, uma cadeia alfanumérica sem outros caracteres especiais é tratada como um elemento de identificação, o mesmo que se fosse precedida pelo # character. The second optional parameter allows us to reverse the behavior, i.e. if we used toggle('#address-container', false), o elemento só seria exibido se a caixa de seleção fosse desmarcada.

A implementação padrão do JavaScript muda a propriedade hidden para os elementos. Entretanto, podemos mudar facilmente o comportamento, por exemplo, adicionando uma animação. Basta anular o método Nette.toggle em JavaScript com uma solução personalizada:

Nette.toggle = (selector, visible, srcElement, event) => {
	document.querySelectorAll(selector).forEach((el) => {
		// hide or show 'el' according to the value of 'visible'
	});
};

Desabilitando a Validação

Em certos casos, é necessário desativar a validação. Se um botão submeter não deve executar a validação após a submissão (por exemplo Cancelar ou Prever botão), você pode desabilitar a validação ligando para $submit->setValidationScope([]). Você também pode validar o formulário parcialmente, especificando os itens a serem validados.

$form->addText('name')
	->setRequired();

$details = $form->addContainer('details');
$details->addInteger('age')
	->setRequired('age');
$details->addInteger('age2')
	->setRequired('age2');

$form->addSubmit('send1'); // valida o formulário completo
$form->addSubmit('send2')
	->setValidationScope([]); // Não valida nada
$form->addSubmit('send3')
	->setValidationScope([$form['name']]); // valida apenas o campo 'name' (nome)
$form->addSubmit('send4')
	->setValidationScope([$form['details']['age']]); // Valida apenas o campo 'age
$form->addSubmit('send5')
	->setValidationScope([$form['details'])); // valida 'details' container

O evento onValidate no formulário é sempre invocado e não é afetado pelo setValidationScope. onValidate O eventoonValidate no container é invocado somente quando este container é especificado para validação parcial.