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: getValidated() when validation multiple asterisk #9220

Merged
merged 5 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
69 changes: 31 additions & 38 deletions system/Validation/DotArrayFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ final class DotArrayFilter
/**
* Creates a new array with only the elements specified in dot array syntax.
*
* This code comes from the dot_array_search() function.
*
* @param array $indexes The dot array syntax pattern to use for filtering.
* @param array $array The array to filter.
*
Expand All @@ -33,20 +31,14 @@ public static function run(array $indexes, array $array): array
$result = [];

foreach ($indexes as $index) {
// See https://regex101.com/r/44Ipql/1
$segments = preg_split(
'/(?<!\\\\)\./',
rtrim($index, '* '),
0,
PREG_SPLIT_NO_EMPTY
);

$segments = array_map(
static fn ($key) => str_replace('\.', '.', $key),
$segments
);

$result = array_replace_recursive($result, self::filter($segments, $array));
$segments = preg_split('/(?<!\\\\)\./', $index, -1, PREG_SPLIT_NO_EMPTY);
$segments = array_map(static fn ($key) => str_replace('\.', '.', $key), $segments);

$filteredArray = self::filter($segments, $array);

if ($filteredArray !== []) {
$result = array_replace_recursive($result, $filteredArray);
}
}

return $result;
Expand All @@ -62,53 +54,54 @@ public static function run(array $indexes, array $array): array
*/
private static function filter(array $indexes, array $array): array
{
// If index is empty, returns empty array.
// If there are no indexes left, return an empty array
if ($indexes === []) {
return [];
}

// Grab the current index.
// Get the current index
$currentIndex = array_shift($indexes);

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

// Handle Wildcard (*)
// Handle the wildcard '*' at the current level
if ($currentIndex === '*') {
$answer = [];
$result = [];

// Iterate over all keys at this level
foreach ($array as $key => $value) {
if (! is_array($value)) {
continue;
}

$result = self::filter($indexes, $value);

if ($result !== []) {
$answer[$key] = $result;
if ($indexes === []) {
// If no indexes are left, capture the entire value
$result[$key] = $value;
} elseif (is_array($value)) {
// If there are still indexes left, continue filtering recursively
$filtered = self::filter($indexes, $value);
if ($filtered !== []) {
$result[$key] = $filtered;
}
}
}

return $answer;
return $result;
}

// If this is the last index, make sure to return it now,
// and not try to recurse through things.
// If this is the last index, return the value
if ($indexes === []) {
return [$currentIndex => $array[$currentIndex]];
return [$currentIndex => $array[$currentIndex] ?? []];
}

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

if ($result !== []) {
return [$currentIndex => $result];
if ($filtered !== []) {
return [$currentIndex => $filtered];
}
}

// Otherwise, not found.
return [];
}
}
81 changes: 81 additions & 0 deletions tests/system/Validation/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use CodeIgniter\Validation\Exceptions\ValidationException;
use Config\App;
use Config\Services;
use Generator;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\ExpectationFailedException;
Expand Down Expand Up @@ -1826,4 +1827,84 @@ public function testRuleWithAsteriskToMultiDimensionalArray(): void
$this->validation->getErrors()
);
}

/**
* @param array<string, mixed> $data
* @param array<string, string> $rules
* @param array<string, mixed> $expectedData
*
* @see https://github.com/codeigniter4/CodeIgniter4/issues/9219
*/
#[DataProvider('provideMultipleAsterisk')]
public function testRuleWithMultipleAsterisk(
array $data = [],
array $rules = [],
bool $expectedCheck = false,
array $expectedData = []
): void {
$this->validation->setRules($rules);

$this->assertSame($expectedCheck, $this->validation->run($data));
$this->assertSame($expectedData, $this->validation->getValidated());
}

public static function provideMultipleAsterisk(): Generator
{
yield 'success' => [
[
'dates' => [
23 => [
45 => 'Its Mee!',
],
],
'foo' => [
'bar' => [
'data' => [
'name' => 'John Doe',
'age' => 29,
'location' => 'Indonesia',
],
],
],
],
[
'dates.*.*' => 'required',
'foo.*.*.*' => 'required',
],
true,
[
'dates' => [
23 => [
45 => 'Its Mee!',
],
],
'foo' => [
'bar' => [
'data' => [
'name' => 'John Doe',
'age' => 29,
'location' => 'Indonesia',
],
],
],
],
];

yield 'failed' => [
[
'foo' => [
'bar' => [
'data' => [
'name' => '',
'age' => 29,
'location' => 'Indonesia',
],
],
],
],
['foo.*.*.*' => 'required'],
false,
[],
];
}
}
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.5.6.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Bugs Fixed
**********
- **Session Library:** The session initialization debug message now uses the correct log type "debug" instead of "info".

- **Validation:** Fixed the `getValidated()` method that did not return valid data when validation rules used multiple asterisks.

See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
for a complete list of bugs fixed.
Loading