Skip to content
Open
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
9 changes: 5 additions & 4 deletions system/Validation/DotArrayFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ private static function filter(array $indexes, array $array): array
// 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 !== '*') {
// If the current index doesn't exist and is not a wildcard, return an empty array.
// Use array_key_exists() so explicit null values are preserved.
if ($currentIndex !== '*' && ! array_key_exists($currentIndex, $array)) {
return [];
}

Expand All @@ -88,9 +89,9 @@ private static function filter(array $indexes, array $array): array
return $result;
}

// If this is the last index, return the value
// If this is the last index, return the value as-is, including null.
if ($indexes === []) {
return [$currentIndex => $array[$currentIndex] ?? []];
return [$currentIndex => $array[$currentIndex]];
}

// If the current value is an array, recursively filter it
Expand Down
11 changes: 11 additions & 0 deletions tests/system/Validation/DotArrayFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,15 @@ public function testRunReturnOrderedIndices(): void

$this->assertSame($data, $result);
}

public function testRunPreservesNullValue(): void
{
$data = [
'foo' => null,
];

$result = DotArrayFilter::run(['foo'], $data);

$this->assertSame(['foo' => null], $result);
}
}
43 changes: 43 additions & 0 deletions tests/system/Validation/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,49 @@ public function testJsonInput(): void
service('superglobals')->unsetServer('CONTENT_TYPE');
}

/**
* @param array<string, string> $rules
* @param array<string, mixed> $expectedValidated
*/
#[DataProvider('provideGetValidatedWithNullValue')]
public function testGetValidatedWithNullValue(
array $rules,
bool $expectedResult,
array $expectedValidated,
): void {
$data = [
'role' => null,
];

$result = $this->validation->setRules($rules)->run($data);

$this->assertSame($expectedResult, $result);
$this->assertSame($expectedValidated, $this->validation->getValidated());
$this->assertSame($expectedResult ? [] : ['role'], array_keys($this->validation->getErrors()));
}

/**
* @return iterable<string, array{
* 0: array<string, string>,
* 1: bool,
* 2: array<string, mixed>
* }>
*/
public static function provideGetValidatedWithNullValue(): iterable
{
yield 'permit_empty preserves null' => [
['role' => 'permit_empty|string'],
true,
['role' => null],
];

yield 'string fails on null' => [
['role' => 'string'],
false,
[],
];
}

public function testJsonInputInvalid(): void
{
$this->expectException(HTTPException::class);
Expand Down
1 change: 1 addition & 0 deletions user_guide_src/source/changelogs/v4.7.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Bugs Fixed

- **Autoloader:** Fixed a bug where ``Autoloader::unregister()`` (used during tests) silently failed to remove handlers from the SPL autoload stack, causing closures to accumulate permanently.
- **Common:** Fixed a bug where the ``command()`` helper function did not properly clean up output buffers, which could lead to risky tests when exceptions were thrown.
- **Validation:** Fixed a bug where ``Validation::getValidated()`` dropped fields whose validated value was explicitly ``null``.

See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
Expand Down
Loading