-
Notifications
You must be signed in to change notification settings - Fork 770
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve the "Feature Guide" documentation
Because the document was quite big already, I split the exception handling part to another document.
- Loading branch information
1 parent
eb459ad
commit 3833ad7
Showing
18 changed files
with
199 additions
and
220 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,258 +1,102 @@ | ||
# Feature Guide | ||
|
||
## Namespace import | ||
|
||
Respect\Validation is namespaced, but you can make your life easier by importing | ||
a single class into your context: | ||
We'll use `v` as an alias for `Respect\Validation\Validator` to keep things simple: | ||
|
||
```php | ||
use Respect\Validation\Validator as v; | ||
``` | ||
|
||
## Simple validation | ||
|
||
The Hello World validator is something like this: | ||
|
||
```php | ||
$number = 123; | ||
v::numericVal()->isValid($number); // true | ||
``` | ||
|
||
## Chained validation | ||
|
||
It is possible to use validators in a chain. Sample below validates a string | ||
containing numbers and letters, no whitespace and length between 1 and 15. | ||
|
||
```php | ||
$usernameValidator = v::alnum()->noWhitespace()->length(1, 15); | ||
$usernameValidator->isValid('alganet'); // true | ||
``` | ||
|
||
## Validating object properties | ||
|
||
Given this simple object: | ||
|
||
```php | ||
$user = new stdClass; | ||
$user->name = 'Alexandre'; | ||
$user->birthdate = '1987-07-01'; | ||
``` | ||
|
||
Is possible to validate its properties in a single chain: | ||
|
||
```php | ||
$userValidator = v::property('name', v::stringType()->length(1, 32)) | ||
->property('birthdate', v::dateTimeDiff(v::greaterThanOrEqual(18), 'years')); | ||
|
||
$userValidator->isValid($user); // true | ||
``` | ||
|
||
Validating array keys is also possible using `v::key()` | ||
|
||
Note that we used `v::stringType()` and `v::dateTime()` in the beginning of the validator. | ||
Although is not mandatory, it is a good practice to use the type of the | ||
validated object as the first node in the chain. | ||
|
||
## Validating array keys and values | ||
|
||
Validating array keys into another array is also possible using [Key](rules/Key.md). | ||
|
||
If we got the array below: | ||
|
||
```php | ||
$data = [ | ||
'parentKey' => [ | ||
'field1' => 'value1', | ||
'field2' => 'value2' | ||
'field3' => true, | ||
] | ||
]; | ||
``` | ||
## Validating using booleans | ||
|
||
Using the next combination of rules, we can validate child keys. | ||
With the `isValid()` method, determine if your input meets a specific validation rule. | ||
|
||
```php | ||
v::key( | ||
'parentKey', | ||
v::key('field1', v::stringType()) | ||
->key('field2', v::stringType()) | ||
->key('field3', v::boolType()) | ||
) | ||
->assert($data); // You can also use check() or validate() | ||
if (v::intType()->positive()->isValid($input)) { | ||
echo 'The input you gave me is a positive integer'; | ||
} else { | ||
echo 'The input you gave me is not a positive integer'; | ||
} | ||
``` | ||
|
||
## Input optional | ||
Note that you can combine multiple rules for a complex validation. | ||
## Validating using exceptions | ||
|
||
On oldest versions of Respect\Validation all validators treat input as optional | ||
and accept an empty string input as valid. Even though a useful feature that | ||
caused a lot of troubles for our team and neither was an obvious behavior. Also | ||
there was some people who likes to accept `null` as optional value, not only an | ||
empty string. | ||
The `assert()` method throws an exception when validation fails. You can handle those exceptions with `try/catch` for more robust error handling. | ||
|
||
For that reason all rules are mandatory now but if you want to treat a value as | ||
optional you can use `v::optional()` rule: | ||
### Basic example | ||
|
||
```php | ||
v::alpha()->isValid(''); // false input required | ||
v::alpha()->isValid(null); // false input required | ||
|
||
v::optional(v::alpha())->isValid(''); // true | ||
v::optional(v::alpha())->isValid(null); // true | ||
v::intType()->positive()->assert($input); | ||
``` | ||
|
||
By _optional_ we consider `null` or an empty string (`''`). | ||
|
||
See more on [Optional](rules/UndefOr.md). | ||
|
||
## Negating rules | ||
### Custom templates | ||
|
||
You can use the `v::not()` to negate any rule: | ||
Define your own error message when the validation fails: | ||
|
||
```php | ||
v::not(v::intVal())->isValid(10); // false, input must not be integer | ||
v::between(1, 256)->assert($input, '{{name}} is not what I was expecting'); | ||
``` | ||
|
||
## Validator reuse | ||
### Custom templates per rule | ||
|
||
Once created, you can reuse your validator anywhere. Remember `$usernameValidator`? | ||
Provide unique messages for each rule in a chain: | ||
|
||
```php | ||
$usernameValidator->isValid('respect'); //true | ||
$usernameValidator->isValid('alexandre gaigalas'); // false | ||
$usernameValidator->isValid('#$%'); //false | ||
v::alnum()->lowercase()->assert($input, [ | ||
'alnum' => 'Your username must contain only letters and digits', | ||
'lowercase' => 'Your username must be lowercase', | ||
]); | ||
``` | ||
|
||
## Exception types | ||
|
||
- `Respect\Validation\Exceptions\Exception`: | ||
- All exceptions implement this interface; | ||
- `Respect\Validation\Exceptions\ValidationException`: | ||
- Implements the `Respect\Validation\Exceptions\Exception` interface | ||
- Thrown when the `check()` fails | ||
- All validation exceptions extend this class | ||
- Available methods: | ||
- `getMessage()`; | ||
- `updateMode($mode)`; | ||
- `updateTemplate($template)`; | ||
- `Respect\Validation\Exceptions\NestedValidationException`: | ||
- Extends the `Respect\Validation\Exceptions\ValidationException` class | ||
- Usually thrown when the `assert()` fails | ||
- Available methods: | ||
- `getFullMessage()`; | ||
- `getMessages()`; | ||
|
||
## Informative exceptions | ||
|
||
When something goes wrong, Validation can tell you exactly what's going on. For this, | ||
we use the `assert()` method instead of `validate()`: | ||
### Custom exception objects | ||
|
||
Integrate your own exception objects when the validation fails: | ||
```php | ||
use Respect\Validation\Exceptions\NestedValidationException; | ||
|
||
try { | ||
$usernameValidator->assert('really messed up screen#name'); | ||
} catch(NestedValidationException $exception) { | ||
echo $exception->getFullMessage(); | ||
} | ||
v::alnum()->assert($input, new DomainException('Not a valid username')); | ||
``` | ||
|
||
The printed message is exactly this, as a nested Markdown list: | ||
|
||
```no-highlight | ||
- All of the required rules must pass for "really messed up screen#name" | ||
- "really messed up screen#name" must contain only letters (a-z) and digits (0-9) | ||
- "really messed up screen#name" must not contain whitespace | ||
- "really messed up screen#name" must have a length between 1 and 15 | ||
``` | ||
## Inverting validation rules | ||
|
||
## Getting all messages as an array | ||
|
||
If you want to get all the messages as an array you can use `getMessages()` for | ||
that. The `getMessages()` method returns an array with all the messages. | ||
Use the `not` prefix to invert a validation rule. | ||
|
||
```php | ||
try { | ||
$usernameValidator->assert('really messed up screen#name'); | ||
} catch(NestedValidationException $exception) { | ||
print_r($exception->getMessages()); | ||
} | ||
v::notEquals('main')->assert($input); | ||
``` | ||
|
||
The `getMessages()` returns an array in which the keys are the name of the | ||
validators, or its reference in case you are using [Key](rules/Key.md) or | ||
[Property](rules/Property.md) rule: | ||
For more details, check the [Not](rules/Not.md) rule documentation. | ||
|
||
```no-highlight | ||
Array | ||
( | ||
[alnum] => "really messed up screen#name" must contain only letters (a-z) and digits (0-9) | ||
[noWhitespace] => "really messed up screen#name" must not contain whitespace | ||
[length] => "really messed up screen#name" must have a length between 1 and 15 | ||
) | ||
``` | ||
## Reusing validators | ||
|
||
## Custom messages | ||
|
||
Getting messages as an array is fine, but sometimes you need to customize them | ||
in order to present them to the user. This is possible using the `getMessages()` | ||
method as well by passing the templates as an argument: | ||
Validators can be created once and reused across multiple inputs. | ||
|
||
```php | ||
try { | ||
$usernameValidator->assert('really messed up screen#name', [ | ||
'alnum' => '{{name}} must contain only letters and digits', | ||
'noWhitespace' => '{{name}} cannot contain spaces', | ||
'length' => '{{name}} must not have more than 15 chars', | ||
]); | ||
} catch(NestedValidationException $exception) { | ||
print_r($exception->getMessages()); | ||
} | ||
``` | ||
|
||
For all messages, the `{{name}}` variable is available for templates. If you do | ||
not define a name it uses the input to replace this placeholder. | ||
$validator = v::alnum()->lowercase(); | ||
|
||
The result of the code above will be: | ||
|
||
```no-highlight | ||
Array | ||
( | ||
[alnum] => "really messed up screen#name" must contain only letters and digits | ||
[noWhitespace] => "really messed up screen#name" cannot contain spaces | ||
[length] => "really messed up screen#name" must not have more than 15 chars | ||
) | ||
$validator->assert('respect'); | ||
$validator->assert('validation'); | ||
$validator->assert('alexandre gaigalas'); | ||
``` | ||
|
||
Note that `getMessage()` will only return a message when the specific validation | ||
in the chain fails. | ||
|
||
## Validator name | ||
## Customising validator names | ||
|
||
On `v::property()` and `v::key()`, `{{name}}` is the property/key name. For others, | ||
is the same as the input. You can customize a validator name using: | ||
Template messages include the placeholder `{{name}}`, which defaults to the input. Use `setName()` to replace it with a more descriptive label. | ||
|
||
```php | ||
v::dateTime('Y-m-d')->between('1980-02-02', 'now')->setName('Member Since'); | ||
v::dateTime('Y-m-d') | ||
->between('1980-02-02', 'now') | ||
->setName('Age') | ||
->assert($input); | ||
``` | ||
|
||
## Validation methods | ||
## Smart input handling | ||
|
||
We've seen `validate()` that returns true or false and `assert()` that throws a complete | ||
validation report. There is also a `check()` method that returns an Exception | ||
only with the first error found: | ||
Respect\Validation offers over 150 rules, many of which are designed to address common input handling scenarios. Here’s a quick guide to some specific use cases and the rules that make validation straightforward. | ||
|
||
```php | ||
use Respect\Validation\Exceptions\ValidationException; | ||
|
||
try { | ||
$usernameValidator->check('really messed up screen#name'); | ||
} catch(ValidationException $exception) { | ||
echo $exception->getMessage(); | ||
} | ||
``` | ||
|
||
Message: | ||
|
||
```no-highlight | ||
"really messed up screen#name" must contain only letters (a-z) and digits (0-9) | ||
``` | ||
* Validating arrays: [Key](rules/Key.md), [KeyOptional](rules/KeyOptional.md), and [KeyExists](rules/KeyExists.md). | ||
* Validating array structures: [KeySet](rules/KeySet.md). | ||
* Validating object properties: [Property](rules/Property.md), [PropertyOptional](rules/PropertyOptional.md), and [PropertyExists](rules/PropertyExists.md). | ||
* Validating only when input is not `null`: [NullOr](rules/NullOr.md). | ||
* Validating only when input is not `null` or an empty string: [UndefOr](rules/UndefOr.md). | ||
* Validating the length of the input: [Length](rules/Length.md). | ||
* Validating the maximum value of the input: [Max](rules/Max.md). | ||
* Validating the minimum value of the input: [Min](rules/Min.md). |
Oops, something went wrong.