Skip to content

Commit

Permalink
feat(php): allow to pass raw boolean to api (#18520)
Browse files Browse the repository at this point in the history
This allows users to use APIs that require booleans in query params not to be cast to int, e.g. `&foo=true`. Currently, `true` is cast to `1` so it's passed as `&foo=1`. That might not be supported by the target API.

The fix contains copy-pasted function from guzzlehttp/psr7 `Query::build()` with minor tweak.
  • Loading branch information
simPod authored May 1, 2024
1 parent 0768ddc commit 98d0261
Show file tree
Hide file tree
Showing 17 changed files with 528 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -529,22 +529,61 @@ class ObjectSerializer
}

/**
* Native `http_build_query` wrapper.
* @see https://www.php.net/manual/en/function.http-build-query
*
* @param array|object $data May be an array or object containing properties.
* @param string $numeric_prefix If numeric indices are used in the base array and this parameter is provided, it will be prepended to the numeric index for elements in the base array only.
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
*
* @return string
*/
public static function buildQuery(
array|object $data,
string $numeric_prefix = '',
?string $arg_separator = null,
int $encoding_type = \PHP_QUERY_RFC3986
): string {
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
* Build a query string from an array of key value pairs.
*
* This function can use the return value of `parse()` to build a query
* string. This function does not modify the provided keys when an array is
* encountered (like `http_build_query()` would).
*
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
* to encode using RFC3986, or PHP_QUERY_RFC1738
* to encode using RFC1738.
*/
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): string
{
if (!$params) {
return '';
}

if ($encoding === false) {
$encoder = function (string $str): string {
return $str;
};
} elseif ($encoding === PHP_QUERY_RFC3986) {
$encoder = 'rawurlencode';
} elseif ($encoding === PHP_QUERY_RFC1738) {
$encoder = 'urlencode';
} else {
throw new \InvalidArgumentException('Invalid type');
}

$castBool = Configuration::BOOLEAN_FORMAT_INT == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()
? function ($v) { return (int) $v; }
: function ($v) { return $v ? 'true' : 'false'; };

$qs = '';
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? $castBool($v) : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
$qs .= '&';
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? $castBool($vv) : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}
$qs .= '&';
}
}
}

return $qs ? (string) substr($qs, 0, -1) : '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -536,22 +536,64 @@ class ObjectSerializer
}

/**
* Native `http_build_query` wrapper.
* @see https://www.php.net/manual/en/function.http-build-query
*
* @param array|object $data May be an array or object containing properties.
* @param string $numeric_prefix If numeric indices are used in the base array and this parameter is provided, it will be prepended to the numeric index for elements in the base array only.
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
*
* @return string
*/
public static function buildQuery(
$data,
string $numeric_prefix = '',
?string $arg_separator = null,
int $encoding_type = \PHP_QUERY_RFC3986
): string {
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
* Build a query string from an array of key value pairs.
*
* This function can use the return value of `parse()` to build a query
* string. This function does not modify the provided keys when an array is
* encountered (like `http_build_query()` would).
*
* The function is copied from https://github.com/guzzle/psr7/blob/a243f80a1ca7fe8ceed4deee17f12c1930efe662/src/Query.php#L59-L112
* with a modification which is described in https://github.com/guzzle/psr7/pull/603
*
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
* to encode using RFC3986, or PHP_QUERY_RFC1738
* to encode using RFC1738.
*/
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): string
{
if (!$params) {
return '';
}

if ($encoding === false) {
$encoder = function (string $str): string {
return $str;
};
} elseif ($encoding === PHP_QUERY_RFC3986) {
$encoder = 'rawurlencode';
} elseif ($encoding === PHP_QUERY_RFC1738) {
$encoder = 'urlencode';
} else {
throw new \InvalidArgumentException('Invalid type');
}

$castBool = Configuration::BOOLEAN_FORMAT_INT == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()
? function ($v) { return (int) $v; }
: function ($v) { return $v ? 'true' : 'false'; };

$qs = '';
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? $castBool($v) : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
$qs .= '&';
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? $castBool($vv) : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}
$qs .= '&';
}
}
}

return $qs ? (string) substr($qs, 0, -1) : '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
namespace {{apiPackage}};

use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Query;
use Http\Client\Common\Plugin\ErrorPlugin;
use Http\Client\Common\Plugin\RedirectPlugin;
use Http\Client\Common\PluginClient;
Expand Down Expand Up @@ -643,7 +642,7 @@ use function sprintf;
} else {
// for HTTP post (form)
$httpBody = Query::build($formParams);
$httpBody = ObjectSerializer::buildQuery($formParams);
}
}

Expand Down Expand Up @@ -762,7 +761,7 @@ use function sprintf;
->withHost($host)
->withScheme($scheme)
->withPort($port)
->withQuery(Query::build($queryParams));
->withQuery(ObjectSerializer::buildQuery($queryParams));
if ($user) {
$uri = $uri->withUserInfo($user, $password);
Expand Down
73 changes: 56 additions & 17 deletions samples/client/echo_api/php-nextgen/src/ObjectSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -539,22 +539,61 @@ public static function deserialize(mixed $data, string $class, array $httpHeader
}

/**
* Native `http_build_query` wrapper.
* @see https://www.php.net/manual/en/function.http-build-query
*
* @param array|object $data May be an array or object containing properties.
* @param string $numeric_prefix If numeric indices are used in the base array and this parameter is provided, it will be prepended to the numeric index for elements in the base array only.
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
*
* @return string
*/
public static function buildQuery(
array|object $data,
string $numeric_prefix = '',
?string $arg_separator = null,
int $encoding_type = \PHP_QUERY_RFC3986
): string {
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
* Build a query string from an array of key value pairs.
*
* This function can use the return value of `parse()` to build a query
* string. This function does not modify the provided keys when an array is
* encountered (like `http_build_query()` would).
*
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
* to encode using RFC3986, or PHP_QUERY_RFC1738
* to encode using RFC1738.
*/
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): string
{
if (!$params) {
return '';
}

if ($encoding === false) {
$encoder = function (string $str): string {
return $str;
};
} elseif ($encoding === PHP_QUERY_RFC3986) {
$encoder = 'rawurlencode';
} elseif ($encoding === PHP_QUERY_RFC1738) {
$encoder = 'urlencode';
} else {
throw new \InvalidArgumentException('Invalid type');
}

$castBool = Configuration::BOOLEAN_FORMAT_INT == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()
? function ($v) { return (int) $v; }
: function ($v) { return $v ? 'true' : 'false'; };

$qs = '';
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? $castBool($v) : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
$qs .= '&';
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? $castBool($vv) : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}
$qs .= '&';
}
}
}

return $qs ? (string) substr($qs, 0, -1) : '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@

use GuzzleHttp\Psr7\Utils;
use OpenAPI\Client\Model\ModelInterface;
use function GuzzleHttp\Psr7\;
use function is_array;
use function is_bool;
use function substr;
use const PHP_QUERY_RFC1738;
use const PHP_QUERY_RFC3986;

/**
* ObjectSerializer Class Doc Comment
Expand Down Expand Up @@ -545,22 +551,66 @@ public static function deserialize($data, $class, $httpHeaders = null)
}

/**
* Native `http_build_query` wrapper.
* @see https://www.php.net/manual/en/function.http-build-query
* Build a query string from an array of key value pairs.
*
* @param array|object $data May be an array or object containing properties.
* @param string $numeric_prefix If numeric indices are used in the base array and this parameter is provided, it will be prepended to the numeric index for elements in the base array only.
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
* This function can use the return value of `parse()` to build a query
* string. This function does not modify the provided keys when an array is
* encountered (like `http_build_query()` would).
*
* @return string
* The function is copied from https://github.com/guzzle/psr7/blob/a243f80a1ca7fe8ceed4deee17f12c1930efe662/src/Query.php#L59-L112
* with a modification which is described in https://github.com/guzzle/psr7/pull/603
*
* @param array $params Query string parameters.
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
* to encode using RFC3986, or PHP_QUERY_RFC1738
* to encode using RFC1738.
* @param bool $treatBooleansAsInts When `true` values are cast to int (e.g. ['foo' => false] gives `foo=0`).
* When `false` values are cast to strings (e.g. ['foo' => false] gives `foo=false`).
*/
public static function buildQuery(
$data,
string $numeric_prefix = '',
?string $arg_separator = null,
int $encoding_type = \PHP_QUERY_RFC3986
): string {
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBooleansAsInts = true): string
{
if (!$params) {
return '';
}

if ($encoding === false) {
$encoder = function (string $str): string {
return $str;
};
} elseif ($encoding === PHP_QUERY_RFC3986) {
$encoder = 'rawurlencode';
} elseif ($encoding === PHP_QUERY_RFC1738) {
$encoder = 'urlencode';
} else {
throw new \InvalidArgumentException('Invalid type');
}

$castBool = $treatBooleansAsInts
? function ($v) { return (int) $v; }
: function ($v) { return $v ? 'true' : 'false'; };

$qs = '';
foreach ($params as $k => $v) {
$k = $encoder((string) $k);
if (!is_array($v)) {
$qs .= $k;
$v = is_bool($v) ? $castBool($v) : $v;
if ($v !== null) {
$qs .= '='.$encoder((string) $v);
}
$qs .= '&';
} else {
foreach ($v as $vv) {
$qs .= $k;
$vv = is_bool($vv) ? $castBool($vv) : $vv;
if ($vv !== null) {
$qs .= '='.$encoder((string) $vv);
}
$qs .= '&';
}
}
}

return $qs ? (string) substr($qs, 0, -1) : '';
}
}
Loading

0 comments on commit 98d0261

Please sign in to comment.