Skip to content

Commit 4a7fbd1

Browse files
ddevsrmichalsn
andauthored
fix: getValidated() when validation multiple asterisk (#9220)
* fix: validation multiple asterisk * docs: changelog * Update user_guide_src/source/changelogs/v4.5.6.rst Co-authored-by: Michal Sniatala <[email protected]> * tests: multiple asterisk for fail * fix: PHPStan errors appear --------- Co-authored-by: Michal Sniatala <[email protected]>
1 parent ba62eae commit 4a7fbd1

File tree

3 files changed

+114
-38
lines changed

3 files changed

+114
-38
lines changed

system/Validation/DotArrayFilter.php

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ final class DotArrayFilter
2121
/**
2222
* Creates a new array with only the elements specified in dot array syntax.
2323
*
24-
* This code comes from the dot_array_search() function.
25-
*
2624
* @param array $indexes The dot array syntax pattern to use for filtering.
2725
* @param array $array The array to filter.
2826
*
@@ -33,20 +31,14 @@ public static function run(array $indexes, array $array): array
3331
$result = [];
3432

3533
foreach ($indexes as $index) {
36-
// See https://regex101.com/r/44Ipql/1
37-
$segments = preg_split(
38-
'/(?<!\\\\)\./',
39-
rtrim($index, '* '),
40-
0,
41-
PREG_SPLIT_NO_EMPTY
42-
);
43-
44-
$segments = array_map(
45-
static fn ($key) => str_replace('\.', '.', $key),
46-
$segments
47-
);
48-
49-
$result = array_replace_recursive($result, self::filter($segments, $array));
34+
$segments = preg_split('/(?<!\\\\)\./', $index, -1, PREG_SPLIT_NO_EMPTY);
35+
$segments = array_map(static fn ($key) => str_replace('\.', '.', $key), $segments);
36+
37+
$filteredArray = self::filter($segments, $array);
38+
39+
if ($filteredArray !== []) {
40+
$result = array_replace_recursive($result, $filteredArray);
41+
}
5042
}
5143

5244
return $result;
@@ -62,53 +54,54 @@ public static function run(array $indexes, array $array): array
6254
*/
6355
private static function filter(array $indexes, array $array): array
6456
{
65-
// If index is empty, returns empty array.
57+
// If there are no indexes left, return an empty array
6658
if ($indexes === []) {
6759
return [];
6860
}
6961

70-
// Grab the current index.
62+
// Get the current index
7163
$currentIndex = array_shift($indexes);
7264

65+
// If the current index doesn't exist and is not a wildcard, return an empty array
7366
if (! isset($array[$currentIndex]) && $currentIndex !== '*') {
7467
return [];
7568
}
7669

77-
// Handle Wildcard (*)
70+
// Handle the wildcard '*' at the current level
7871
if ($currentIndex === '*') {
79-
$answer = [];
72+
$result = [];
8073

74+
// Iterate over all keys at this level
8175
foreach ($array as $key => $value) {
82-
if (! is_array($value)) {
83-
continue;
84-
}
85-
86-
$result = self::filter($indexes, $value);
87-
88-
if ($result !== []) {
89-
$answer[$key] = $result;
76+
if ($indexes === []) {
77+
// If no indexes are left, capture the entire value
78+
$result[$key] = $value;
79+
} elseif (is_array($value)) {
80+
// If there are still indexes left, continue filtering recursively
81+
$filtered = self::filter($indexes, $value);
82+
if ($filtered !== []) {
83+
$result[$key] = $filtered;
84+
}
9085
}
9186
}
9287

93-
return $answer;
88+
return $result;
9489
}
9590

96-
// If this is the last index, make sure to return it now,
97-
// and not try to recurse through things.
91+
// If this is the last index, return the value
9892
if ($indexes === []) {
99-
return [$currentIndex => $array[$currentIndex]];
93+
return [$currentIndex => $array[$currentIndex] ?? []];
10094
}
10195

102-
// Do we need to recursively filter this value?
103-
if (is_array($array[$currentIndex]) && $array[$currentIndex] !== []) {
104-
$result = self::filter($indexes, $array[$currentIndex]);
96+
// If the current value is an array, recursively filter it
97+
if (is_array($array[$currentIndex])) {
98+
$filtered = self::filter($indexes, $array[$currentIndex]);
10599

106-
if ($result !== []) {
107-
return [$currentIndex => $result];
100+
if ($filtered !== []) {
101+
return [$currentIndex => $filtered];
108102
}
109103
}
110104

111-
// Otherwise, not found.
112105
return [];
113106
}
114107
}

tests/system/Validation/ValidationTest.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use CodeIgniter\Validation\Exceptions\ValidationException;
2222
use Config\App;
2323
use Config\Services;
24+
use Generator;
2425
use PHPUnit\Framework\Attributes\DataProvider;
2526
use PHPUnit\Framework\Attributes\Group;
2627
use PHPUnit\Framework\ExpectationFailedException;
@@ -1826,4 +1827,84 @@ public function testRuleWithAsteriskToMultiDimensionalArray(): void
18261827
$this->validation->getErrors()
18271828
);
18281829
}
1830+
1831+
/**
1832+
* @param array<string, mixed> $data
1833+
* @param array<string, string> $rules
1834+
* @param array<string, mixed> $expectedData
1835+
*
1836+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/9219
1837+
*/
1838+
#[DataProvider('provideMultipleAsterisk')]
1839+
public function testRuleWithMultipleAsterisk(
1840+
array $data = [],
1841+
array $rules = [],
1842+
bool $expectedCheck = false,
1843+
array $expectedData = []
1844+
): void {
1845+
$this->validation->setRules($rules);
1846+
1847+
$this->assertSame($expectedCheck, $this->validation->run($data));
1848+
$this->assertSame($expectedData, $this->validation->getValidated());
1849+
}
1850+
1851+
public static function provideMultipleAsterisk(): Generator
1852+
{
1853+
yield 'success' => [
1854+
[
1855+
'dates' => [
1856+
23 => [
1857+
45 => 'Its Mee!',
1858+
],
1859+
],
1860+
'foo' => [
1861+
'bar' => [
1862+
'data' => [
1863+
'name' => 'John Doe',
1864+
'age' => 29,
1865+
'location' => 'Indonesia',
1866+
],
1867+
],
1868+
],
1869+
],
1870+
[
1871+
'dates.*.*' => 'required',
1872+
'foo.*.*.*' => 'required',
1873+
],
1874+
true,
1875+
[
1876+
'dates' => [
1877+
23 => [
1878+
45 => 'Its Mee!',
1879+
],
1880+
],
1881+
'foo' => [
1882+
'bar' => [
1883+
'data' => [
1884+
'name' => 'John Doe',
1885+
'age' => 29,
1886+
'location' => 'Indonesia',
1887+
],
1888+
],
1889+
],
1890+
],
1891+
];
1892+
1893+
yield 'failed' => [
1894+
[
1895+
'foo' => [
1896+
'bar' => [
1897+
'data' => [
1898+
'name' => '',
1899+
'age' => 29,
1900+
'location' => 'Indonesia',
1901+
],
1902+
],
1903+
],
1904+
],
1905+
['foo.*.*.*' => 'required'],
1906+
false,
1907+
[],
1908+
];
1909+
}
18291910
}

user_guide_src/source/changelogs/v4.5.6.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Bugs Fixed
3131
**********
3232
- **Session Library:** The session initialization debug message now uses the correct log type "debug" instead of "info".
3333

34+
- **Validation:** Fixed the `getValidated()` method that did not return valid data when validation rules used multiple asterisks.
35+
3436
See the repo's
3537
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
3638
for a complete list of bugs fixed.

0 commit comments

Comments
 (0)