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());