Skip to content

Commit

Permalink
Merge d2f6e18 into 6b13de1
Browse files Browse the repository at this point in the history
  • Loading branch information
lalobo committed Apr 18, 2018
2 parents 6b13de1 + d2f6e18 commit 41de601
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 4 deletions.
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,72 @@ Each type also has additional properties.
]
]
]
```
with inheritance:

```
$rules = [
'animal' => [
'name' => 'Animal',
'required' => true,
'type' => 'object',
'properties' => [
'type' => [
'required' => true,
'type' => 'string',
'constraints' => [
'enum' => ['cat', 'dog']
]
],
'age' => [
'required' => true,
'type' => 'number',
'constraints' => [
'integer' => true
]
]
],
'inheritance' => [
'discriminator' => 'type',
'properties' => [
'cat' => [
'miceCaught' => [
'required' => true,
'type' => 'number',
'constraints' => [
'integer' => true
]
]
],
'dog' => [
'carsChased' => [
'required' => true,
'type' => 'number',
'constraints' => [
'integer' => true
]
],
'collar' => [
'required' => true,
'type' => 'object',
'properties' => [
'colour' => [
'required' => true,
'type' => 'string'
]
]
]
]
]
]
]
]
```
The object type validates the item as an associative array/standard object. it also has the following properties:
* **properties** [*array*] : an optional associative array of rules for the object's properties. You can use a wildcard rule here.
* **inheritance** [*object*] : optional. Used inheritance. The child objects' properties are defined here. This hs the following properties
* **discriminator** [*string*] this is required. the property on the parent that will act as a discriminator
* **properties** [*object*] The properties of the children organised by child name

- **array**

Expand Down
38 changes: 34 additions & 4 deletions src/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Mooti\Validator\Exception\DataValidationException;
use Mooti\Validator\Exception\InvalidTypeValidatorException;
use Mooti\Validator\TypeValidator\TypeValidatorInterface;
use Psr\Log\InvalidArgumentException;

class Validator
{
Expand Down Expand Up @@ -165,10 +166,10 @@ public function validateData(array $validationRule, $itemKey, $data, $fullyQuali
/**
* Validate a single item of data and any properties/items it has (if it is an object/array) using the given validation rule.
*
* @param array $validationRule The rule to validate against
* @param string $item The item to validate
* @param array $validationRule The rule to validate against
* @param string $item The item to validate
* @param string $fullyQualifiedName The fully qualified name of the item being validated
*
* @throws InvalidRuleException
*/
public function validateItem(array $validationRule, $item, $fullyQualifiedName)
{
Expand All @@ -180,8 +181,37 @@ public function validateItem(array $validationRule, $item, $fullyQualifiedName)

$validationType = $validationRule['type'];

if ($validationType == 'object' && isset($validationRule['inheritance']) && is_array($validationRule['inheritance'])) {
if (empty($validationRule['inheritance']['discriminator'])) {
throw new InvalidRuleException(sprintf('inheritance needs a discriminator in %s', $fullyQualifiedName));
}
$discriminator = $validationRule['inheritance']['discriminator'];
$discriminatorValue = $item->$discriminator ?? $item[$discriminator] ?? null;

$discriminatorRequired = $validationRule['properties'][$discriminator]['required'] ?? false;

if ($discriminatorRequired == false) {
throw new InvalidRuleException(sprintf(
'discriminator %s in %s is has to be a required value',
$discriminator,
$fullyQualifiedName
));
}
$extraProperties = $validationRule['inheritance']['properties'][strtolower($discriminatorValue)] ?? null;
} else {
$extraProperties = null;
}

if ($validationType == 'object' && isset($validationRule['properties']) && is_array($validationRule['properties'])) {
$this->isValid($validationRule['properties'], $item, $fullyQualifiedName);

if (!empty($extraProperties)) {
$properties = array_merge($validationRule['properties'], $extraProperties);
} else {
$properties = $validationRule['properties'];
}

$this->isValid($properties, $item, $fullyQualifiedName);

} elseif ($validationType == 'array' && isset($validationRule['items']) && is_array($validationRule['items'])) {
$this->isValid($validationRule['items'], $item, $fullyQualifiedName);
}
Expand Down
138 changes: 138 additions & 0 deletions tests/phpunit/src/Functional/ValidatorInheritenceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

namespace Mooti\Test\PHPUnit\Validator\Functional;

use Mooti\Validator\Validator;
use Mooti\Validator\Exception\DataValidationException;

class ValidatorInheritenceTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
* @dataProvider dataToValidate
*/
public function validate($data, $valid, $errors)
{
$validationRules = [
'animal' => [
'name' => 'Animal',
'required' => true,
'type' => 'object',
'properties' => [
'type' => [
'required' => true,
'type' => 'string',
'constraints' => [
'enum' => ['cat', 'dog']
]
],
'age' => [
'required' => true,
'type' => 'number',
'constraints' => [
'integer' => true
]
]
],
'inheritance' => [
'discriminator' => 'type',
'properties' => [
'cat' => [
'miceCaught' => [
'required' => true,
'type' => 'number',
'constraints' => [
'integer' => true
]
]
],
'dog' => [
'carsChased' => [
'required' => true,
'type' => 'number',
'constraints' => [
'integer' => true
]
],
'collar' => [
'required' => true,
'type' => 'object',
'properties' => [
'colour' => [
'required' => true,
'type' => 'string'
]
]
]
]
]
]
]
];

$validator = new Validator;
$this->assertEquals($valid, $validator->isValid($validationRules, $data));
$this->assertEquals($errors, $validator->getErrors());
}

public function dataToValidate()
{
return [
[[], false, ['animal' => ['Animal is required']]],
[['animal' => []], false, [
'animal.type' => ['This value is required'],
'animal.age' => ['This value is required']
]],
[['animal' => [
'type' => 'aardvark',
'age' => 2
]], false, [
'animal.type' => [
'aardvark is not an allowed value for This value. Allowed values are: cat, dog'
]
]],
[['animal' => [
'type' => 'cat',
'age' => 2
]], false, [
'animal.miceCaught' => [
'This value is required'
]
]],
[['animal' => [
'type' => 'cat',
'age' => 2,
'miceCaught' => 3
]], true, []],
[['animal' => [
'type' => 'dog',
'age' => 3
]], false, [
'animal.carsChased' => [
'This value is required'
],
'animal.collar' => [
'This value is required'
]
]],
[['animal' => [
'type' => 'dog',
'age' => 3,
'carsChased' => 3,
'collar' => []
]], false, [
'animal.collar.colour' => [
'This value is required'
]
]],
[['animal' => [
'type' => 'dog',
'age' => 3,
'carsChased' => 3,
'collar' => [
'colour' => 'red'
]
]], true, []]
];
}
}

0 comments on commit 41de601

Please sign in to comment.