From 17c2f05168a49100bd356bcfca1204a71a937263 Mon Sep 17 00:00:00 2001 From: Tom Breese Date: Sun, 14 Oct 2018 15:27:37 -0400 Subject: [PATCH 1/6] required-conditionals; adding requiredwith and requiredWithout for conditional requirements --- README.md | 115 +++++++++++- lang/en.php | 2 + src/Valitron/Validator.php | 73 +++++++- tests/Valitron/ValidateTest.php | 304 ++++++++++++++++++++++++++++++++ 4 files changed, 491 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9eb0f82..0b199a5 100644 --- a/README.md +++ b/README.md @@ -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 * `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) * `different` - Field must be different than another field * `accepted` - Checkbox or Radio must be accepted (yes, on, 1, true) @@ -198,7 +217,101 @@ $v->rules([ $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 The `equals` rule checks if two fields are equals in the data array, and that the second field is not null. diff --git a/lang/en.php b/lang/en.php index 0c9e5a1..ba062b0 100644 --- a/lang/en.php +++ b/lang/en.php @@ -34,5 +34,7 @@ return array( 'lengthMax' => "must not exceed %d characters", 'instanceOf' => "must be an instance of '%s'", 'containsUnique' => "must contain unique elements only", + 'requiredWith' => "is required", + 'requiredWithout'=> "is required", 'subset' => "contains an item that is not in the list", ); diff --git a/src/Valitron/Validator.php b/src/Valitron/Validator.php index 93c06be..738d21a 100644 --- a/src/Valitron/Validator.php +++ b/src/Valitron/Validator.php @@ -897,6 +897,74 @@ class Validator 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 * @@ -1051,8 +1119,9 @@ class Validator foreach ($v['fields'] as $field) { list($values, $multiple) = $this->getPart($this->_fields, explode('.', $field), false); - // Don't validate if the field is not required and the value is empty - if ($this->hasRule('optional', $field) && isset($values)) { + // 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)) + || ($this->hasRule('requiredWith', $field) || $this->hasRule('requiredWithout', $field))) { //Continue with execution below if statement } elseif ( $v['rule'] !== 'required' && !$this->hasRule('required', $field) && diff --git a/tests/Valitron/ValidateTest.php b/tests/Valitron/ValidateTest.php index 169c0e6..d1cfab1 100644 --- a/tests/Valitron/ValidateTest.php +++ b/tests/Valitron/ValidateTest.php @@ -2220,6 +2220,310 @@ class ValidateTest extends BaseTestCase $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 */ From c8c428b3cd80254d9cca2602f8a76692ca601676 Mon Sep 17 00:00:00 2001 From: Tom Breese Date: Sun, 14 Oct 2018 15:30:13 -0400 Subject: [PATCH 2/6] required-conditionals; fixing missing semi colon in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b199a5..0433da0 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ $v->validate(); 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') +$v->rule('requiredWith', 'password', 'username'); ``` Alternate syntax. From e3c6331380e0c5eec7ef29183aac52c7a36886e5 Mon Sep 17 00:00:00 2001 From: Tom Breese Date: Sun, 14 Oct 2018 15:32:30 -0400 Subject: [PATCH 3/6] required-conditionals; fixing field typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0433da0..af970f7 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ $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 +// in this case the username 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']); From 757b07f3cd00632d5198c4cdbe40e40f7fef287e Mon Sep 17 00:00:00 2001 From: Tom Breese Date: Mon, 15 Oct 2018 22:32:48 -0400 Subject: [PATCH 4/6] required-conditionals; adding strict for requiredWithAll and requiredWithoutAll --- .gitignore | 1 + README.md | 72 +++++++-- src/Valitron/Validator.php | 52 +++++-- tests/Valitron/ValidateTest.php | 264 ++++++++++++++++++-------------- 4 files changed, 238 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index 17193f5..b670dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ composer.phar composer.lock vendor .idea/ +/nbproject/private/ \ No newline at end of file diff --git a/README.md b/README.md index af970f7..f0df53c 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ 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. +You can conditionally require values using required conditional rules. In this example, for authentication, we're requiring either a token when both the email and password are not present, or a password when the email address is present. ```php // this rule set would work for either data set... $data = ['email' => 'test@test.com', 'password' => 'mypassword']; @@ -135,10 +135,16 @@ $data = ['token' => 'jashdjahs83rufh89y38h38h']; $v = new Valitron\Validator($data); $v->rules([ 'requiredWithout' => [ - ['token', ['email', 'password']] + ['token', ['email', 'password'], true] ], - 'requiredWith' => [] + 'requiredWith' => [ ['password', ['email']] + ], + 'email' => [ + ['email'] + ] + 'optional' => [ + ['email'] ] ]); $this->assertTrue($v->validate()); @@ -235,11 +241,9 @@ $v->rules([ $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. +*Note* You can provide multiple values 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']); ``` @@ -248,17 +252,35 @@ Alternate syntax. $v = new Valitron\Validator(['username' => 'spiderman', 'password' => 'Gr33nG0Blin']); $v->rules([ 'requiredWith' => [ - ['password', 'username', 'email'] + ['password', ['username', 'email']] ] ]); $v->validate(); ``` -This is the same as the above example: + +### Strict flag +The strict flag will change the `requiredWith` rule to `requiredWithAll` which will require the field only if ALL of the other fields are present, not null, and not the empty string. ```php -$v = new Valitron\Validator(['username' => 'spiderman', 'password' => 'Gr33nG0Blin']); +// in this example the suffix field is required only when both the first_name and last_name are provided +$v->rule('requiredWith', 'suffix', ['first_name', 'last_name'], true); +``` +Alternate syntax. +```php +$v = new Valitron\Validator(['first_name' => 'steve', 'last_name' => 'holt', 'suffix' => 'Mr']); $v->rules([ 'requiredWith' => [ - ['password', ['username', 'email']] + ['suffix', ['first_name', 'last_name'], true] + ] +]); +$v->validate(); +``` + +Likewise, in this case `validate()` would still return true, as the suffix field would not be required in strict mode, as not all of the fields are provided. +```php +$v = new Valitron\Validator(['first_name' => 'steve']); +$v->rules([ + 'requiredWith' => [ + ['suffix', ['first_name', 'last_name'], true] ] ]); $v->validate(); @@ -283,11 +305,9 @@ $v->rules([ $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. +*Note* You can provide multiple values as an array. In this case if ANY of the fields are NOT present the field will be required. ```php // in this case the username 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']); ``` @@ -297,17 +317,35 @@ Alternate syntax. $v = new Valitron\Validator(['username' => 'spiderman', 'first_name' => 'Peter']); $v->rules([ 'requiredWithout' => [ - ['username', 'first_name', 'last_name'] + ['username', ['first_name', 'last_name']] ] ]); $v->validate(); ``` -This is the same as the above example: + +### Strict flag +The strict flag will change the `requiredWithout` rule to `requiredWithoutAll` which will require the field only if ALL of the other fields are not present. ```php -$v = new Valitron\Validator(['username' => 'spiderman', 'first_name' => 'Peter']); +// in this example the username field is required only when both the first_name and last_name are not provided +$v->rule('requiredWithout', 'username', ['first_name', 'last_name'], true); +``` +Alternate syntax. +```php +$v = new Valitron\Validator(['username' => 'BatMan']); $v->rules([ 'requiredWithout' => [ - ['username', ['first_name', 'last_name']] + ['username', ['first_name', 'last_name'], true] + ] +]); +$v->validate(); +``` + +Likewise, in this case `validate()` would still return true, as the username field would not be required in strict mode, as all of the fields are provided. +```php +$v = new Valitron\Validator(['first_name' => 'steve', 'last_name' => 'holt']); +$v->rules([ + 'requiredWithout' => [ + ['suffix', ['first_name', 'last_name'], true] ] ]); $v->validate(); diff --git a/src/Valitron/Validator.php b/src/Valitron/Validator.php index 738d21a..b23e31a 100644 --- a/src/Valitron/Validator.php +++ b/src/Valitron/Validator.php @@ -909,19 +909,29 @@ class Validator 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) { + if (isset($params[0])) { + // convert single value to array if it isn't already + $reqParams = is_array($params[0]) ? $params[0] : array($params[0]); + // check for the flag indicating if all fields are required + $allRequired = isset($params[1]) && (bool)$params[1]; + $emptyFields = 0; + foreach ($reqParams 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 (isset($fields[$requiredField]) && !is_null($fields[$requiredField]) + && (is_string($fields[$requiredField]) ? trim($fields[$requiredField]) !== '' : true)) { + if (!$allRequired) { + $conditionallyReq = true; + break; + } else { + $emptyFields++; + } } } + // if all required fields are present in strict mode, we're requiring it + if ($allRequired && $emptyFields === count($reqParams)) { + $conditionallyReq = true; + } } // if we have conditionally required fields if ($conditionallyReq && (is_null($value) || @@ -943,19 +953,29 @@ class Validator 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) { + if (count($params[0])) { + // convert single value to array if it isn't already + $reqParams = is_array($params[0]) ? $params[0] : array($params[0]); + // check for the flag indicating if all fields are required + $allEmpty = isset($params[1]) && (bool)$params[1]; + $filledFields = 0; + foreach ($reqParams 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 (!$allEmpty) { + $conditionallyReq = true; + break; + } else { + $filledFields++; + } } } + // if all fields were empty, then we're requiring this in strict mode + if ($allEmpty && $filledFields === count($reqParams)) { + $conditionallyReq = true; + } } // if we have conditionally required fields if ($conditionallyReq && (is_null($value) || diff --git a/tests/Valitron/ValidateTest.php b/tests/Valitron/ValidateTest.php index d1cfab1..6c43d27 100644 --- a/tests/Valitron/ValidateTest.php +++ b/tests/Valitron/ValidateTest.php @@ -2227,23 +2227,23 @@ class ValidateTest extends BaseTestCase $this->assertTrue($v->validate()); } - public function testRequiredWithValidEmptyString() + public function testRequiredWithValidNoParams() { - $v = new Validator(array('username' => '', 'password' => 'mypassword')); + $v = new Validator(array()); $v->rule('requiredWith', 'password', 'username'); $this->assertTrue($v->validate()); } - public function testRequiredWithValidZeroValue() + public function testRequiredWithValidEmptyString() { - $v = new Validator(array('username' => 0, 'password' => 'mypassword')); + $v = new Validator(array('username' => '')); $v->rule('requiredWith', 'password', 'username'); $this->assertTrue($v->validate()); } public function testRequiredWithValidNullValue() { - $v = new Validator(array('username' => null, 'password' => 'mypassword')); + $v = new Validator(array('username' => null)); $v->rule('requiredWith', 'password', 'username'); $this->assertTrue($v->validate()); } @@ -2259,34 +2259,51 @@ class ValidateTest extends BaseTestCase $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() + public function testRequiredWithValidArray() { $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() + public function testRequiredWithStrictValidArray() { $v = new Validator(array('username' => 'tester', 'email' => 'test@test.com', 'password' => 'mypassword')); + $v->rule('requiredWith', 'password', array('username', 'email'), true); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithStrictInvalidArray() + { + $v = new Validator(array('email' => 'test@test.com', 'username' => 'batman')); + $v->rule('requiredWith', 'password', array('username', 'email'), true); + $this->assertFalse($v->validate()); + } + + public function testRequiredWithStrictValidArrayNotRequired() + { + $v = new Validator(array('username' => 'tester', 'email' => 'test@test.com')); + $v->rule('requiredWith', 'password', array('username', 'email', 'nickname'), true); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithStrictValidArrayEmptyValues() + { + $v = new Validator(array('email' => '', 'username' => null)); + $v->rule('requiredWith', 'password', array('username', 'email'), true); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithStrictInvalidArraySingleValue() + { + $v = new Validator(array('email' => 'tester', 'username' => null)); + $v->rule('requiredWith', 'password', array('username', 'email'), true); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithValidArrayAltSyntax() + { + $v = new Validator(array('password' => 'mypassword')); $v->rules(array( 'requiredWith' => array( array('password', array('username', 'email')) @@ -2313,37 +2330,37 @@ class ValidateTest extends BaseTestCase $this->assertFalse($v->validate()); } - public function testRequiredWithInvalidList() + public function testRequiredWithInvalidArray() { - $v = new Validator(array('username' => 'tester', 'email' => 'test@test.com')); - $v->rule('requiredWith', 'password', 'username', 'email'); + $v = new Validator(array('email' => 'test@test.com', 'nickname' => 'kevin')); + $v->rule('requiredWith', 'password', array('username', 'email', 'nickname')); $this->assertFalse($v->validate()); } - public function testRequiredWithInvalidListAltSyntax() + public function testRequiredWithInvalidStrictArray() + { + $v = new Validator(array('email' => 'test@test.com', 'username' => 'batman', 'nickname' => 'james')); + $v->rule('requiredWith', 'password', array('username', 'email', 'nickname'), true); + $this->assertFalse($v->validate()); + } + + public function testRequiredWithInvalidArrayAltSyntax() { $v = new Validator(array('username' => 'tester', 'email' => 'test@test.com')); $v->rules(array( 'requiredWith' => array( - array('password', 'username', 'email') + array('password', array('username', 'email', 'nickname')) ) )); $this->assertFalse($v->validate()); } - public function testRequiredWithInvalidListArray() + public function testRequiredWithStrictInvalidArrayAltSyntax() { - $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 = new Validator(array('username' => 'tester', 'email' => 'test@test.com', 'nickname' => 'joseph')); $v->rules(array( 'requiredWith' => array( - array('password', array('username', 'email')) + array('password', array('username', 'email', 'nickname'), true) ) )); $this->assertFalse($v->validate()); @@ -2358,6 +2375,13 @@ class ValidateTest extends BaseTestCase $this->assertTrue($v->validate()); } + public function testRequiredWithoutInvalidNotPresent() + { + $v = new Validator(array()); + $v->rule('requiredWithout', 'password', 'username'); + $this->assertFalse($v->validate()); + } + public function testRequiredWithoutValidEmptyString() { $v = new Validator(array('username' => '', 'password' => 'mypassword')); @@ -2365,11 +2389,11 @@ class ValidateTest extends BaseTestCase $this->assertTrue($v->validate()); } - public function testRequiredWithoutValidZeroValue() + public function testRequiredWithoutInvalidEmptyStringNotPresent() { - $v = new Validator(array('username' => 0, 'password' => 'mypassword')); + $v = new Validator(array('username' => '')); $v->rule('requiredWithout', 'password', 'username'); - $this->assertTrue($v->validate()); + $this->assertFalse($v->validate()); } public function testRequiredWithoutValidNullValue() @@ -2379,6 +2403,13 @@ class ValidateTest extends BaseTestCase $this->assertTrue($v->validate()); } + public function testRequiredWithoutInvlidNullValueNotPresent() + { + $v = new Validator(array('username' => null)); + $v->rule('requiredWithout', 'password', 'username'); + $this->assertFalse($v->validate()); + } + public function testRequiredWithoutValidAltSyntax() { $v = new Validator(array('password' => 'mypassword')); @@ -2390,94 +2421,75 @@ class ValidateTest extends BaseTestCase $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() + public function testRequiredWithoutInvalidAltSyntaxNotPresent() { $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') + array('password', 'username') ) )); $this->assertFalse($v->validate()); } - public function testRequiredWithoutInvalidListArray() + public function testRequiredWithoutValidArray() { - $v = new Validator(array('username' => 'tester')); + $v = new Validator(array('password' => 'mypassword')); + $v->rule('requiredWithout', 'password', array('username', 'email')); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithoutInvalidArrayNotPresent() + { + $v = new Validator(array()); $v->rule('requiredWithout', 'password', array('username', 'email')); $this->assertFalse($v->validate()); } - public function testRequiredWithoutInvalidListArrayAltSyntax() + public function testRequiredWithoutValidArrayPartial() + { + $v = new Validator(array('password' => 'mypassword', 'email' => 'test@test.com')); + $v->rule('requiredWithout', 'password', array('username', 'email')); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithoutInvalidArrayPartial() { $v = new Validator(array('email' => 'test@test.com')); + $v->rule('requiredWithout', 'password', array('username', 'email')); + $this->assertFalse($v->validate()); + } + + public function testRequiredWithoutValidArrayStrict() + { + $v = new Validator(array('email' => 'test@test.com')); + $v->rule('requiredWithout', 'password', array('username', 'email'), true); + $this->assertTrue($v->validate()); + } + + public function testRequiredWithoutInvalidArrayStrict() + { + $v = new Validator(array()); + $v->rule('requiredWithout', 'password', array('username', 'email'), true); + $this->assertFalse($v->validate()); + } + + public function testRequiredWithoutInvalidArrayNotProvided() + { + $v = new Validator(array('email' => 'test@test.com')); + $v->rule('requiredWithout', 'password', array('username', 'email')); + $this->assertFalse($v->validate()); + } + + public function testRequiredWithoutValidArrayAltSyntax() + { + $v = new Validator(array('password' => 'mypassword')); $v->rules(array( 'requiredWithout' => array( array('password', array('username', 'email')) ) )); - $this->assertFalse($v->validate()); + $this->assertTrue($v->validate()); } public function testConditionallyRequiredAuthSampleToken() @@ -2485,9 +2497,21 @@ class ValidateTest extends BaseTestCase $v = new Validator(array('token' => 'ajkdhieyf2834fsuhf8934y89')); $v->rule('requiredWithout', 'token', array('email', 'password')); $v->rule('requiredWith', 'password', 'email'); + $v->rule('email', 'email'); + $v->rule('optional', 'email'); $this->assertTrue($v->validate()); } + public function testConditionallyRequiredAuthSampleMissingPassword() + { + $v = new Validator(array('email' => 'test@test.com')); + $v->rule('requiredWithout', 'token', array('email', 'password')); + $v->rule('requiredWith', 'password', 'email'); + $v->rule('email', 'email'); + $v->rule('optional', 'email'); + $this->assertFalse($v->validate()); + } + public function testConditionallyRequiredAuthSampleTokenAltSyntax() { $v = new Validator(array('token' => 'ajkdhieyf2834fsuhf8934y89')); @@ -2497,19 +2521,17 @@ class ValidateTest extends BaseTestCase ), 'requiredWith' => array( array('password', array('email')) + ), + 'email' => array( + array('email') + ), + 'optional' => array( + 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')); @@ -2519,6 +2541,12 @@ class ValidateTest extends BaseTestCase ), 'requiredWith' => array( array('password', array('email')) + ), + 'email' => array( + array('email') + ), + 'optional' => array( + array('email') ) )); $this->assertTrue($v->validate()); From ee4abd9a5ff701d0278adc39b205f93964844a2c Mon Sep 17 00:00:00 2001 From: Tom Breese Date: Mon, 15 Oct 2018 22:41:14 -0400 Subject: [PATCH 5/6] required-conditionals; fixing count to isset --- src/Valitron/Validator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Valitron/Validator.php b/src/Valitron/Validator.php index b23e31a..959d9b3 100644 --- a/src/Valitron/Validator.php +++ b/src/Valitron/Validator.php @@ -954,7 +954,7 @@ class Validator { $conditionallyReq = false; // if we actually have conditionally required with fields to check against - if (count($params[0])) { + if (isset($params[0])) { // convert single value to array if it isn't already $reqParams = is_array($params[0]) ? $params[0] : array($params[0]); // check for the flag indicating if all fields are required From 6f125ff66606bf140192ce4ec119b98777c86524 Mon Sep 17 00:00:00 2001 From: Tom Breese Date: Mon, 15 Oct 2018 22:42:49 -0400 Subject: [PATCH 6/6] removing gitignore for netbeans project --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index b670dd0..17193f5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ composer.phar composer.lock vendor .idea/ -/nbproject/private/ \ No newline at end of file