Skip to content

Commit ed0cdd0

Browse files
authored
Merge pull request #6589 from ping-yee/modify-validation-required_without
fix: `required_without` rule logic in `Validation` class.
2 parents dcdaa43 + 445f9fa commit ed0cdd0

File tree

6 files changed

+65
-13
lines changed

6 files changed

+65
-13
lines changed

system/Validation/Rules.php

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,29 +279,48 @@ public function required_with($str = null, ?string $fields = null, array $data =
279279
* required_without[id,email]
280280
*
281281
* @param string|null $str
282+
* @param string|null $otherFields The param fields of required_without[].
283+
* @param string|null $field This rule param fields aren't present, this field is required.
282284
*/
283-
public function required_without($str = null, ?string $fields = null, array $data = []): bool
285+
public function required_without($str = null, ?string $otherFields = null, array $data = [], ?string $error = null, ?string $field = null): bool
284286
{
285-
if ($fields === null || empty($data)) {
286-
throw new InvalidArgumentException('You must supply the parameters: fields, data.');
287+
if ($otherFields === null || empty($data)) {
288+
throw new InvalidArgumentException('You must supply the parameters: otherFields, data.');
287289
}
288290

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

295297
if ($present) {
296298
return true;
297299
}
298300

299301
// Still here? Then we fail this test if
300302
// any of the fields are not present in $data
301-
foreach ($fields as $field) {
302-
if ((strpos($field, '.') === false && (! array_key_exists($field, $data) || empty($data[$field]))) || (strpos($field, '.') !== false && empty(dot_array_search($field, $data)))) {
303+
foreach ($otherFields as $otherField) {
304+
if ((strpos($otherField, '.') === false) && (! array_key_exists($otherField, $data) || empty($data[$otherField]))) {
303305
return false;
304306
}
307+
if (strpos($otherField, '.') !== false) {
308+
if ($field === null) {
309+
throw new InvalidArgumentException('You must supply the parameters: field.');
310+
}
311+
312+
$fieldData = dot_array_search($otherField, $data);
313+
$fieldSplitArray = explode('.', $field);
314+
$fieldKey = $fieldSplitArray[1];
315+
316+
if (is_array($fieldData)) {
317+
return ! empty(dot_array_search($otherField, $data)[$fieldKey]);
318+
}
319+
$nowField = str_replace('*', $fieldKey, $otherField);
320+
$nowFieldVaule = dot_array_search($nowField, $data);
321+
322+
return null !== $nowFieldVaule;
323+
}
305324
}
306325

307326
return true;

system/Validation/StrictRules/Rules.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,10 +302,12 @@ public function required_with($str = null, ?string $fields = null, array $data =
302302
*
303303
* required_without[id,email]
304304
*
305-
* @param mixed $str
305+
* @param string|null $str
306+
* @param string|null $otherFields The param fields of required_without[].
307+
* @param string|null $field This rule param fields aren't present, this field is required.
306308
*/
307-
public function required_without($str = null, ?string $fields = null, array $data = []): bool
309+
public function required_without($str = null, ?string $otherFields = null, array $data = [], ?string $error = null, ?string $field = null): bool
308310
{
309-
return $this->nonStrictRules->required_without($str, $fields, $data);
311+
return $this->nonStrictRules->required_without($str, $otherFields, $data, $error, $field);
310312
}
311313
}

system/Validation/Validation.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ protected function processRules(
312312
$found = true;
313313
$passed = $param === false
314314
? $set->{$rule}($value, $error)
315-
: $set->{$rule}($value, $param, $data, $error);
315+
: $set->{$rule}($value, $param, $data, $error, $field);
316316

317317
break;
318318
}

tests/system/Validation/ValidationTest.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,13 +1414,20 @@ public function testNestedArrayThrowsException(): void
14141414
'credit_amount' => null,
14151415
'purpose' => 'A',
14161416
],
1417+
'account_3' => [
1418+
'account_number' => '',
1419+
'credit_amount' => 2000,
1420+
'purpose' => '',
1421+
],
14171422
],
14181423
];
14191424
$this->validation->run($data);
14201425

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

@@ -1436,4 +1443,26 @@ public function testRuleWithLeadingAsterisk(): void
14361443
$this->assertFalse($this->validation->run($data));
14371444
$this->assertSame('Required *.foo', $this->validation->getError('*.foo'));
14381445
}
1446+
1447+
/**
1448+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/5942
1449+
*/
1450+
public function testRequireWithoutWithWildCard()
1451+
{
1452+
$data = [
1453+
'a' => [
1454+
['b' => 1, 'c' => 2],
1455+
['c' => ''],
1456+
],
1457+
];
1458+
1459+
$this->validation->setRules([
1460+
'a.*.c' => 'required_without[a.*.b]',
1461+
])->run($data);
1462+
1463+
$this->assertSame(
1464+
'The a.*.c field is required when a.*.b is not present.',
1465+
$this->validation->getError('a.1.c')
1466+
);
1467+
}
14391468
}

user_guide_src/source/changelogs/v4.2.7.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ BREAKING
1414

1515
- 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.
1616
- ``Time::__toString()`` is now locale-independent. It returns database-compatible strings like '2022-09-07 12:00:00' in any locale.
17+
- 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.
1718

1819
Enhancements
1920
************

user_guide_src/source/installation/upgrade_427.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Others
5353
======
5454

5555
- ``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.
56+
- 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.
5657

5758
Project Files
5859
*************

0 commit comments

Comments
 (0)