Skip to content

Commit

Permalink
Merge pull request #16 from HylianShield/development
Browse files Browse the repository at this point in the history
Release v0.8 - Validator context
  • Loading branch information
janmartendeboer committed Nov 4, 2014
2 parents 1e60888 + 6b194c7 commit dc8847b
Show file tree
Hide file tree
Showing 113 changed files with 1,309 additions and 199 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
before_script:
- composer self-update
- composer validate
Expand Down
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# v0.8.0

- Added an interface for validators
- Deprecated method type on Validator in favor of getType
- Added context to validations, which are used to enrich the messages of
validators.
- Added support for PHP 5.6 through Travis CI
- Fixed code style issues
- Removed number tests using octet literals, as PHP does not interpret them
as expected.

# v0.7.0

- Added Email validator
Expand Down Expand Up @@ -31,7 +42,7 @@

# v0.2.2

- Fix the numeric arrar validator unit test
- Fix the numeric array validator unit test
- Improve performance of Range validators

# v0.2.1
Expand Down
226 changes: 226 additions & 0 deletions DEBUGGING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
# Debugging

The most neat thing about a good debugger is that it can save you copious
amounts of time, figuring out what went wrong when hitting save and running
your code.

Even then, a lot of fail happens in production and will be generated by your
user base.

The HylianShield validator is prepared for this, in a few ways:

- It holds simple and descriptive names for validators
- Validators will try to tell you what they got as input,
what kind of type it is and what they expected as valid input.
- Some validators (we aim to revisit all of them to implement this) make use
of the new validator context. This context registers assertions,
intentions and violations throughout the validation process. Whenever it can,
a validator will write down all violations encountered by the validator when
debugging an error.

## Validator getType().

The validator type can tell a lot about the reason why something failed.

```php
<?php
$validator = new \HylianShield\Validator\Email;
echo $validator->getType(); // 'email'
```

When casting a validator to a string, that does a call to `getType`,
so this works as well:

```php
<?php
echo $validator; // 'email'
```

## Validator getMessage()

After calling the validate method, you can use `getMessage` to see what went
wrong with the validation. The message will tell you the last supplied value,
the expected type and if possible show the different violations that caused
the validator to fail the supplied value.

```php
<?php
$validator = new \HylianShield\Validator\CoreFunction();
$validator->validate('My epic function');

echo $validator->getMessage();
```

Which will output:

```
Invalid value supplied: (string) 'My epic function'; Expected: function
Violations:
#1 Violation - Function "My epic function" does not exist - Violation code #2
```

The `CoreFunction` validator does two checks under the hood. First it checks
if the supplied value is a string. This is true in our case,
so it will move on to the next check, which is a simple question to the core
API if the supplied value is an existing function. At that point it fails and
adds a violation to the context created by the validator.

## Validator Context

Although a validator is perfectly capable of creating a context by itself,
you can create one of your own, pass it along and see the validator fill it
with valuable information.

```php
<?php
$validator = new \HylianShield\Validator\CoreFunction();
$context = $validator::createContext();
$validator->validate('My epic function', $context);

echo $context;
```

Which will output:

```
Context:
#1 Assertion - Validator is callable: Yes
#2 Intention - Passing context to registered validator.
#3 Violation - Function "My epic function" does not exist - Violation code #2
#4 Assertion - Validation was successful: No
```

You can get the intentions, assertions and violations individually from the
context, using their respective getters:

```php
<?php
$context->getAssertions(); // Assertion[]
$context->getIntentions(); // Intention[]
$context->getViolations(); // Violation[]
```

To get a complete picture of a context, here is a dump of the previously used
context:

```
class HylianShield\Validator\Context\Context#809 (1) {
protected $indications =>
array(4) {
[0] =>
class HylianShield\Validator\Context\Indication\Assertion#810 (2) {
protected $result =>
bool(true)
protected $description =>
string(21) "Validator is callable"
}
[1] =>
class HylianShield\Validator\Context\Indication\Intention#811 (1) {
protected $description =>
string(40) "Passing context to registered validator."
}
[2] =>
class HylianShield\Validator\Context\Indication\Violation#812 (3) {
protected $code =>
int(2)
protected $context =>
array(1) {
...
}
protected $description =>
string(31) "Function ":name" does not exist"
}
[3] =>
class HylianShield\Validator\Context\Indication\Assertion#813 (2) {
protected $result =>
bool(false)
protected $description =>
string(25) "Validation was successful"
}
}
}
```

### Intentions

Intentions are exactly what they are called. They are what the validator
intends to do. If at some point your code breaks because of the intention of
a validator, you should be able to make use of this information.

#### Adding an intention

```php
<?php
$context->addIntention('Skip validation rule #3');
```

### Assertions

Assertions are simply findings the validator made while walking through
validation rules. If at some point your validator appears to apply the wrong
rules to your input, it can be useful to see if the validator made a wrong
assumption.

#### Adding an assertion

```php
<?php
$options = array();

$context->addAssertion(
'Array of options is empty',
empty($options)
);
```

### Violations

The violations tell us the reasons why a validator decided to call your
supplied data invalid.

#### Adding a violation

```php
<?php
$context->addViolation(
'The function ":name" does not exist',
CoreFunction::VIOLATION_EXISTS,
array(
'name' => 'My awesome function'
)
);

echo $context;
```

Which will output:

```
Context:
#1 Violation - The function "My awesome function" does not exist - Violation code #2
```

#### Translating a violation

Since we do not want to show our users the same violation per se,
but perhaps make use of its context, or we do not serve English users,
we can translate the violation.

```php
<?php
use \HylianShield\Validator\Context\Indication\Violation;

$violation = new Violation(
'The function ":name" does not exist',
CoreFunction::VIOLATION_EXISTS,
array(
'name' => 'My awesome function'
)
);

echo $violation->interpolate('We have a loopy function called :name');
// 'We have a loopy function called My awesome function'

echo $violation->interpolate('Failing function: {name}', '{', '}');
// Failing function: My awesome function
```
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ We recognize that PHP has no proper type hinting for scalar data types. This is
- [API Docs: A completely generated API documentation](http://hylianshield.github.io/validator/)
- [Use case: An example of the HylianShield validator in action](USECASE.md)
- [Reference: An overview of the available validators and their arguments](REFERENCE.md)
- [Debugging: Add some context and meaning to failing validations](DEBUGGING.md)
- [Frameworks: 1-2-3-go. Direct integration with your framework](FRAMEWORKS.md)
- [Changelog: What changed in the last versions?](CHANGELOG.md)
- [Contributing: How do I add a validator in the mix?](CONTRIBUTING.md)
Expand Down
15 changes: 10 additions & 5 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,18 @@ if (!$isValid) {

// We should also be able to identify the type of the validator.
$validatorsByType = array(
$validator->type() => $validator
$validator->getType() => $validator
);

// Or to ensure a more unique identifier.
$uniqueValidators = array(
"{$validator}" => $validator
);

// E.g.: Our range validators also describe their range.
$validator = new Validator\Integer(1, 100);
echo $validator->getType(); // integer
echo $validator; // integer(1, 100)
```

## Core
Expand Down Expand Up @@ -92,10 +97,10 @@ $uniqueValidators = array(

## LogicalGate

- `LogicalAnd(\HylianShield\Validator $a, \HylianShield\Validator $b, [, ...])`
- `LogicalOr(\HylianShield\Validator $a, \HylianShield\Validator $b, [, ...])`
- `LogicalXor(\HylianShield\Validator $a, \HylianShield\Validator $b)`
- `LogicalNot(\HylianShield\Validator $validator)`
- `LogicalAnd(\HylianShield\ValidatorÌnterface $a, \HylianShield\ValidatorÌnterface $b, [, ...])`
- `LogicalOr(\HylianShield\ValidatorÌnterface $a, \HylianShield\ValidatorÌnterface $b, [, ...])`
- `LogicalXor(\HylianShield\ValidatorÌnterface $a, \HylianShield\ValidatorÌnterface $b)`
- `LogicalNot(\HylianShield\ValidatorÌnterface $validator)`

## Financial

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hylianshield/validator",
"type": "library",
"version": "0.7.0",
"version": "0.8.0",
"description": "Data validation and sanitizing",
"keywords": ["hylianshield", "validator", "validate", "validation"],
"homepage": "https://github.com/HylianShield/validator",
Expand Down

0 comments on commit dc8847b

Please sign in to comment.