Skip to content

Commit

Permalink
Add the ability to define a pretty name for an item
Browse files Browse the repository at this point in the history
  • Loading branch information
lalobo committed Jun 28, 2016
1 parent 589a469 commit a6f96be
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 41 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,23 @@ The libray allows you to validate a json style data structure using a set of val

$rules = [
'name' => [
'name' => 'Name',
'required' => true,
'type' => 'string',
'constraints' => [
'length' => [1,null]
]
],
'age' => [
'name' => 'Age',
'required' => false,
'type' => 'number',
'constraints' => [
'integer' => true
]
],
'address' => [
'name' => 'Address',
'required' => false,
'type' => 'object',
'properties' => [
Expand Down Expand Up @@ -112,8 +115,9 @@ The rules follow a simple structure. There are two categories of rules. Named, a
```
$rules = [
'name' => [
'required' => true,
'type' => 'string',
'name' => 'Name',
'required' => true,
'type' => 'string',
'constraints' => [
'callback' => 'MyValidator::checkName'
]
Expand All @@ -137,6 +141,7 @@ $rules = [
All rules have a mandatory `type` and an optional `constraints` property. Additionaly, all named rules have a mandatory `required` property.

* **properties**
* **name** [*string*]: The human readable name of your item (this is optional)
* **required** [*true/false*]: Wether the item is required or not (For named rules only)
* **type** [*string*]: The type of item. Currently `string`, `number`, `array` or `object`
* **constraints** [*array*] : an optional associative array of constraints. These are:
Expand Down
5 changes: 3 additions & 2 deletions src/TypeValidator/AbstractTypeValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ class AbstractTypeValidator implements TypeValidatorInterface
*
* @param array $constraints The rules
* @param mixed $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @throws DataValidationException
*/
public function validate(array $constraints, $data)
public function validate(array $constraints, $data, $prettyName = 'This value')
{
if (isset($constraints['callback'])) {
call_user_func_array($constraints['callback'], array($data));
call_user_func_array($constraints['callback'], array($data, $prettyName));
}
}
}
12 changes: 7 additions & 5 deletions src/TypeValidator/ArrayValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,32 @@ class ArrayValidator extends AbstractTypeValidator
*
* @param array $constraints The rules
* @param mixed $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @throws DataValidationException
*/
public function validate(array $constraints, $data)
public function validate(array $constraints, $data, $prettyName = 'This value')
{
if (gettype($data) == 'array') {
$this->validateSequentialArray($data);
$this->validateSequentialArray($data, $prettyName);
} else {
throw new DataValidationException('This value must be a sequential array');
throw new DataValidationException(sprintf('%s must be a sequential array', $prettyName));
}
}

/**
* Validate that array is sequential
*
* @param array $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @throws DataValidationException
*/
public function validateSequentialArray(array $data)
public function validateSequentialArray(array $data, $prettyName = 'This value')
{
//if the array has to have keys that are both numeric AND sequential
if (!empty($data) && array_keys($data) !== range(0, count($data) - 1)) {
throw new DataValidationException('This value is an array but it is not sequential');
throw new DataValidationException(sprintf('%s is an array but it is not sequential', $prettyName));
}
}
}
14 changes: 8 additions & 6 deletions src/TypeValidator/NumberValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,35 @@ class NumberValidator extends AbstractTypeValidator
*
* @param array $constraints The rules
* @param mixed $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @return boolean Wether it was valid or not
*/
public function validate(array $constraints, $data)
public function validate(array $constraints, $data, $prettyName = 'This value')
{
if (is_numeric($data) == false) {
throw new DataValidationException('This value must be a number');
throw new DataValidationException(sprintf('%s must be a number', $prettyName));
}

if (isset($constraints['integer'])) {
$this->validateInteger($data, $constraints['integer']);
$this->validateInteger($data, $constraints['integer'], $prettyName);
}

parent::validate($constraints, $data);
parent::validate($constraints, $data, $prettyName);
}

/**
* Validate that the data is/is not an integer
*
* @param array $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @throws DataValidationException
*/
public function validateInteger($data, $isInt)
public function validateInteger($data, $isInt, $prettyName = 'This value')
{
if ($isInt != is_int($data)) {
throw new DataValidationException('This value must '.($isInt == false?'not':'').' be an integer');
throw new DataValidationException(sprintf('%s must '.($isInt == false?'not':'').' be an integer', $prettyName));
}
}
}
19 changes: 11 additions & 8 deletions src/TypeValidator/ObjectValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,48 +23,51 @@ class ObjectValidator extends AbstractTypeValidator
*
* @param array $constraints The rules
* @param mixed $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @return boolean Wether it was valid or not
*/
public function validate(array $constraints, $data)
public function validate(array $constraints, $data, $prettyName = 'This value')
{
if (gettype($data) == 'object') {
$this->validateObject($data);
} elseif (gettype($data) == 'array') {
$this->validateAssociativeArray($data);
$this->validateAssociativeArray($data, $prettyName);
} else {
throw new DataValidationException('This value must be a standard object or an associative array');
throw new DataValidationException(sprintf('%s must be a standard object or an associative array', $prettyName));
}

parent::validate($constraints, $data);
parent::validate($constraints, $data, $prettyName);
}

/**
* Validate that the data is an instance of the stdClass
*
* @param object $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @throws DataValidationException
*/
public function validateObject($data)
public function validateObject($data, $prettyName = 'This value')
{
if (!$data instanceof \stdClass) {
throw new DataValidationException('This value must be an instance of the stdClass');
throw new DataValidationException(sprintf('%s must be an instance of the stdClass', $prettyName));
}
}

/**
* Validate that the data is an associative array
*
* @param array $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @throws DataValidationException
*/
public function validateAssociativeArray(array $data)
public function validateAssociativeArray(array $data, $prettyName = 'This value')
{
//if the array has keys that are both numeric AND sequential then it is not associative
if (!empty($data) && array_keys($data) === range(0, count($data) - 1)) {
throw new DataValidationException('This value is an array but it is not associative');
throw new DataValidationException(sprintf('%s is an array but it is not associative', $prettyName));
}
}
}
15 changes: 8 additions & 7 deletions src/TypeValidator/StringValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,36 @@ class StringValidator extends AbstractTypeValidator
*
* @param array $constraints The rules
* @param mixed $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @return boolean Wether it was valid or not
*/
public function validate(array $constraints, $data)
public function validate(array $constraints, $data, $prettyName = 'This value')
{
if (gettype($data) != 'string') {
throw new DataValidationException('This value must be a string');
throw new DataValidationException(sprintf('%s must be a string', $prettyName));
}

if (isset($constraints['length'])) {
if (sizeof($constraints['length']) != 2) {
throw new InvalidRuleException('The length property needs to have two members');
}
$this->validateLength($data, $constraints['length'][0], $constraints['length'][1]);
$this->validateLength($data, $constraints['length'][0], $constraints['length'][1], $prettyName);
}

parent::validate($constraints, $data);
parent::validate($constraints, $data, $prettyName);
}

public function validateLength($data, $min = null, $max = null)
public function validateLength($data, $min = null, $max = null, $prettyName = 'This value')
{
$length = strlen($data);

if (isset($min) && $length < $min) {
throw new DataValidationException('This value must have a length of at least '.$min);
throw new DataValidationException(sprintf('%s must have a length of at least '.$min, $prettyName));
}

if (isset($max) && $length > $max) {
throw new DataValidationException('This value must have a length less than or equal to '.$max);
throw new DataValidationException(sprintf('%s must have a length less than or equal to '.$max, $prettyName));
}

return true;
Expand Down
3 changes: 2 additions & 1 deletion src/TypeValidator/TypeValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ interface TypeValidatorInterface
*
* @param array $constraints The rules
* @param mixed $data The data to validate
* @param mixed $prettyName Human readable name for the data being validated
*
* @return boolean Whether it was valid or not
*/
public function validate(array $constraints, $data);
public function validate(array $constraints, $data, $prettyName);
}
8 changes: 5 additions & 3 deletions src/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ public function validateData(array $validationRule, $itemKey, $data, $fullyQuali
}

if ($validationRule['required'] == true && $this->propertyExists($itemKey, $data) == false) {
throw new DataValidationException('This value is required');
$prettyName = isset($validationRule['name'])?$validationRule['name']:'This value';
throw new DataValidationException(sprintf('%s is required', $prettyName));
} elseif ($validationRule['required'] == false && $this->propertyExists($itemKey, $data) == false) {
//The item does not exist and is not required so no need to validate
return;
Expand All @@ -157,8 +158,9 @@ public function validateItem(array $validationRule, $item, $fullyQualifiedName)
{
$typeValidator = $this->getTypeValidator($validationRule['type']);

$constraints = isset($validationRule['constraints']) ? $validationRule['constraints'] : [];
$typeValidator->validate($constraints, $item);
$constraints = isset($validationRule['constraints']) ? $validationRule['constraints'] : [];
$prettyName = isset($validationRule['name'])?$validationRule['name']:'This value';
$typeValidator->validate($constraints, $item, $prettyName);

$validationType = $validationRule['type'];

Expand Down
18 changes: 11 additions & 7 deletions tests/phpunit/src/Functional/ValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public function validate($data, $valid, $errors)
{
$validationRules = [
'name' => [
'name' => 'Name',
'required' => true,
'type' => 'string',
'constraints' => [
Expand All @@ -30,13 +31,15 @@ public function validate($data, $valid, $errors)
]
],
'age' => [
'name' => 'Age',
'required' => false,
'type' => 'number',
'constraints' => [
'integer' => true
]
],
'address' => [
'name' => 'Address',
'required' => false,
'type' => 'object',
'properties' => [
Expand All @@ -61,6 +64,7 @@ public function validate($data, $valid, $errors)
]
],
'nickNames' => [
'name' => 'Nick Names',
'required' => false,
'type' => 'array',
'items' => [
Expand All @@ -82,19 +86,19 @@ public function validate($data, $valid, $errors)
public function dataToValidate()
{
return [
[[], false, ['name' => ['This value is required']]],
[['name' => null], false, ['name' => ['This value must be a string']]],
[['name' => 1], false, ['name' => ['This value must be a string']]],
[['name' => ''], false, ['name' => ['This value must have a length of at least 1']]],
[[], false, ['name' => ['Name is required']]],
[['name' => null], false, ['name' => ['Name must be a string']]],
[['name' => 1], false, ['name' => ['Name must be a string']]],
[['name' => ''], false, ['name' => ['Name must have a length of at least 1']]],
[['name' => 'Ken'], false, ['name' => ['This value must have two words']]],
[['name' => 'Ken Lalobo'], true, []],
[['name' => 'Ken Lalobo', 'age' => 'test'], false, ['age' => ['This value must be a number']]],
[['name' => 'Ken Lalobo', 'age' => 0.1], false, ['age' => ['This value must be an integer']]],
[['name' => 'Ken Lalobo', 'age' => 'test'], false, ['age' => ['Age must be a number']]],
[['name' => 'Ken Lalobo', 'age' => 0.1], false, ['age' => ['Age must be an integer']]],
[['name' => 'Ken Lalobo', 'age' => 102], true, []],
[
['name' => 'Ken Lalobo', 'age' => 102, 'address' => null],
false,
['address' => ['This value must be a standard object or an associative array']]
['address' => ['Address must be a standard object or an associative array']]
],
[
['name' => 'Ken Lalobo', 'age' => 102, 'address' => []],
Expand Down

0 comments on commit a6f96be

Please sign in to comment.