Merge pull request #104 from thinkjson/array-validation

Validation of nested arrays, closes #8
This commit is contained in:
Vance Lucas 2014-09-08 11:06:07 -05:00
commit 5d26fca5e5
3 changed files with 170 additions and 3 deletions

View File

@ -69,6 +69,23 @@ if($v->validate()) {
} }
``` ```
You may use dot syntax to access members of multi-dimensional arrays,
and an asterisk to validate each member of an array:
```php
$v = new Valitron\Validator(array('settings' => array(
array('threshold' => 50),
array('threshold' => 90)
)));
$v->rule('max', 'settings.*.threshold', 100);
if($v->validate()) {
echo "Yay! We're all good!";
} else {
// Errors
print_r($v->errors());
}
```
Setting language and language dir globally: Setting language and language dir globally:
```php ```php
@ -92,6 +109,7 @@ V::lang('ar');
* `accepted` - Checkbox or Radio must be accepted (yes, on, 1, true) * `accepted` - Checkbox or Radio must be accepted (yes, on, 1, true)
* `numeric` - Must be numeric * `numeric` - Must be numeric
* `integer` - Must be integer number * `integer` - Must be integer number
* `array` - Must be array
* `length` - String must be certain length * `length` - String must be certain length
* `lengthBetween` - String must be between given lengths * `lengthBetween` - String must be between given lengths
* `lengthMin` - String must be greater than given length * `lengthMin` - String must be greater than given length

View File

@ -186,6 +186,18 @@ class Validator
return $this->validateRequired($field, $value) && in_array($value, $acceptable, true); return $this->validateRequired($field, $value) && in_array($value, $acceptable, true);
} }
/**
* Validate that a field is an array
*
* @param string $field
* @param mixed $value
* @return bool
*/
protected function validateArray($field, $value)
{
return is_array($value);
}
/** /**
* Validate that a field is numeric * Validate that a field is numeric
* *
@ -772,6 +784,47 @@ class Validator
$this->_labels = array(); $this->_labels = array();
} }
private function get($data, $identifiers) {
$identifier = array_shift($identifiers);
// Glob match
if ($identifier === '*')
{
$values = array();
foreach($data as $row)
{
list($value, $multiple) = $this->get($row, $identifiers);
if ($multiple)
{
$values = array_merge($values, $value);
}
else
{
$values[] = $value;
}
}
return array($values, true);
}
// Dead end, abort
elseif ($identifier === NULL || ! isset($data[$identifier]))
{
return array(NULL, false);
}
// Match array element
elseif (count($identifiers) === 0)
{
return array($data[$identifier], false);
}
// We need to go deeper
else
{
return $this->get($data[$identifier], $identifiers);
}
}
/** /**
* Run validations and return boolean result * Run validations and return boolean result
* *
@ -781,10 +834,10 @@ class Validator
{ {
foreach ($this->_validations as $v) { foreach ($this->_validations as $v) {
foreach ($v['fields'] as $field) { foreach ($v['fields'] as $field) {
$value = isset($this->_fields[$field]) ? $this->_fields[$field] : null; list($values, $multiple) = $this->get($this->_fields, explode('.', $field));
// Don't validate if the field is not required and the value is empty // Don't validate if the field is not required and the value is empty
if ($v['rule'] !== 'required' && !$this->hasRule('required', $field) && (! isset($value) || $value === '')) { if ($v['rule'] !== 'required' && !$this->hasRule('required', $field) && (! isset($values) || $values === '' || ($multiple && count($values) == 0))) {
continue; continue;
} }
@ -795,7 +848,16 @@ class Validator
$callback = array($this, 'validate' . ucfirst($v['rule'])); $callback = array($this, 'validate' . ucfirst($v['rule']));
} }
$result = call_user_func($callback, $field, $value, $v['params']); if (! $multiple)
{
$values = array($values);
}
$result = true;
foreach($values as $value)
{
$result = $result && call_user_func($callback, $field, $value, $v['params']);
}
if (!$result) { if (!$result) {
$this->error($field, $v['message'], $v['params']); $this->error($field, $v['message'], $v['params']);
} }

View File

@ -273,6 +273,93 @@ class ValidateTest extends BaseTestCase
$this->assertTrue($v->validate()); $this->assertTrue($v->validate());
} }
public function testArrayValid()
{
$v = new Validator(array('colors' => array('yellow')));
$v->rule('array', 'colors');
$this->assertTrue($v->validate());
}
public function testAssocArrayValid()
{
$v = new Validator(array('settings' => array('color' => 'yellow')));
$v->rule('array', 'settings');
$this->assertTrue($v->validate());
}
public function testArrayInvalid()
{
$v = new Validator(array('colors' => 'yellow'));
$v->rule('array', 'colors');
$this->assertFalse($v->validate());
}
public function testArrayAccess()
{
$v = new Validator(array('settings' => array('enabled' => true)));
$v->rule('boolean', 'settings.enabled');
$this->assertTrue($v->validate());
}
public function testArrayAccessInvalid()
{
$v = new Validator(array('settings' => array('threshold' => 500)));
$v->rule('max', 'settings.threshold', 100);
$this->assertFalse($v->validate());
}
public function testForeachArrayAccess()
{
$v = new Validator(array('settings' => array(
array('enabled' => true),
array('enabled' => true)
)));
$v->rule('boolean', 'settings.*.enabled');
$this->assertTrue($v->validate());
}
public function testForeachArrayAccessInvalid()
{
$v = new Validator(array('settings' => array(
array('threshold' => 50),
array('threshold' => 500)
)));
$v->rule('max', 'settings.*.threshold', 100);
$this->assertFalse($v->validate());
}
public function testNestedForeachArrayAccess()
{
$v = new Validator(array('widgets' => array(
array('settings' => array(
array('enabled' => true),
array('enabled' => true)
)),
array('settings' => array(
array('enabled' => true),
array('enabled' => true)
))
)));
$v->rule('boolean', 'widgets.*.settings.*.enabled');
$this->assertTrue($v->validate());
}
public function testNestedForeachArrayAccessInvalid()
{
$v = new Validator(array('widgets' => array(
array('settings' => array(
array('threshold' => 50),
array('threshold' => 90)
)),
array('settings' => array(
array('threshold' => 40),
array('threshold' => 500)
))
)));
$v->rule('max', 'widgets.*.settings.*.threshold', 100);
$this->assertFalse($v->validate());
}
public function testInInvalid() public function testInInvalid()
{ {
$v = new Validator(array('color' => 'yellow')); $v = new Validator(array('color' => 'yellow'));