required-conditionals; adding requiredwith and requiredWithout for conditional requirements

This commit is contained in:
Tom Breese 2018-10-14 15:27:37 -04:00
parent 661365f317
commit 17c2f05168
4 changed files with 491 additions and 3 deletions

115
README.md
View File

@ -125,11 +125,30 @@ V::lang('ar');
``` ```
You can conditionally require values using required conditional rules. In this example we're requiring either a token or an email address/password combination for authentication.
```php
// this rule set would work for either data set...
$data = ['email' => 'test@test.com', 'password' => 'mypassword'];
// or...
$data = ['token' => 'jashdjahs83rufh89y38h38h'];
$v = new Valitron\Validator($data);
$v->rules([
'requiredWithout' => [
['token', ['email', 'password']]
],
'requiredWith' => []
['password', ['email']]
]
]);
$this->assertTrue($v->validate());
```
## Built-in Validation Rules ## Built-in Validation Rules
* `required` - Field is required * `required` - Field is required
* `requiredWith` - Field is required if any other fields are present
* `requiredWithout` - Field is required if any other fields are NOT present
* `equals` - Field must match another field (email/password confirmation) * `equals` - Field must match another field (email/password confirmation)
* `different` - Field must be different than another field * `different` - Field must be different than another field
* `accepted` - Checkbox or Radio must be accepted (yes, on, 1, true) * `accepted` - Checkbox or Radio must be accepted (yes, on, 1, true)
@ -198,7 +217,101 @@ $v->rules([
$v->validate(); $v->validate();
``` ```
Example using alternate syntax. ## requiredWith fields usage
The `requiredWith` rule checks that the field is required, not null, and not the empty string, if any other fields are present, not null, and not the empty string.
```php
// password field will be required when the username field is provided and not empty
$v->rule('requiredWith', 'password', 'username')
```
Alternate syntax.
```php
$v = new Valitron\Validator(['username' => 'spiderman', 'password' => 'Gr33nG0Blin']);
$v->rules([
'requiredWith' => [
['password', 'username']
]
]);
$v->validate();
```
*Note* You can provide multiple values either as comma-separated list or as an array. In this case if ANY of the fields are present the field will be required.
```php
// in this case the password field will be required if the username or email fields are present
$v->rule('requiredWith', 'password', 'username', 'email');
// this is the same as the above line
$v->rule('requiredWith', 'password', ['username', 'email']);
```
Alternate syntax.
```php
$v = new Valitron\Validator(['username' => 'spiderman', 'password' => 'Gr33nG0Blin']);
$v->rules([
'requiredWith' => [
['password', 'username', 'email']
]
]);
$v->validate();
```
This is the same as the above example:
```php
$v = new Valitron\Validator(['username' => 'spiderman', 'password' => 'Gr33nG0Blin']);
$v->rules([
'requiredWith' => [
['password', ['username', 'email']]
]
]);
$v->validate();
```
## requiredWithout fields usage
The `requiredWithout` rule checks that the field is required, not null, and not the empty string, if any other fields are NOT present.
```php
// this rule will require the username field when the first_name is not present
$v->rule('requiredWithout', 'username', 'first_name')
```
Alternate syntax.
```php
// this will return true, as the username is provided when the first_name is not provided
$v = new Valitron\Validator(['username' => 'spiderman']);
$v->rules([
'requiredWithout' => [
['username', 'first_name']
]
]);
$v->validate();
```
*Note* You can provide multiple values either as comma-separated list or as an array. In this case if ANY of the fields are NOT present the field will be required.
```php
// in this case the password field will be required if either the first_name or last_name fields are not present
$v->rule('requiredWithout', 'username', 'first_name', 'last_name');
// this is the same as the above line
$v->rule('requiredWithout', 'username', ['first_name', 'last_name']);
```
Alternate syntax.
```php
// this passes validation because although the last_name field is not present, the username is provided
$v = new Valitron\Validator(['username' => 'spiderman', 'first_name' => 'Peter']);
$v->rules([
'requiredWithout' => [
['username', 'first_name', 'last_name']
]
]);
$v->validate();
```
This is the same as the above example:
```php
$v = new Valitron\Validator(['username' => 'spiderman', 'first_name' => 'Peter']);
$v->rules([
'requiredWithout' => [
['username', ['first_name', 'last_name']]
]
]);
$v->validate();
```
## equals fields usage ## equals fields usage
The `equals` rule checks if two fields are equals in the data array, and that the second field is not null. The `equals` rule checks if two fields are equals in the data array, and that the second field is not null.

View File

@ -34,5 +34,7 @@ return array(
'lengthMax' => "must not exceed %d characters", 'lengthMax' => "must not exceed %d characters",
'instanceOf' => "must be an instance of '%s'", 'instanceOf' => "must be an instance of '%s'",
'containsUnique' => "must contain unique elements only", 'containsUnique' => "must contain unique elements only",
'requiredWith' => "is required",
'requiredWithout'=> "is required",
'subset' => "contains an item that is not in the list", 'subset' => "contains an item that is not in the list",
); );

View File

@ -897,6 +897,74 @@ class Validator
return $isInstanceOf; return $isInstanceOf;
} }
/**
* Validates whether or not a field is required based on whether or not other fields are present.
*
* @param string $field name of the field in the data array
* @param mixed $value value of this field
* @param array $params parameters for this rule
* @param array $fields full list of data to be validated
* @return bool
*/
protected function validateRequiredWith($field, $value, $params, $fields)
{
$conditionallyReq = false;
// correct for fields as comma list of params or array of params
// this will allow either to work
$params = isset($params[0]) && is_array($params[0]) ? $params[0] : $params;
// if we actually have conditionally required with fields to check against
if (count($params)) {
foreach ($params as $requiredField) {
// check the field is set, not null, and not the empty string
if (isset($fields[$requiredField]) && (!is_null($fields[$requiredField])
|| (is_string($fields[$requiredField]) && trim($fields[$requiredField]) !== ''))) {
$conditionallyReq = true;
break;
}
}
}
// if we have conditionally required fields
if ($conditionallyReq && (is_null($value) ||
is_string($value) && trim($value) === '')) {
return false;
}
return true;
}
/**
* Validates whether or not a field is required based on whether or not other fields are present.
*
* @param string $field name of the field in the data array
* @param mixed $value value of this field
* @param array $params parameters for this rule
* @param array $fields full list of data to be validated
* @return bool
*/
protected function validateRequiredWithout($field, $value, $params, $fields)
{
$conditionallyReq = false;
// correct for fields as comma list of params or array of params
// this will allow either to work
$params = isset($params[0]) && is_array($params[0]) ? $params[0] : $params;
// if we actually have conditionally required with fields to check against
if (count($params)) {
foreach ($params as $requiredField) {
// check the field is NOT set, null, or the empty string, in which case we are requiring this value be present
if (!isset($fields[$requiredField]) || (is_null($fields[$requiredField])
|| (is_string($fields[$requiredField]) && trim($fields[$requiredField]) === ''))) {
$conditionallyReq = true;
break;
}
}
}
// if we have conditionally required fields
if ($conditionallyReq && (is_null($value) ||
is_string($value) && trim($value) === '')) {
return false;
}
return true;
}
/** /**
* Validate optional field * Validate optional field
* *
@ -1051,8 +1119,9 @@ class Validator
foreach ($v['fields'] as $field) { foreach ($v['fields'] as $field) {
list($values, $multiple) = $this->getPart($this->_fields, explode('.', $field), false); list($values, $multiple) = $this->getPart($this->_fields, explode('.', $field), false);
// 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 and we don't have a conditionally required rule present on the field
if ($this->hasRule('optional', $field) && isset($values)) { if (($this->hasRule('optional', $field) && isset($values))
|| ($this->hasRule('requiredWith', $field) || $this->hasRule('requiredWithout', $field))) {
//Continue with execution below if statement //Continue with execution below if statement
} elseif ( } elseif (
$v['rule'] !== 'required' && !$this->hasRule('required', $field) && $v['rule'] !== 'required' && !$this->hasRule('required', $field) &&

View File

@ -2220,6 +2220,310 @@ class ValidateTest extends BaseTestCase
$this->assertFalse($v->validate()); $this->assertFalse($v->validate());
} }
public function testRequiredWithValid()
{
$v = new Validator(array('username' => 'tester', 'password' => 'mypassword'));
$v->rule('requiredWith', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithValidEmptyString()
{
$v = new Validator(array('username' => '', 'password' => 'mypassword'));
$v->rule('requiredWith', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithValidZeroValue()
{
$v = new Validator(array('username' => 0, 'password' => 'mypassword'));
$v->rule('requiredWith', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithValidNullValue()
{
$v = new Validator(array('username' => null, 'password' => 'mypassword'));
$v->rule('requiredWith', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithValidAltSyntax()
{
$v = new Validator(array('username' => 'tester', 'password' => 'mypassword'));
$v->rules(array(
'requiredWith' => array(
array('password', 'username')
)
));
$this->assertTrue($v->validate());
}
public function testRequiredWithValidList()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com', 'password' => 'mypassword'));
$v->rule('requiredWith', 'password', 'username', 'email');
$this->assertTrue($v->validate());
}
public function testRequiredWithValidListAltSyntax()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com', 'password' => 'mypassword'));
$v->rules(array(
'requiredWith' => array(
array('password', 'username', 'email')
)
));
$this->assertTrue($v->validate());
}
public function testRequiredWithValidListArray()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com', 'password' => 'mypassword'));
$v->rule('requiredWith', 'password', array('username', 'email'));
$this->assertTrue($v->validate());
}
public function testRequiredWithValidListArrayAltSyntax()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com', 'password' => 'mypassword'));
$v->rules(array(
'requiredWith' => array(
array('password', array('username', 'email'))
)
));
$this->assertTrue($v->validate());
}
public function testRequiredWithInvalid()
{
$v = new Validator(array('username' => 'tester'));
$v->rule('requiredWith', 'password', 'username');
$this->assertFalse($v->validate());
}
public function testRequiredWithInvalidAltSyntax()
{
$v = new Validator(array('username' => 'tester'));
$v->rules(array(
'requiredWith' => array(
array('password', 'username')
)
));
$this->assertFalse($v->validate());
}
public function testRequiredWithInvalidList()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com'));
$v->rule('requiredWith', 'password', 'username', 'email');
$this->assertFalse($v->validate());
}
public function testRequiredWithInvalidListAltSyntax()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com'));
$v->rules(array(
'requiredWith' => array(
array('password', 'username', 'email')
)
));
$this->assertFalse($v->validate());
}
public function testRequiredWithInvalidListArray()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com'));
$v->rule('requiredWith', 'password', array('username', 'email'));
$this->assertFalse($v->validate());
}
public function testRequiredWithInvalidListArrayAltSyntax()
{
$v = new Validator(array('username' => 'tester', 'email' => 'test@test.com'));
$v->rules(array(
'requiredWith' => array(
array('password', array('username', 'email'))
)
));
$this->assertFalse($v->validate());
}
// required without tests
public function testRequiredWithoutValid()
{
$v = new Validator(array('password' => 'mypassword'));
$v->rule('requiredWithout', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidEmptyString()
{
$v = new Validator(array('username' => '', 'password' => 'mypassword'));
$v->rule('requiredWithout', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidZeroValue()
{
$v = new Validator(array('username' => 0, 'password' => 'mypassword'));
$v->rule('requiredWithout', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidNullValue()
{
$v = new Validator(array('username' => null, 'password' => 'mypassword'));
$v->rule('requiredWithout', 'password', 'username');
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidAltSyntax()
{
$v = new Validator(array('password' => 'mypassword'));
$v->rules(array(
'requiredWithout' => array(
array('password', 'username')
)
));
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidList()
{
$v = new Validator(array('password' => 'mypassword'));
$v->rule('requiredWithout', 'password', 'username', 'email');
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidListAltSyntax()
{
$v = new Validator(array('password' => 'mypassword'));
$v->rules(array(
'requiredWithout' => array(
array('password', 'username', 'email')
)
));
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidListArray()
{
$v = new Validator(array('password' => 'mypassword'));
$v->rule('requiredWithout', 'password', array('username', 'email'));
$this->assertTrue($v->validate());
}
public function testRequiredWithoutValidListArrayAltSyntax()
{
$v = new Validator(array('password' => 'mypassword'));
$v->rules(array(
'requiredWithout' => array(
array('password', array('username', 'email'))
)
));
$this->assertTrue($v->validate());
}
public function testRequiredWithoutInvalid()
{
$v = new Validator(array('username' => 'tester'));
$v->rule('requiredWithout', 'password', 'username', 'email');
$this->assertFalse($v->validate());
}
public function testRequiredWithoutInvalidAltSyntax()
{
$v = new Validator(array('username' => 'tester'));
$v->rules(array(
'requiredWithout' => array(
array('password', 'username', 'email')
)
));
$this->assertFalse($v->validate());
}
public function testRequiredWithoutInvalidList()
{
$v = new Validator(array());
$v->rule('requiredWithout', 'password', 'username', 'email');
$this->assertFalse($v->validate());
}
public function testRequiredWithoutInvalidListAltSyntax()
{
$v = new Validator(array('email' => 'test@test.com'));
$v->rules(array(
'requiredWithout' => array(
array('password', 'username', 'email')
)
));
$this->assertFalse($v->validate());
}
public function testRequiredWithoutInvalidListArray()
{
$v = new Validator(array('username' => 'tester'));
$v->rule('requiredWithout', 'password', array('username', 'email'));
$this->assertFalse($v->validate());
}
public function testRequiredWithoutInvalidListArrayAltSyntax()
{
$v = new Validator(array('email' => 'test@test.com'));
$v->rules(array(
'requiredWithout' => array(
array('password', array('username', 'email'))
)
));
$this->assertFalse($v->validate());
}
public function testConditionallyRequiredAuthSampleToken()
{
$v = new Validator(array('token' => 'ajkdhieyf2834fsuhf8934y89'));
$v->rule('requiredWithout', 'token', array('email', 'password'));
$v->rule('requiredWith', 'password', 'email');
$this->assertTrue($v->validate());
}
public function testConditionallyRequiredAuthSampleTokenAltSyntax()
{
$v = new Validator(array('token' => 'ajkdhieyf2834fsuhf8934y89'));
$v->rules(array(
'requiredWithout' => array(
array('token', array('email', 'password'))
),
'requiredWith' => array(
array('password', array('email'))
)
));
$this->assertTrue($v->validate());
}
public function testConditionallyRequiredAuthSampleEmailPassword()
{
$v = new Validator(array('email' => 'test@test.com', 'password' => 'mypassword'));
$v->rule('requiredWithout', 'token', array('email', 'password'));
$v->rule('requiredWith', 'password', 'email');
$this->assertTrue($v->validate());
}
public function testConditionallyRequiredAuthSampleEmailPasswordAltSyntax()
{
$v = new Validator(array('email' => 'test@test.com', 'password' => 'mypassword'));
$v->rules(array(
'requiredWithout' => array(
array('token', array('email', 'password'))
),
'requiredWith' => array(
array('password', array('email'))
)
));
$this->assertTrue($v->validate());
}
/** /**
* @dataProvider dataProviderFor_testError * @dataProvider dataProviderFor_testError
*/ */