Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: required_without rule logic in Validation class. #6589

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
kenjis marked this conversation as resolved.
Show resolved Hide resolved
{
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 Rule of :php:func:`Validation\\Rule::required_without()` parameters are changed and this rule logic is fixed.
kenjis marked this conversation as resolved.
Show resolved Hide resolved

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 rule of ``required_without`` logic is changed to validate each array separately, and the name of parameters are also changed.
kenjis marked this conversation as resolved.
Show resolved Hide resolved

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