Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the validation of an array of objects #40

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ A validation library for the Slim Framework. It internally uses [Respect/Validat
- [Route parameters](#route-parameters)
- [JSON requests](#json-requests)
- [XML requests](#xml-requests)
- [Array](#array)
- [Translate errors](#translate-errors)
- [Testing](#testing)
- [Contributing](#contributing)
Expand Down Expand Up @@ -288,6 +289,42 @@ Array
```


### Array

If you want to validate a request that contains an array as the root level, you can directly use [Respect/Validation][respect-validation] as the first parameter of the Validation middleware. For example:

```php
use Respect\Validation\Validator as v;

$app = new \Slim\App();

//Create the validators
$validators = v::each(
v::keySet(
v::key("id", v::intVal()),
v::key("key", v::stringType())
)
);
```


If you'll have an error, the result would be:

```php
//In your route
$errors = $req->getAttribute('errors');

print_r($errors);
/*
Array
(
[0] => Must have keys { "id", "key" }

)
*/
```


### Translate errors

You can provide a callable function to translate the errors.
Expand Down
50 changes: 41 additions & 9 deletions src/Validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace DavidePastore\Slim\Validation;

use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Validator;

/**
* Validation for Slim.
Expand Down Expand Up @@ -66,6 +67,13 @@ class Validation
*/
protected $translator_name = 'translator';

/**
* Is the validators an instance of Validator?
*
* @var boolean
*/
protected $isValidator = false;

/**
* Create new Validator service provider.
*
Expand All @@ -78,6 +86,9 @@ public function __construct($validators = null, $translator = null, $options = [
// Set the validators
if (is_array($validators) || $validators instanceof \ArrayAccess) {
$this->validators = $validators;
} elseif ($validators instanceof Validator) {
$this->validators = $validators;
$this->isValidator = true;
} elseif (is_null($validators)) {
$this->validators = [];
}
Expand All @@ -99,7 +110,11 @@ public function __invoke($request, $response, $next)
$this->errors = [];
$params = $request->getParams();
$params = array_merge((array) $request->getAttribute('routeInfo')[2], $params);
$this->validate($params, $this->validators);
if ($this->isValidator) {
$this->validateParam($params, $this->validators);
} else {
$this->validate($params, $this->validators);
}

$request = $request->withAttribute($this->errors_name, $this->getErrors());
$request = $request->withAttribute($this->has_errors_name, $this->hasErrors());
Expand All @@ -126,21 +141,38 @@ private function validate($params = [], $validators = [], $actualKeys = [])
if (is_array($validator)) {
$this->validate($params, $validator, $actualKeys);
} else {
try {
$validator->assert($param);
} catch (NestedValidationException $exception) {
if ($this->translator) {
$exception->setParam('translator', $this->translator);
}
$this->errors[implode('.', $actualKeys)] = $exception->getMessages();
}
$this->validateParam($param, $validator, $actualKeys);
}

//Remove the key added in this foreach
array_pop($actualKeys);
}
}

/**
* Validate a param.
* @param any $param The parameter to validate.
* @param any $validator The validator to use to validate the given parameter.
* @param array $actualKeys An array with the position of the parameter.
*/
private function validateParam($param, $validator, $actualKeys = [])
{
try {
$validator->assert($param);
} catch (NestedValidationException $exception) {
if ($this->translator) {
$exception->setParam('translator', $this->translator);
}

$messages = $exception->getMessages();
if (empty($actualKeys)) {
$this->errors = $messages;
} else {
$this->errors[implode('.', $actualKeys)] = $messages;
}
}
}

/**
* Get the nested parameter value.
*
Expand Down
Loading