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
2 changes: 1 addition & 1 deletion src/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ protected function getArguments(Hook $hook, array $values, array $requestParams)
$existsInValues = \array_key_exists($key, $values);
$paramExists = $existsInRequest || $existsInValues;

if ($existsInRequest) {
if ($existsInRequest && !($param['optional'] && $requestParams[$key] === null)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we want to actually pass null to an optional param?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what should we do? should we check if validator is nullable ? what do we do? if null value is supported, shouldn't default be null? do we have a case where we support null but also have something else as default value?

$arg = $requestParams[$key];
} else {
if (!is_string($param['default']) && \is_callable($param['default'])) {
Expand Down
76 changes: 76 additions & 0 deletions tests/HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -858,4 +858,80 @@ public function testErrorHandlerChaining(): void
$this->assertEquals('First error handler failed', $e->getPrevious()->getMessage());
}
}

public function testOptionalParamsWithNullUseDefault(): void
{
// Test when optional param receives null, it should use default value
// Empty strings are treated as valid values and preserved as-is
// Note: Using Text validator with min=0 to allow empty strings
$route = new Route('GET', '/test-null');
$route
->param('param1', 'default1', new Text(200, min: 0), 'param1 desc', true)
->param('param2', 'default2', new Text(200, min: 0), 'param2 desc', true)
->action(function ($param1, $param2) {
echo $param1 . '|' . $param2;
});

// Test with null value - should use default
\ob_start();
$request = new UtopiaRequestTest();
$request::_setParams(['param1' => null, 'param2' => 'value2']);
$this->app->execute($route, $request, new Response());
$result = \ob_get_contents();
\ob_end_clean();

$this->assertEquals('default1|value2', $result);

// Test with both params having valid values
\ob_start();
$request = new UtopiaRequestTest();
$request::_setParams(['param1' => 'value1', 'param2' => 'value2']);
$this->app->execute($route, $request, new Response());
$result = \ob_get_contents();
\ob_end_clean();

$this->assertEquals('value1|value2', $result);

// Test with both params as null - both should use defaults
\ob_start();
$request = new UtopiaRequestTest();
$request::_setParams(['param1' => null, 'param2' => null]);
$this->app->execute($route, $request, new Response());
$result = \ob_get_contents();
\ob_end_clean();

$this->assertEquals('default1|default2', $result);

// Test with empty string - should be preserved as valid value
\ob_start();
$request = new UtopiaRequestTest();
$request::_setParams(['param1' => '', 'param2' => 'value2']);
$this->app->execute($route, $request, new Response());
$result = \ob_get_contents();
\ob_end_clean();

// Empty string is a valid value, not replaced with default
$this->assertEquals('|value2', $result);

// Test with both empty string and null
\ob_start();
$request = new UtopiaRequestTest();
$request::_setParams(['param1' => null, 'param2' => '']);
$this->app->execute($route, $request, new Response());
$result = \ob_get_contents();
\ob_end_clean();

// null uses default, empty string is preserved
$this->assertEquals('default1|', $result);

// Test with numeric zero - should be treated as valid value (not null)
\ob_start();
$request = new UtopiaRequestTest();
$request::_setParams(['param1' => '0', 'param2' => 'value2']);
$this->app->execute($route, $request, new Response());
$result = \ob_get_contents();
\ob_end_clean();

$this->assertEquals('0|value2', $result);
}
}