Skip to content

Commit 8b9f434

Browse files
authored
[12.x] Add in_array_keys validation rule to check for presence of specified array keys (#55807)
* Add in_array_keys validation rule * Add tests * CS fixes * CS fixes * CS fixes
1 parent 6cde2ab commit 8b9f434

File tree

4 files changed

+126
-0
lines changed

4 files changed

+126
-0
lines changed

src/Illuminate/Translation/lang/en/validation.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
'image' => 'The :attribute field must be an image.',
7474
'in' => 'The selected :attribute is invalid.',
7575
'in_array' => 'The :attribute field must exist in :other.',
76+
'in_array_keys' => 'The :attribute field must contain at least one of the following keys: :values.',
7677
'integer' => 'The :attribute field must be an integer.',
7778
'ip' => 'The :attribute field must be a valid IP address.',
7879
'ipv4' => 'The :attribute field must be a valid IPv4 address.',

src/Illuminate/Validation/Concerns/ReplacesAttributes.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,24 @@ protected function replaceInArray($message, $attribute, $rule, $parameters)
325325
return str_replace(':other', $this->getDisplayableAttribute($parameters[0]), $message);
326326
}
327327

328+
/**
329+
* Replace all place-holders for the in_array_keys rule.
330+
*
331+
* @param string $message
332+
* @param string $attribute
333+
* @param string $rule
334+
* @param array<int,string> $parameters
335+
* @return string
336+
*/
337+
protected function replaceInArrayKeys($message, $attribute, $rule, $parameters)
338+
{
339+
foreach ($parameters as &$parameter) {
340+
$parameter = $this->getDisplayableValue($attribute, $parameter);
341+
}
342+
343+
return str_replace(':values', implode(', ', $parameters), $message);
344+
}
345+
328346
/**
329347
* Replace all place-holders for the required_array_keys rule.
330348
*

src/Illuminate/Validation/Concerns/ValidatesAttributes.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,33 @@ public function validateInArray($attribute, $value, $parameters)
14501450
return in_array($value, $otherValues);
14511451
}
14521452

1453+
/**
1454+
* Validate that an array has at least one of the given keys.
1455+
*
1456+
* @param string $attribute
1457+
* @param mixed $value
1458+
* @param array<int, int|string> $parameters
1459+
* @return bool
1460+
*/
1461+
public function validateInArrayKeys($attribute, $value, $parameters)
1462+
{
1463+
if (! is_array($value)) {
1464+
return false;
1465+
}
1466+
1467+
if (empty($parameters)) {
1468+
return false;
1469+
}
1470+
1471+
foreach ($parameters as $param) {
1472+
if (Arr::exists($value, $param)) {
1473+
return true;
1474+
}
1475+
}
1476+
1477+
return false;
1478+
}
1479+
14531480
/**
14541481
* Validate that an attribute is an integer.
14551482
*
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Validation;
4+
5+
use Illuminate\Translation\ArrayLoader;
6+
use Illuminate\Translation\Translator;
7+
use Illuminate\Validation\Validator;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class ValidationInArrayKeysTest extends TestCase
11+
{
12+
public function testInArrayKeysValidation()
13+
{
14+
$trans = $this->getIlluminateArrayTranslator();
15+
16+
// Test passes when array has at least one of the specified keys
17+
$v = new Validator($trans, ['foo' => ['first_key' => 'bar', 'second_key' => 'baz']], ['foo' => 'in_array_keys:first_key,third_key']);
18+
$this->assertTrue($v->passes());
19+
20+
// Test passes when array has multiple of the specified keys
21+
$v = new Validator($trans, ['foo' => ['first_key' => 'bar', 'second_key' => 'baz']], ['foo' => 'in_array_keys:first_key,second_key']);
22+
$this->assertTrue($v->passes());
23+
24+
// Test fails when array doesn't have any of the specified keys
25+
$v = new Validator($trans, ['foo' => ['first_key' => 'bar', 'second_key' => 'baz']], ['foo' => 'in_array_keys:third_key,fourth_key']);
26+
$this->assertTrue($v->fails());
27+
28+
// Test fails when value is not an array
29+
$v = new Validator($trans, ['foo' => 'not-an-array'], ['foo' => 'in_array_keys:first_key']);
30+
$this->assertTrue($v->fails());
31+
32+
// Test fails when no keys are specified
33+
$v = new Validator($trans, ['foo' => ['first_key' => 'bar']], ['foo' => 'in_array_keys:']);
34+
$this->assertTrue($v->fails());
35+
}
36+
37+
public function testInArrayKeysValidationWithNestedArrays()
38+
{
39+
$trans = $this->getIlluminateArrayTranslator();
40+
41+
// Test passes with nested arrays
42+
$v = new Validator($trans, [
43+
'foo' => [
44+
'first_key' => ['nested' => 'value'],
45+
'second_key' => 'baz',
46+
],
47+
], ['foo' => 'in_array_keys:first_key,third_key']);
48+
$this->assertTrue($v->passes());
49+
50+
// Test with dot notation for nested arrays
51+
$v = new Validator($trans, [
52+
'foo' => [
53+
'first' => [
54+
'nested_key' => 'value',
55+
],
56+
],
57+
], ['foo.first' => 'in_array_keys:nested_key']);
58+
$this->assertTrue($v->passes());
59+
}
60+
61+
public function testInArrayKeysValidationErrorMessage()
62+
{
63+
$trans = $this->getIlluminateArrayTranslator();
64+
$trans->addLines([
65+
'validation.in_array_keys' => 'The :attribute field must contain at least one of the following keys: :values.',
66+
], 'en');
67+
68+
$v = new Validator($trans, ['foo' => ['wrong_key' => 'bar']], ['foo' => 'in_array_keys:first_key,second_key']);
69+
$this->assertFalse($v->passes());
70+
$this->assertEquals(
71+
'The foo field must contain at least one of the following keys: first_key, second_key.',
72+
$v->messages()->first('foo')
73+
);
74+
}
75+
76+
protected function getIlluminateArrayTranslator()
77+
{
78+
return new Translator(new ArrayLoader, 'en');
79+
}
80+
}

0 commit comments

Comments
 (0)