Skip to content

Commit

Permalink
Merge pull request #6589 from ping-yee/modify-validation-required_wit…
Browse files Browse the repository at this point in the history
…hout

fix: `required_without` rule logic in `Validation` class.
  • Loading branch information
kenjis authored Sep 30, 2022
2 parents dcdaa43 + 445f9fa commit ed0cdd0
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 13 deletions.
33 changes: 26 additions & 7 deletions system/Validation/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -279,29 +279,48 @@ public function required_with($str = null, ?string $fields = null, array $data =
* required_without[id,email]
*
* @param string|null $str
* @param string|null $otherFields The param fields of required_without[].
* @param string|null $field This rule param fields aren't present, this field is required.
*/
public function required_without($str = null, ?string $fields = null, array $data = []): bool
public function required_without($str = null, ?string $otherFields = null, array $data = [], ?string $error = null, ?string $field = null): bool
{
if ($fields === null || empty($data)) {
throw new InvalidArgumentException('You must supply the parameters: fields, data.');
if ($otherFields === null || empty($data)) {
throw new InvalidArgumentException('You must supply the parameters: otherFields, data.');
}

// If the field is present we can safely assume that
// the field is here, no matter whether the corresponding
// search field is present or not.
$fields = explode(',', $fields);
$present = $this->required($str ?? '');
$otherFields = explode(',', $otherFields);
$present = $this->required($str ?? '');

if ($present) {
return true;
}

// Still here? Then we fail this test if
// any of the fields are not present in $data
foreach ($fields as $field) {
if ((strpos($field, '.') === false && (! array_key_exists($field, $data) || empty($data[$field]))) || (strpos($field, '.') !== false && empty(dot_array_search($field, $data)))) {
foreach ($otherFields as $otherField) {
if ((strpos($otherField, '.') === false) && (! array_key_exists($otherField, $data) || empty($data[$otherField]))) {
return false;
}
if (strpos($otherField, '.') !== false) {
if ($field === null) {
throw new InvalidArgumentException('You must supply the parameters: field.');
}

$fieldData = dot_array_search($otherField, $data);
$fieldSplitArray = explode('.', $field);
$fieldKey = $fieldSplitArray[1];

if (is_array($fieldData)) {
return ! empty(dot_array_search($otherField, $data)[$fieldKey]);
}
$nowField = str_replace('*', $fieldKey, $otherField);
$nowFieldVaule = dot_array_search($nowField, $data);

return null !== $nowFieldVaule;
}
}

return true;
Expand Down
8 changes: 5 additions & 3 deletions system/Validation/StrictRules/Rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,12 @@ public function required_with($str = null, ?string $fields = null, array $data =
*
* required_without[id,email]
*
* @param mixed $str
* @param string|null $str
* @param string|null $otherFields The param fields of required_without[].
* @param string|null $field This rule param fields aren't present, this field is required.
*/
public function required_without($str = null, ?string $fields = null, array $data = []): bool
public function required_without($str = null, ?string $otherFields = null, array $data = [], ?string $error = null, ?string $field = null): bool
{
return $this->nonStrictRules->required_without($str, $fields, $data);
return $this->nonStrictRules->required_without($str, $otherFields, $data, $error, $field);
}
}
2 changes: 1 addition & 1 deletion system/Validation/Validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ protected function processRules(
$found = true;
$passed = $param === false
? $set->{$rule}($value, $error)
: $set->{$rule}($value, $param, $data, $error);
: $set->{$rule}($value, $param, $data, $error, $field);

break;
}
Expand Down
33 changes: 31 additions & 2 deletions tests/system/Validation/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1414,13 +1414,20 @@ public function testNestedArrayThrowsException(): void
'credit_amount' => null,
'purpose' => 'A',
],
'account_3' => [
'account_number' => '',
'credit_amount' => 2000,
'purpose' => '',
],
],
];
$this->validation->run($data);

$this->assertSame([
'beneficiaries_accounts.account_2.credit_amount' => 'The CREDIT AMOUNT field is required.',
'beneficiaries_accounts.account_2.purpose' => 'The PURPOSE field must be at least 3 characters in length.',
'beneficiaries_accounts.account_3.account_number' => 'The BENEFICIARY ACCOUNT NUMBER field must be exactly 5 characters in length.',
'beneficiaries_accounts.account_2.credit_amount' => 'The CREDIT AMOUNT field is required.',
'beneficiaries_accounts.account_2.purpose' => 'The PURPOSE field must be at least 3 characters in length.',
'beneficiaries_accounts.account_3.purpose' => 'The PURPOSE field is required when BENEFICIARY ACCOUNT NUMBER is not present.',
], $this->validation->getErrors());
}

Expand All @@ -1436,4 +1443,26 @@ public function testRuleWithLeadingAsterisk(): void
$this->assertFalse($this->validation->run($data));
$this->assertSame('Required *.foo', $this->validation->getError('*.foo'));
}

/**
* @see https://github.com/codeigniter4/CodeIgniter4/issues/5942
*/
public function testRequireWithoutWithWildCard()
{
$data = [
'a' => [
['b' => 1, 'c' => 2],
['c' => ''],
],
];

$this->validation->setRules([
'a.*.c' => 'required_without[a.*.b]',
])->run($data);

$this->assertSame(
'The a.*.c field is required when a.*.b is not present.',
$this->validation->getError('a.1.c')
);
}
}
1 change: 1 addition & 0 deletions user_guide_src/source/changelogs/v4.2.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ BREAKING

- The default values of the parameters in :php:func:`set_cookie()` and :php:meth:`CodeIgniter\\HTTP\\Response::setCookie()` has been fixed. Now the default values of ``$secure`` and ``$httponly`` are ``null``, and these values will be replaced with the ``Config\Cookie`` values.
- ``Time::__toString()`` is now locale-independent. It returns database-compatible strings like '2022-09-07 12:00:00' in any locale.
- The Validation rule ``Validation\Rule::required_without()`` and ``Validation\StrictRules\Rule::required_without()`` parameters have been changed and the logic of these rule has also been fixed.

Enhancements
************
Expand Down
1 change: 1 addition & 0 deletions user_guide_src/source/installation/upgrade_427.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Others
======

- ``Time::__toString()`` is now locale-independent. It returns database-compatible strings like '2022-09-07 12:00:00' in any locale. Most locales are not affected by this change. But in a few locales like `ar`, `fa`, ``Time::__toString()`` (or ``(string) $time`` or implicit casting to a string) no longer returns a localized datetime string. if you want to get a localized datetime string, use :ref:`Time::toDateTimeString() <time-todatetimestring>` instead.
- The logic of Validation rule ``required_without`` has been changed to validate each array item separately when validating fields with asterisk (``*``), and the method signature of the rule method has also been changed. Extending classes should likewise update the parameters so as not to break LSP.

Project Files
*************
Expand Down

0 comments on commit ed0cdd0

Please sign in to comment.