Skip to content

Commit 98d0261

Browse files
authored
feat(php): allow to pass raw boolean to api (#18520)
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.
1 parent 0768ddc commit 98d0261

File tree

17 files changed

+528
-179
lines changed

17 files changed

+528
-179
lines changed

modules/openapi-generator/src/main/resources/php-nextgen/ObjectSerializer.mustache

+56-17
Original file line numberDiff line numberDiff line change
@@ -529,22 +529,61 @@ class ObjectSerializer
529529
}
530530

531531
/**
532-
* Native `http_build_query` wrapper.
533-
* @see https://www.php.net/manual/en/function.http-build-query
534-
*
535-
* @param array|object $data May be an array or object containing properties.
536-
* @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.
537-
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
538-
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
539-
*
540-
* @return string
541-
*/
542-
public static function buildQuery(
543-
array|object $data,
544-
string $numeric_prefix = '',
545-
?string $arg_separator = null,
546-
int $encoding_type = \PHP_QUERY_RFC3986
547-
): string {
548-
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
532+
* Build a query string from an array of key value pairs.
533+
*
534+
* This function can use the return value of `parse()` to build a query
535+
* string. This function does not modify the provided keys when an array is
536+
* encountered (like `http_build_query()` would).
537+
*
538+
* @param array $params Query string parameters.
539+
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
540+
* to encode using RFC3986, or PHP_QUERY_RFC1738
541+
* to encode using RFC1738.
542+
*/
543+
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): string
544+
{
545+
if (!$params) {
546+
return '';
547+
}
548+
549+
if ($encoding === false) {
550+
$encoder = function (string $str): string {
551+
return $str;
552+
};
553+
} elseif ($encoding === PHP_QUERY_RFC3986) {
554+
$encoder = 'rawurlencode';
555+
} elseif ($encoding === PHP_QUERY_RFC1738) {
556+
$encoder = 'urlencode';
557+
} else {
558+
throw new \InvalidArgumentException('Invalid type');
559+
}
560+
561+
$castBool = Configuration::BOOLEAN_FORMAT_INT == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()
562+
? function ($v) { return (int) $v; }
563+
: function ($v) { return $v ? 'true' : 'false'; };
564+
565+
$qs = '';
566+
foreach ($params as $k => $v) {
567+
$k = $encoder((string) $k);
568+
if (!is_array($v)) {
569+
$qs .= $k;
570+
$v = is_bool($v) ? $castBool($v) : $v;
571+
if ($v !== null) {
572+
$qs .= '='.$encoder((string) $v);
573+
}
574+
$qs .= '&';
575+
} else {
576+
foreach ($v as $vv) {
577+
$qs .= $k;
578+
$vv = is_bool($vv) ? $castBool($vv) : $vv;
579+
if ($vv !== null) {
580+
$qs .= '='.$encoder((string) $vv);
581+
}
582+
$qs .= '&';
583+
}
584+
}
585+
}
586+
587+
return $qs ? (string) substr($qs, 0, -1) : '';
549588
}
550589
}

modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache

+59-17
Original file line numberDiff line numberDiff line change
@@ -536,22 +536,64 @@ class ObjectSerializer
536536
}
537537

538538
/**
539-
* Native `http_build_query` wrapper.
540-
* @see https://www.php.net/manual/en/function.http-build-query
541-
*
542-
* @param array|object $data May be an array or object containing properties.
543-
* @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.
544-
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
545-
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
546-
*
547-
* @return string
548-
*/
549-
public static function buildQuery(
550-
$data,
551-
string $numeric_prefix = '',
552-
?string $arg_separator = null,
553-
int $encoding_type = \PHP_QUERY_RFC3986
554-
): string {
555-
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
539+
* Build a query string from an array of key value pairs.
540+
*
541+
* This function can use the return value of `parse()` to build a query
542+
* string. This function does not modify the provided keys when an array is
543+
* encountered (like `http_build_query()` would).
544+
*
545+
* The function is copied from https://github.com/guzzle/psr7/blob/a243f80a1ca7fe8ceed4deee17f12c1930efe662/src/Query.php#L59-L112
546+
* with a modification which is described in https://github.com/guzzle/psr7/pull/603
547+
*
548+
* @param array $params Query string parameters.
549+
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
550+
* to encode using RFC3986, or PHP_QUERY_RFC1738
551+
* to encode using RFC1738.
552+
*/
553+
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): string
554+
{
555+
if (!$params) {
556+
return '';
557+
}
558+
559+
if ($encoding === false) {
560+
$encoder = function (string $str): string {
561+
return $str;
562+
};
563+
} elseif ($encoding === PHP_QUERY_RFC3986) {
564+
$encoder = 'rawurlencode';
565+
} elseif ($encoding === PHP_QUERY_RFC1738) {
566+
$encoder = 'urlencode';
567+
} else {
568+
throw new \InvalidArgumentException('Invalid type');
569+
}
570+
571+
$castBool = Configuration::BOOLEAN_FORMAT_INT == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()
572+
? function ($v) { return (int) $v; }
573+
: function ($v) { return $v ? 'true' : 'false'; };
574+
575+
$qs = '';
576+
foreach ($params as $k => $v) {
577+
$k = $encoder((string) $k);
578+
if (!is_array($v)) {
579+
$qs .= $k;
580+
$v = is_bool($v) ? $castBool($v) : $v;
581+
if ($v !== null) {
582+
$qs .= '='.$encoder((string) $v);
583+
}
584+
$qs .= '&';
585+
} else {
586+
foreach ($v as $vv) {
587+
$qs .= $k;
588+
$vv = is_bool($vv) ? $castBool($vv) : $vv;
589+
if ($vv !== null) {
590+
$qs .= '='.$encoder((string) $vv);
591+
}
592+
$qs .= '&';
593+
}
594+
}
595+
}
596+
597+
return $qs ? (string) substr($qs, 0, -1) : '';
556598
}
557599
}

modules/openapi-generator/src/main/resources/php/libraries/psr-18/api.mustache

+2-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
namespace {{apiPackage}};
2020

2121
use GuzzleHttp\Psr7\MultipartStream;
22-
use GuzzleHttp\Psr7\Query;
2322
use Http\Client\Common\Plugin\ErrorPlugin;
2423
use Http\Client\Common\Plugin\RedirectPlugin;
2524
use Http\Client\Common\PluginClient;
@@ -643,7 +642,7 @@ use function sprintf;
643642
644643
} else {
645644
// for HTTP post (form)
646-
$httpBody = Query::build($formParams);
645+
$httpBody = ObjectSerializer::buildQuery($formParams);
647646
}
648647
}
649648

@@ -762,7 +761,7 @@ use function sprintf;
762761
->withHost($host)
763762
->withScheme($scheme)
764763
->withPort($port)
765-
->withQuery(Query::build($queryParams));
764+
->withQuery(ObjectSerializer::buildQuery($queryParams));
766765
767766
if ($user) {
768767
$uri = $uri->withUserInfo($user, $password);

samples/client/echo_api/php-nextgen/src/ObjectSerializer.php

+56-17
Original file line numberDiff line numberDiff line change
@@ -539,22 +539,61 @@ public static function deserialize(mixed $data, string $class, array $httpHeader
539539
}
540540

541541
/**
542-
* Native `http_build_query` wrapper.
543-
* @see https://www.php.net/manual/en/function.http-build-query
544-
*
545-
* @param array|object $data May be an array or object containing properties.
546-
* @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.
547-
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
548-
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
549-
*
550-
* @return string
551-
*/
552-
public static function buildQuery(
553-
array|object $data,
554-
string $numeric_prefix = '',
555-
?string $arg_separator = null,
556-
int $encoding_type = \PHP_QUERY_RFC3986
557-
): string {
558-
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
542+
* Build a query string from an array of key value pairs.
543+
*
544+
* This function can use the return value of `parse()` to build a query
545+
* string. This function does not modify the provided keys when an array is
546+
* encountered (like `http_build_query()` would).
547+
*
548+
* @param array $params Query string parameters.
549+
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
550+
* to encode using RFC3986, or PHP_QUERY_RFC1738
551+
* to encode using RFC1738.
552+
*/
553+
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): string
554+
{
555+
if (!$params) {
556+
return '';
557+
}
558+
559+
if ($encoding === false) {
560+
$encoder = function (string $str): string {
561+
return $str;
562+
};
563+
} elseif ($encoding === PHP_QUERY_RFC3986) {
564+
$encoder = 'rawurlencode';
565+
} elseif ($encoding === PHP_QUERY_RFC1738) {
566+
$encoder = 'urlencode';
567+
} else {
568+
throw new \InvalidArgumentException('Invalid type');
569+
}
570+
571+
$castBool = Configuration::BOOLEAN_FORMAT_INT == Configuration::getDefaultConfiguration()->getBooleanFormatForQueryString()
572+
? function ($v) { return (int) $v; }
573+
: function ($v) { return $v ? 'true' : 'false'; };
574+
575+
$qs = '';
576+
foreach ($params as $k => $v) {
577+
$k = $encoder((string) $k);
578+
if (!is_array($v)) {
579+
$qs .= $k;
580+
$v = is_bool($v) ? $castBool($v) : $v;
581+
if ($v !== null) {
582+
$qs .= '='.$encoder((string) $v);
583+
}
584+
$qs .= '&';
585+
} else {
586+
foreach ($v as $vv) {
587+
$qs .= $k;
588+
$vv = is_bool($vv) ? $castBool($vv) : $vv;
589+
if ($vv !== null) {
590+
$qs .= '='.$encoder((string) $vv);
591+
}
592+
$qs .= '&';
593+
}
594+
}
595+
}
596+
597+
return $qs ? (string) substr($qs, 0, -1) : '';
559598
}
560599
}

samples/client/petstore/php-nextgen/OpenAPIClient-php/lib/ObjectSerializer.php

+64-14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030

3131
use GuzzleHttp\Psr7\Utils;
3232
use OpenAPI\Client\Model\ModelInterface;
33+
use function GuzzleHttp\Psr7\;
34+
use function is_array;
35+
use function is_bool;
36+
use function substr;
37+
use const PHP_QUERY_RFC1738;
38+
use const PHP_QUERY_RFC3986;
3339

3440
/**
3541
* ObjectSerializer Class Doc Comment
@@ -545,22 +551,66 @@ public static function deserialize($data, $class, $httpHeaders = null)
545551
}
546552

547553
/**
548-
* Native `http_build_query` wrapper.
549-
* @see https://www.php.net/manual/en/function.http-build-query
554+
* Build a query string from an array of key value pairs.
550555
*
551-
* @param array|object $data May be an array or object containing properties.
552-
* @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.
553-
* @param string|null $arg_separator arg_separator.output is used to separate arguments but may be overridden by specifying this parameter.
554-
* @param int $encoding_type Encoding type. By default, PHP_QUERY_RFC1738.
556+
* This function can use the return value of `parse()` to build a query
557+
* string. This function does not modify the provided keys when an array is
558+
* encountered (like `http_build_query()` would).
555559
*
556-
* @return string
560+
* The function is copied from https://github.com/guzzle/psr7/blob/a243f80a1ca7fe8ceed4deee17f12c1930efe662/src/Query.php#L59-L112
561+
* with a modification which is described in https://github.com/guzzle/psr7/pull/603
562+
*
563+
* @param array $params Query string parameters.
564+
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
565+
* to encode using RFC3986, or PHP_QUERY_RFC1738
566+
* to encode using RFC1738.
567+
* @param bool $treatBooleansAsInts When `true` values are cast to int (e.g. ['foo' => false] gives `foo=0`).
568+
* When `false` values are cast to strings (e.g. ['foo' => false] gives `foo=false`).
557569
*/
558-
public static function buildQuery(
559-
$data,
560-
string $numeric_prefix = '',
561-
?string $arg_separator = null,
562-
int $encoding_type = \PHP_QUERY_RFC3986
563-
): string {
564-
return \GuzzleHttp\Psr7\Query::build($data, $encoding_type);
570+
public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBooleansAsInts = true): string
571+
{
572+
if (!$params) {
573+
return '';
574+
}
575+
576+
if ($encoding === false) {
577+
$encoder = function (string $str): string {
578+
return $str;
579+
};
580+
} elseif ($encoding === PHP_QUERY_RFC3986) {
581+
$encoder = 'rawurlencode';
582+
} elseif ($encoding === PHP_QUERY_RFC1738) {
583+
$encoder = 'urlencode';
584+
} else {
585+
throw new \InvalidArgumentException('Invalid type');
586+
}
587+
588+
$castBool = $treatBooleansAsInts
589+
? function ($v) { return (int) $v; }
590+
: function ($v) { return $v ? 'true' : 'false'; };
591+
592+
$qs = '';
593+
foreach ($params as $k => $v) {
594+
$k = $encoder((string) $k);
595+
if (!is_array($v)) {
596+
$qs .= $k;
597+
$v = is_bool($v) ? $castBool($v) : $v;
598+
if ($v !== null) {
599+
$qs .= '='.$encoder((string) $v);
600+
}
601+
$qs .= '&';
602+
} else {
603+
foreach ($v as $vv) {
604+
$qs .= $k;
605+
$vv = is_bool($vv) ? $castBool($vv) : $vv;
606+
if ($vv !== null) {
607+
$qs .= '='.$encoder((string) $vv);
608+
}
609+
$qs .= '&';
610+
}
611+
}
612+
}
613+
614+
return $qs ? (string) substr($qs, 0, -1) : '';
565615
}
566616
}

0 commit comments

Comments
 (0)