Skip to content

Commit

Permalink
[PHP] Accept 0 as value for query parameters (#13868)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasphansen authored Nov 2, 2022
1 parent 89fc631 commit 0d1e313
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,49 @@ class ObjectSerializer
return rawurlencode(self::toString($value));
}

/**
* Checks if a value is empty, based on its OpenAPI type.
*
* @param mixed $value
* @param string $openApiType
*
* @return bool true if $value is empty
*/
private static function isEmptyValue($value, string $openApiType): bool
{
# If empty() returns false, it is not empty regardless of its type.
if (!empty($value)) {
return false;
}

# Null is always empty, as we cannot send a real "null" value in a query parameter.
if ($value === null) {
return true;
}

switch ($openApiType) {
# For numeric values, false and '' are considered empty.
# This comparison is safe for floating point values, since the previous call to empty() will
# filter out values that don't match 0.
case 'int':
case 'integer':
return $value !== 0;
case 'number':
case 'float':
return $value !== 0 && $value !== 0.0;
# For boolean values, '' is considered empty
case 'bool':
case 'boolean':
return !in_array($value, [false, 0], true);
# For all the other types, any value at this point can be considered empty.
default:
return true;
}
}
/**
* Take query parameter properties and turn it into an array suitable for
* native http_build_query or GuzzleHttp\Psr7\Query::build.
Expand All @@ -169,10 +212,12 @@ class ObjectSerializer
bool $explode = true,
bool $required = true
): array {
if (
empty($value)
&& ($value !== false || $openApiType !== 'boolean') // if $value === false and $openApiType ==='boolean' it isn't empty
) {
# Check if we should omit this parameter from the query. This should only happen when:
# - Parameter is NOT required; AND
# - its value is set to a value that is equivalent to "empty", depending on its OpenAPI type. For
# example, 0 as "int" or "boolean" is NOT an empty value.
if (self::isEmptyValue($value, $openApiType)) {
if ($required) {
return ["{$paramName}" => ''];
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,49 @@ public static function toPathValue($value)
return rawurlencode(self::toString($value));
}

/**
* Checks if a value is empty, based on its OpenAPI type.
*
* @param mixed $value
* @param string $openApiType
*
* @return bool true if $value is empty
*/
private static function isEmptyValue($value, string $openApiType): bool
{
# If empty() returns false, it is not empty regardless of its type.
if (!empty($value)) {
return false;
}

# Null is always empty, as we cannot send a real "null" value in a query parameter.
if ($value === null) {
return true;
}

switch ($openApiType) {
# For numeric values, false and '' are considered empty.
# This comparison is safe for floating point values, since the previous call to empty() will
# filter out values that don't match 0.
case 'int':
case 'integer':
return $value !== 0;

case 'number':
case 'float':
return $value !== 0 && $value !== 0.0;

# For boolean values, '' is considered empty
case 'bool':
case 'boolean':
return !in_array($value, [false, 0], true);

# For all the other types, any value at this point can be considered empty.
default:
return true;
}
}

/**
* Take query parameter properties and turn it into an array suitable for
* native http_build_query or GuzzleHttp\Psr7\Query::build.
Expand All @@ -178,10 +221,12 @@ public static function toQueryValue(
bool $explode = true,
bool $required = true
): array {
if (
empty($value)
&& ($value !== false || $openApiType !== 'boolean') // if $value === false and $openApiType ==='boolean' it isn't empty
) {

# Check if we should omit this parameter from the query. This should only happen when:
# - Parameter is NOT required; AND
# - its value is set to a value that is equivalent to "empty", depending on its OpenAPI type. For
# example, 0 as "int" or "boolean" is NOT an empty value.
if (self::isEmptyValue($value, $openApiType)) {
if ($required) {
return ["{$paramName}" => ''];
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,97 @@ public function provideQueryParams(): array
'form null DateTime object, explode on, required false' => [
null, 'dateTime', '\DateTime', 'form', true, false, '',
],
'form 1 int, explode on, required false' => [
1, 'field', 'int', 'form', true, false, 'field=1',
],
'form 0 int, explode on, required false' => [
0, 'field', 'int', 'form', true, false, 'field=0',
],
'form 0 int, explode on, required true' => [
0, 'field', 'int', 'form', true, true, 'field=0',
],
'form null int, explode on, required false' => [
null, 'field', 'int', 'form', true, false, '',
],
'form null int, explode on, required true' => [
null, 'field', 'int', 'form', true, true, 'field=',
],
'form 1 integer, explode on, required false' => [
1, 'field', 'integer', 'form', true, false, 'field=1',
],
'form 0 integer, explode on, required false' => [
0, 'field', 'integer', 'form', true, false, 'field=0',
],
'form 0 integer, explode on, required true' => [
0, 'field', 'integer', 'form', true, true, 'field=0',
],
'form null integer, explode on, required false' => [
null, 'field', 'integer', 'form', true, false, '',
],
'form null integer, explode on, required true' => [
null, 'field', 'integer', 'form', true, true, 'field=',
],
'form 1.1 float, explode on, required false' => [
1.1, 'field', 'float', 'form', true, false, 'field=1.1',
],
'form 0 float, explode on, required false' => [
0, 'field', 'float', 'form', true, false, 'field=0',
],
'form 0.0 float, explode on, required false' => [
0.0, 'field', 'float', 'form', true, false, 'field=0',
],
'form 0 float, explode on, required true' => [
0, 'field', 'float', 'form', true, true, 'field=0',
],
'form 0.0 float, explode on, required true' => [
0.0, 'field', 'float', 'form', true, true, 'field=0',
],
'form null float, explode on, required false' => [
null, 'field', 'float', 'form', true, false, '',
],
'form null float, explode on, required true' => [
null, 'field', 'float', 'form', true, true, 'field=',
],
'form 1.1 number, explode on, required false' => [
1.1, 'field', 'number', 'form', true, false, 'field=1.1',
],
'form 0 number, explode on, required false' => [
0, 'field', 'number', 'form', true, false, 'field=0',
],
'form 0.0 number, explode on, required false' => [
0.0, 'field', 'number', 'form', true, false, 'field=0',
],
'form 0 number, explode on, required true' => [
0, 'field', 'number', 'form', true, true, 'field=0',
],
'form 0.0 number, explode on, required true' => [
0.0, 'field', 'number', 'form', true, true, 'field=0',
],
'form null number, explode on, required false' => [
null, 'field', 'number', 'form', true, false, '',
],
'form null number, explode on, required true' => [
null, 'field', 'number', 'form', true, true, 'field=',
],
'form true bool, explode on, required false' => [
true, 'field', 'bool', 'form', true, false, 'field=1',
],
'form false bool, explode on, required false' => [
false, 'field', 'bool', 'form', true, false, 'field=0',
],
'form empty bool, explode on, required false' => [
null, 'field', 'bool', 'form', true, false, '',
],
'form empty bool, explode on, required true' => [
null, 'field', 'bool', 'form', true, true, 'field=',
],
# Entries for "boolean" type are already covered in the beginning of this provider
'form 1 bool, explode on, required false' => [
1, 'field', 'bool', 'form', true, false, 'field=1',
],
'form 0 bool, explode on, required false' => [
0, 'field', 'bool', 'form', true, false, 'field=0',
],
];
}

Expand Down

0 comments on commit 0d1e313

Please sign in to comment.