From 2eaa93731c354c9cb64a41187ba25a1b271cfdea Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Fri, 14 Mar 2025 17:01:49 -0500 Subject: [PATCH 01/12] Output of CLI commands per PR comments --- .../enum-single-value/.openapi-generator/FILES | 4 ++-- .../enum-single-value/models/ObjectSerializer.ts | 14 ++++++-------- .../builds/enum-single-value/models/all.ts | 4 ++-- .../enum-single-value/types/ObjectParamAPI.ts | 4 ++-- .../enum-single-value/types/ObservableAPI.ts | 4 ++-- .../builds/enum-single-value/types/PromiseAPI.ts | 4 ++-- 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES b/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES index 832d1d1b6d4d..f586694f5f67 100644 --- a/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES +++ b/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES @@ -11,8 +11,8 @@ http/isomorphic-fetch.ts index.ts middleware.ts models/ObjectSerializer.ts -models/SingleValueEnum30.ts -models/SingleValueEnum31.ts +models/SomeObject.ts +models/WithNullableType.ts models/all.ts package.json rxjsStub.ts diff --git a/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts b/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts index 15b6c13639d3..d44f397943e3 100644 --- a/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts +++ b/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts @@ -1,8 +1,8 @@ -export * from '../models/SingleValueEnum30'; -export * from '../models/SingleValueEnum31'; +export * from '../models/SomeObject'; +export * from '../models/WithNullableType'; -import { SingleValueEnum30, SingleValueEnum30TypeEnum } from '../models/SingleValueEnum30'; -import { SingleValueEnum31, SingleValueEnum31TypeEnum } from '../models/SingleValueEnum31'; +import { SomeObject } from '../models/SomeObject'; +import { WithNullableType } from '../models/WithNullableType'; /* tslint:disable:no-unused-variable */ let primitives = [ @@ -17,13 +17,11 @@ let primitives = [ ]; let enumsMap: Set = new Set([ - "SingleValueEnum30TypeEnum", - "SingleValueEnum31TypeEnum", ]); let typeMap: {[index: string]: any} = { - "SingleValueEnum30": SingleValueEnum30, - "SingleValueEnum31": SingleValueEnum31, + "SomeObject": SomeObject, + "WithNullableType": WithNullableType, } type MimeTypeDescriptor = { diff --git a/samples/client/others/typescript/builds/enum-single-value/models/all.ts b/samples/client/others/typescript/builds/enum-single-value/models/all.ts index dc9e55201d87..ed435990d1a4 100644 --- a/samples/client/others/typescript/builds/enum-single-value/models/all.ts +++ b/samples/client/others/typescript/builds/enum-single-value/models/all.ts @@ -1,2 +1,2 @@ -export * from '../models/SingleValueEnum30' -export * from '../models/SingleValueEnum31' +export * from '../models/SomeObject' +export * from '../models/WithNullableType' diff --git a/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts b/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts index 766e01f37104..5daa1b27ef4d 100644 --- a/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts +++ b/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts @@ -2,5 +2,5 @@ import { ResponseContext, RequestContext, HttpFile, HttpInfo } from '../http/htt import { Configuration, ConfigurationOptions } from '../configuration' import type { Middleware } from '../middleware'; -import { SingleValueEnum30 } from '../models/SingleValueEnum30'; -import { SingleValueEnum31 } from '../models/SingleValueEnum31'; +import { SomeObject } from '../models/SomeObject'; +import { WithNullableType } from '../models/WithNullableType'; diff --git a/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts b/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts index 37167e1b30fa..ddca5054778e 100644 --- a/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts +++ b/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts @@ -3,5 +3,5 @@ import { Configuration, ConfigurationOptions } from '../configuration' import type { Middleware } from '../middleware'; import { Observable, of, from } from '../rxjsStub'; import {mergeMap, map} from '../rxjsStub'; -import { SingleValueEnum30 } from '../models/SingleValueEnum30'; -import { SingleValueEnum31 } from '../models/SingleValueEnum31'; +import { SomeObject } from '../models/SomeObject'; +import { WithNullableType } from '../models/WithNullableType'; diff --git a/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts b/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts index 55b1d0e53e26..d536e2b2790d 100644 --- a/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts +++ b/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts @@ -2,5 +2,5 @@ import { ResponseContext, RequestContext, HttpFile, HttpInfo } from '../http/htt import { Configuration, ConfigurationOptions, PromiseConfigurationOptions } from '../configuration' import { PromiseMiddleware, Middleware, PromiseMiddlewareWrapper } from '../middleware'; -import { SingleValueEnum30 } from '../models/SingleValueEnum30'; -import { SingleValueEnum31 } from '../models/SingleValueEnum31'; +import { SomeObject } from '../models/SomeObject'; +import { WithNullableType } from '../models/WithNullableType'; From 4518cd54cfa1b7e186650740510f5d85b380d40a Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Fri, 14 Mar 2025 16:53:33 -0500 Subject: [PATCH 02/12] Rebuilding PHP examples, PSR-18 --- .../php/libraries/psr-18/api.mustache | 4 +- .../petstore/php/psr-18/lib/Api/FakeApi.php | 36 +++--- .../petstore/php/psr-18/lib/Api/PetApi.php | 12 +- .../php/psr-18/lib/ObjectSerializer.php | 106 ++++++++++++++++-- 4 files changed, 125 insertions(+), 33 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php/libraries/psr-18/api.mustache b/modules/openapi-generator/src/main/resources/php/libraries/psr-18/api.mustache index 7b286d94d034..16e76da9074c 100644 --- a/modules/openapi-generator/src/main/resources/php/libraries/psr-18/api.mustache +++ b/modules/openapi-generator/src/main/resources/php/libraries/psr-18/api.mustache @@ -593,13 +593,13 @@ use function sprintf; $paramFiles = is_array(${{paramName}}) ? ${{paramName}} : [${{paramName}}]; foreach ($paramFiles as $paramFile) { $formParams['{{baseName}}'][] = \GuzzleHttp\Psr7\try_fopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('{{baseName}}', $paramFile)['{{baseName}}'], 'rb' ); } {{/isFile}} {{^isFile}} - $formParams['{{baseName}}'] = ObjectSerializer::toFormValue(${{paramName}}); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('{{baseName}}', ${{paramName}})); {{/isFile}} } {{/formParams}} diff --git a/samples/client/petstore/php/psr-18/lib/Api/FakeApi.php b/samples/client/petstore/php/psr-18/lib/Api/FakeApi.php index bc23dc9481f7..360a3b16f4c8 100644 --- a/samples/client/petstore/php/psr-18/lib/Api/FakeApi.php +++ b/samples/client/petstore/php/psr-18/lib/Api/FakeApi.php @@ -4002,39 +4002,39 @@ public function testEndpointParametersRequest($number, $double, $pattern_without // form params if ($integer !== null) { - $formParams['integer'] = ObjectSerializer::toFormValue($integer); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('integer', $integer)); } // form params if ($int32 !== null) { - $formParams['int32'] = ObjectSerializer::toFormValue($int32); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('int32', $int32)); } // form params if ($int64 !== null) { - $formParams['int64'] = ObjectSerializer::toFormValue($int64); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('int64', $int64)); } // form params if ($number !== null) { - $formParams['number'] = ObjectSerializer::toFormValue($number); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('number', $number)); } // form params if ($float !== null) { - $formParams['float'] = ObjectSerializer::toFormValue($float); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('float', $float)); } // form params if ($double !== null) { - $formParams['double'] = ObjectSerializer::toFormValue($double); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('double', $double)); } // form params if ($string !== null) { - $formParams['string'] = ObjectSerializer::toFormValue($string); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('string', $string)); } // form params if ($pattern_without_delimiter !== null) { - $formParams['pattern_without_delimiter'] = ObjectSerializer::toFormValue($pattern_without_delimiter); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('pattern_without_delimiter', $pattern_without_delimiter)); } // form params if ($byte !== null) { - $formParams['byte'] = ObjectSerializer::toFormValue($byte); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('byte', $byte)); } // form params if ($binary !== null) { @@ -4043,26 +4043,26 @@ public function testEndpointParametersRequest($number, $double, $pattern_without $paramFiles = is_array($binary) ? $binary : [$binary]; foreach ($paramFiles as $paramFile) { $formParams['binary'][] = \GuzzleHttp\Psr7\try_fopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('binary', $paramFile)['binary'], 'rb' ); } } // form params if ($date !== null) { - $formParams['date'] = ObjectSerializer::toFormValue($date); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('date', $date)); } // form params if ($date_time !== null) { - $formParams['dateTime'] = ObjectSerializer::toFormValue($date_time); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('dateTime', $date_time)); } // form params if ($password !== null) { - $formParams['password'] = ObjectSerializer::toFormValue($password); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('password', $password)); } // form params if ($callback !== null) { - $formParams['callback'] = ObjectSerializer::toFormValue($callback); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('callback', $callback)); } $headers = $this->headerSelector->selectHeaders( @@ -4371,11 +4371,11 @@ public function testEnumParametersRequest($enum_header_string_array = null, $enu // form params if ($enum_form_string_array !== null) { - $formParams['enum_form_string_array'] = ObjectSerializer::toFormValue($enum_form_string_array); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('enum_form_string_array', $enum_form_string_array)); } // form params if ($enum_form_string !== null) { - $formParams['enum_form_string'] = ObjectSerializer::toFormValue($enum_form_string); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('enum_form_string', $enum_form_string)); } $headers = $this->headerSelector->selectHeaders( @@ -5317,11 +5317,11 @@ public function testJsonFormDataRequest($param, $param2) // form params if ($param !== null) { - $formParams['param'] = ObjectSerializer::toFormValue($param); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('param', $param)); } // form params if ($param2 !== null) { - $formParams['param2'] = ObjectSerializer::toFormValue($param2); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('param2', $param2)); } $headers = $this->headerSelector->selectHeaders( diff --git a/samples/client/petstore/php/psr-18/lib/Api/PetApi.php b/samples/client/petstore/php/psr-18/lib/Api/PetApi.php index 09faf0678883..93805e939af4 100644 --- a/samples/client/petstore/php/psr-18/lib/Api/PetApi.php +++ b/samples/client/petstore/php/psr-18/lib/Api/PetApi.php @@ -1818,11 +1818,11 @@ public function updatePetWithFormRequest($pet_id, $name = null, $status = null) // form params if ($name !== null) { - $formParams['name'] = ObjectSerializer::toFormValue($name); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); } // form params if ($status !== null) { - $formParams['status'] = ObjectSerializer::toFormValue($status); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('status', $status)); } $headers = $this->headerSelector->selectHeaders( @@ -2094,7 +2094,7 @@ public function uploadFileRequest($pet_id, $additional_metadata = null, $file = // form params if ($additional_metadata !== null) { - $formParams['additionalMetadata'] = ObjectSerializer::toFormValue($additional_metadata); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('additionalMetadata', $additional_metadata)); } // form params if ($file !== null) { @@ -2103,7 +2103,7 @@ public function uploadFileRequest($pet_id, $additional_metadata = null, $file = $paramFiles = is_array($file) ? $file : [$file]; foreach ($paramFiles as $paramFile) { $formParams['file'][] = \GuzzleHttp\Psr7\try_fopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('file', $paramFile)['file'], 'rb' ); } @@ -2384,7 +2384,7 @@ public function uploadFileWithRequiredFileRequest($pet_id, $required_file, $addi // form params if ($additional_metadata !== null) { - $formParams['additionalMetadata'] = ObjectSerializer::toFormValue($additional_metadata); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('additionalMetadata', $additional_metadata)); } // form params if ($required_file !== null) { @@ -2393,7 +2393,7 @@ public function uploadFileWithRequiredFileRequest($pet_id, $required_file, $addi $paramFiles = is_array($required_file) ? $required_file : [$required_file]; foreach ($paramFiles as $paramFile) { $formParams['requiredFile'][] = \GuzzleHttp\Psr7\try_fopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('requiredFile', $paramFile)['requiredFile'], 'rb' ); } diff --git a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php index 440a243a41a6..5122618f9d0e 100644 --- a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php @@ -330,15 +330,28 @@ public static function toHeaderValue($value) * * @param string|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array */ - public static function toFormValue($value) + public static function toFormValue(string $key, mixed $value) { - if ($value instanceof \SplFileObject) { - return $value->getRealPath(); - } else { - return self::toString($value); + $stringable = self::toString($value); + + if ($stringable !== null) { + return [$key => $stringable]; + } elseif ($value instanceof \SplFileObject) { + return [$key => $value->getRealPath()]; } + + $flattened = []; + $result = []; + + self::flatten_array(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } + + return $result; } /** @@ -349,12 +362,14 @@ public static function toFormValue($value) * * @param float|int|bool|\DateTime $value the value of the parameter * - * @return string the header string + * @return string|null the header string */ public static function toString($value) { if ($value instanceof \DateTime) { // datetime in ISO8601 format return $value->format(self::$dateTimeFormat); + } elseif (!is_scalar($value) && $value !== null) { + return null; } elseif (is_bool($value)) { return $value ? 'true' : 'false'; } else { @@ -614,4 +629,81 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * @param \ArrayAccess|array $source + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flatten_array( + mixed $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + /** + * array_is_list only in PHP >= 8.1 + * + * credit: https://www.php.net/manual/en/function.array-is-list.php#127044 + */ + if (!function_exists('array_is_list')) { + function array_is_list(array $array) + { + $i = -1; + + foreach ($array as $k => $v) { + ++$i; + if ($k !== $i) { + return false; + } + } + + return true; + } + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flatten_array($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } From 2061ee6aee146fc867ec2b5ce813c5e594bb00ec Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Fri, 14 Mar 2025 14:09:23 -0500 Subject: [PATCH 03/12] Rebuilding PHP examples --- .../php/OpenAPIClient-php/lib/Api/FakeApi.php | 36 +++--- .../php/OpenAPIClient-php/lib/Api/PetApi.php | 12 +- .../lib/ObjectSerializer.php | 106 ++++++++++++++++-- 3 files changed, 123 insertions(+), 31 deletions(-) diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/Api/FakeApi.php b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/FakeApi.php index 8c2cde794df9..a89d506fec6e 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/Api/FakeApi.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/FakeApi.php @@ -4567,39 +4567,39 @@ public function testEndpointParametersRequest($number, $double, $pattern_without // form params if ($integer !== null) { - $formParams['integer'] = ObjectSerializer::toFormValue($integer); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('integer', $integer)); } // form params if ($int32 !== null) { - $formParams['int32'] = ObjectSerializer::toFormValue($int32); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('int32', $int32)); } // form params if ($int64 !== null) { - $formParams['int64'] = ObjectSerializer::toFormValue($int64); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('int64', $int64)); } // form params if ($number !== null) { - $formParams['number'] = ObjectSerializer::toFormValue($number); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('number', $number)); } // form params if ($float !== null) { - $formParams['float'] = ObjectSerializer::toFormValue($float); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('float', $float)); } // form params if ($double !== null) { - $formParams['double'] = ObjectSerializer::toFormValue($double); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('double', $double)); } // form params if ($string !== null) { - $formParams['string'] = ObjectSerializer::toFormValue($string); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('string', $string)); } // form params if ($pattern_without_delimiter !== null) { - $formParams['pattern_without_delimiter'] = ObjectSerializer::toFormValue($pattern_without_delimiter); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('pattern_without_delimiter', $pattern_without_delimiter)); } // form params if ($byte !== null) { - $formParams['byte'] = ObjectSerializer::toFormValue($byte); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('byte', $byte)); } // form params if ($binary !== null) { @@ -4608,26 +4608,26 @@ public function testEndpointParametersRequest($number, $double, $pattern_without $paramFiles = is_array($binary) ? $binary : [$binary]; foreach ($paramFiles as $paramFile) { $formParams['binary'][] = \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('binary', $paramFile)['binary'], 'rb' ); } } // form params if ($date !== null) { - $formParams['date'] = ObjectSerializer::toFormValue($date); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('date', $date)); } // form params if ($date_time !== null) { - $formParams['dateTime'] = ObjectSerializer::toFormValue($date_time); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('dateTime', $date_time)); } // form params if ($password !== null) { - $formParams['password'] = ObjectSerializer::toFormValue($password); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('password', $password)); } // form params if ($callback !== null) { - $formParams['callback'] = ObjectSerializer::toFormValue($callback); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('callback', $callback)); } $headers = $this->headerSelector->selectHeaders( @@ -4942,11 +4942,11 @@ public function testEnumParametersRequest($enum_header_string_array = null, $enu // form params if ($enum_form_string_array !== null) { - $formParams['enum_form_string_array'] = ObjectSerializer::toFormValue($enum_form_string_array); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('enum_form_string_array', $enum_form_string_array)); } // form params if ($enum_form_string !== null) { - $formParams['enum_form_string'] = ObjectSerializer::toFormValue($enum_form_string); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('enum_form_string', $enum_form_string)); } $headers = $this->headerSelector->selectHeaders( @@ -5920,11 +5920,11 @@ public function testJsonFormDataRequest($param, $param2, string $contentType = s // form params if ($param !== null) { - $formParams['param'] = ObjectSerializer::toFormValue($param); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('param', $param)); } // form params if ($param2 !== null) { - $formParams['param2'] = ObjectSerializer::toFormValue($param2); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('param2', $param2)); } $headers = $this->headerSelector->selectHeaders( diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php index 9313bf4f6356..60592be509c4 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php @@ -2224,11 +2224,11 @@ public function updatePetWithFormRequest($pet_id, $name = null, $status = null, // form params if ($name !== null) { - $formParams['name'] = ObjectSerializer::toFormValue($name); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); } // form params if ($status !== null) { - $formParams['status'] = ObjectSerializer::toFormValue($status); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('status', $status)); } $headers = $this->headerSelector->selectHeaders( @@ -2556,7 +2556,7 @@ public function uploadFileRequest($pet_id, $additional_metadata = null, $file = // form params if ($additional_metadata !== null) { - $formParams['additionalMetadata'] = ObjectSerializer::toFormValue($additional_metadata); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('additionalMetadata', $additional_metadata)); } // form params if ($file !== null) { @@ -2565,7 +2565,7 @@ public function uploadFileRequest($pet_id, $additional_metadata = null, $file = $paramFiles = is_array($file) ? $file : [$file]; foreach ($paramFiles as $paramFile) { $formParams['file'][] = \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('file', $paramFile)['file'], 'rb' ); } @@ -2903,7 +2903,7 @@ public function uploadFileWithRequiredFileRequest($pet_id, $required_file, $addi // form params if ($additional_metadata !== null) { - $formParams['additionalMetadata'] = ObjectSerializer::toFormValue($additional_metadata); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('additionalMetadata', $additional_metadata)); } // form params if ($required_file !== null) { @@ -2912,7 +2912,7 @@ public function uploadFileWithRequiredFileRequest($pet_id, $required_file, $addi $paramFiles = is_array($required_file) ? $required_file : [$required_file]; foreach ($paramFiles as $paramFile) { $formParams['requiredFile'][] = \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('requiredFile', $paramFile)['requiredFile'], 'rb' ); } diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php index 440a243a41a6..5122618f9d0e 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php @@ -330,15 +330,28 @@ public static function toHeaderValue($value) * * @param string|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array */ - public static function toFormValue($value) + public static function toFormValue(string $key, mixed $value) { - if ($value instanceof \SplFileObject) { - return $value->getRealPath(); - } else { - return self::toString($value); + $stringable = self::toString($value); + + if ($stringable !== null) { + return [$key => $stringable]; + } elseif ($value instanceof \SplFileObject) { + return [$key => $value->getRealPath()]; } + + $flattened = []; + $result = []; + + self::flatten_array(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } + + return $result; } /** @@ -349,12 +362,14 @@ public static function toFormValue($value) * * @param float|int|bool|\DateTime $value the value of the parameter * - * @return string the header string + * @return string|null the header string */ public static function toString($value) { if ($value instanceof \DateTime) { // datetime in ISO8601 format return $value->format(self::$dateTimeFormat); + } elseif (!is_scalar($value) && $value !== null) { + return null; } elseif (is_bool($value)) { return $value ? 'true' : 'false'; } else { @@ -614,4 +629,81 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * @param \ArrayAccess|array $source + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flatten_array( + mixed $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + /** + * array_is_list only in PHP >= 8.1 + * + * credit: https://www.php.net/manual/en/function.array-is-list.php#127044 + */ + if (!function_exists('array_is_list')) { + function array_is_list(array $array) + { + $i = -1; + + foreach ($array as $k => $v) { + ++$i; + if ($k !== $i) { + return false; + } + } + + return true; + } + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flatten_array($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } From c82355d6595911eab9cbdd71b853c5acfe1f7a3c Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Fri, 14 Mar 2025 14:01:32 -0500 Subject: [PATCH 04/12] Adds explanation for ::flatten_array(); optimized array_is_list pollyfill --- .../resources/php/ObjectSerializer.mustache | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache index 7c2a64ee47b4..830c5f1d7948 100644 --- a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache @@ -605,4 +605,81 @@ class ObjectSerializer return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * @param \ArrayAccess|array $source + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flatten_array( + mixed $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + /** + * array_is_list only in PHP >= 8.1 + * + * credit: https://www.php.net/manual/en/function.array-is-list.php#127044 + */ + if (!function_exists('array_is_list')) { + function array_is_list(array $array) + { + $i = -1; + + foreach ($array as $k => $v) { + ++$i; + if ($k !== $i) { + return false; + } + } + + return true; + } + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flatten_array($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } From abbbc2d1a0eca2b37718fb7fb436fd0d332d88ae Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Fri, 14 Mar 2025 11:36:27 -0500 Subject: [PATCH 05/12] [PHP] Fix converting objects to formdata --- .../resources/php/ObjectSerializer.mustache | 29 ++++++++++++++----- .../src/main/resources/php/api.mustache | 4 +-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache index 830c5f1d7948..7ac9fe98f96e 100644 --- a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache @@ -321,15 +321,28 @@ class ObjectSerializer * * @param string|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array */ - public static function toFormValue($value) + public static function toFormValue(string $key, mixed $value) { - if ($value instanceof \SplFileObject) { - return $value->getRealPath(); - } else { - return self::toString($value); + $stringable = self::toString($value); + + if ($stringable !== null) { + return [$key => $stringable]; + } elseif ($value instanceof \SplFileObject) { + return [$key => $value->getRealPath()]; + } + + $flattened = []; + $result = []; + + self::flatten_array(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); } + + return $result; } /** @@ -340,12 +353,14 @@ class ObjectSerializer * * @param float|int|bool|\DateTime $value the value of the parameter * - * @return string the header string + * @return string|null the header string */ public static function toString($value) { if ($value instanceof \DateTime) { // datetime in ISO8601 format return $value->format(self::$dateTimeFormat); + } elseif (!is_scalar($value) && $value !== null) { + return null; } elseif (is_bool($value)) { return $value ? 'true' : 'false'; } else { diff --git a/modules/openapi-generator/src/main/resources/php/api.mustache b/modules/openapi-generator/src/main/resources/php/api.mustache index fedb7d532412..f6246863be4d 100644 --- a/modules/openapi-generator/src/main/resources/php/api.mustache +++ b/modules/openapi-generator/src/main/resources/php/api.mustache @@ -677,13 +677,13 @@ use {{invokerPackage}}\ObjectSerializer; $paramFiles = is_array(${{paramName}}) ? ${{paramName}} : [${{paramName}}]; foreach ($paramFiles as $paramFile) { $formParams['{{baseName}}'][] = \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('{{baseName}}', $paramFile)['{{baseName}}'], 'rb' ); } {{/isFile}} {{^isFile}} - $formParams['{{baseName}}'] = ObjectSerializer::toFormValue(${{paramName}}); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('{{baseName}}', ${{paramName}})); {{/isFile}} } {{/formParams}} From c81808b6a31180b66e9f5f02f448f4e34e153668 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Sat, 15 Mar 2025 12:57:37 -0500 Subject: [PATCH 06/12] flatten_array -> flattenArray to match code style --- .../src/main/resources/php/ObjectSerializer.mustache | 6 +++--- .../petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php | 6 +++--- samples/client/petstore/php/psr-18/lib/ObjectSerializer.php | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache index 7ac9fe98f96e..d6010f005db3 100644 --- a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache @@ -336,7 +336,7 @@ class ObjectSerializer $flattened = []; $result = []; - self::flatten_array(json_decode(json_encode($value), true), $flattened); + self::flattenArray(json_decode(json_encode($value), true), $flattened); foreach ($flattened as $k => $v) { $result["{$key}{$k}"] = self::toString($v); @@ -630,7 +630,7 @@ class ObjectSerializer * * credit: https://github.com/FranBar1966/FlatPHP */ - private static function flatten_array( + private static function flattenArray( mixed $source, array &$destination, string $start = '', @@ -686,7 +686,7 @@ class ObjectSerializer if (is_array($val) && !empty($val)) { $currentName .= "{$currentSuffix}"; - self::flatten_array($val, $destination, $currentName); + self::flattenArray($val, $destination, $currentName); } else { if ($currentSuffixEnd) { $currentName .= $currentSuffix; diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php index 5122618f9d0e..b5c79e57c125 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php @@ -345,7 +345,7 @@ public static function toFormValue(string $key, mixed $value) $flattened = []; $result = []; - self::flatten_array(json_decode(json_encode($value), true), $flattened); + self::flattenArray(json_decode(json_encode($value), true), $flattened); foreach ($flattened as $k => $v) { $result["{$key}{$k}"] = self::toString($v); @@ -639,7 +639,7 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): * * credit: https://github.com/FranBar1966/FlatPHP */ - private static function flatten_array( + private static function flattenArray( mixed $source, array &$destination, string $start = '', @@ -695,7 +695,7 @@ function array_is_list(array $array) if (is_array($val) && !empty($val)) { $currentName .= "{$currentSuffix}"; - self::flatten_array($val, $destination, $currentName); + self::flattenArray($val, $destination, $currentName); } else { if ($currentSuffixEnd) { $currentName .= $currentSuffix; diff --git a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php index 5122618f9d0e..b5c79e57c125 100644 --- a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php @@ -345,7 +345,7 @@ public static function toFormValue(string $key, mixed $value) $flattened = []; $result = []; - self::flatten_array(json_decode(json_encode($value), true), $flattened); + self::flattenArray(json_decode(json_encode($value), true), $flattened); foreach ($flattened as $k => $v) { $result["{$key}{$k}"] = self::toString($v); @@ -639,7 +639,7 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): * * credit: https://github.com/FranBar1966/FlatPHP */ - private static function flatten_array( + private static function flattenArray( mixed $source, array &$destination, string $start = '', @@ -695,7 +695,7 @@ function array_is_list(array $array) if (is_array($val) && !empty($val)) { $currentName .= "{$currentSuffix}"; - self::flatten_array($val, $destination, $currentName); + self::flattenArray($val, $destination, $currentName); } else { if ($currentSuffixEnd) { $currentName .= $currentSuffix; From e9cb42e0b9bb045bc5e4f6e73b9c154fd2a64878 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Sat, 15 Mar 2025 15:35:12 -0500 Subject: [PATCH 07/12] Adds unit test --- ...ith-fake-endpoints-models-for-testing.yaml | 79 ++++ .../petstore/php/OpenAPIClient-php/README.md | 1 + .../php/OpenAPIClient-php/docs/Api/PetApi.md | 77 ++++ .../php/OpenAPIClient-php/lib/Api/PetApi.php | 424 ++++++++++++++++++ .../OpenAPIClient-php/tests/PetApiTest.php | 81 +++- samples/client/petstore/php/psr-18/README.md | 1 + .../petstore/php/psr-18/docs/Api/PetApi.md | 77 ++++ .../petstore/php/psr-18/lib/Api/PetApi.php | 359 +++++++++++++++ 8 files changed, 1096 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/test/resources/3_0/php/petstore-with-fake-endpoints-models-for-testing.yaml b/modules/openapi-generator/src/test/resources/3_0/php/petstore-with-fake-endpoints-models-for-testing.yaml index d9e47ca9ed8d..e971a99dc261 100644 --- a/modules/openapi-generator/src/test/resources/3_0/php/petstore-with-fake-endpoints-models-for-testing.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/php/petstore-with-fake-endpoints-models-for-testing.yaml @@ -311,6 +311,37 @@ paths: description: file to upload type: string format: binary + '/pet/{petId}/uploadImageFullFormData': + post: + tags: + - pet + summary: uploads an image attached to a Pet object as formdata + description: '' + operationId: uploadImageFullFormData + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/PetWithFile' /store/inventory: get: tags: @@ -1566,6 +1597,54 @@ components: - sold xml: name: Pet + PetWithFile: + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + x-is-unique: true + category: + $ref: '#/components/schemas/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + uniqueItems: true + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + file: + description: file to upload + type: string + format: binary + multiple_files: + type: array + items: + type: string + format: binary + xml: + name: PetWithFile ApiResponse: type: object properties: diff --git a/samples/client/petstore/php/OpenAPIClient-php/README.md b/samples/client/petstore/php/OpenAPIClient-php/README.md index 18918e09409b..d6f67751a753 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/README.md +++ b/samples/client/petstore/php/OpenAPIClient-php/README.md @@ -107,6 +107,7 @@ Class | Method | HTTP request | Description *PetApi* | [**updatePetWithForm**](docs/Api/PetApi.md#updatepetwithform) | **POST** /pet/{petId} | Updates a pet in the store with form data *PetApi* | [**uploadFile**](docs/Api/PetApi.md#uploadfile) | **POST** /pet/{petId}/uploadImage | uploads an image *PetApi* | [**uploadFileWithRequiredFile**](docs/Api/PetApi.md#uploadfilewithrequiredfile) | **POST** /fake/{petId}/uploadImageWithRequiredFile | uploads an image (required) +*PetApi* | [**uploadImageFullFormData**](docs/Api/PetApi.md#uploadimagefullformdata) | **POST** /pet/{petId}/uploadImageFullFormData | uploads an image attached to a Pet object as formdata *StoreApi* | [**deleteOrder**](docs/Api/StoreApi.md#deleteorder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID *StoreApi* | [**getInventory**](docs/Api/StoreApi.md#getinventory) | **GET** /store/inventory | Returns pet inventories by status *StoreApi* | [**getOrderById**](docs/Api/StoreApi.md#getorderbyid) | **GET** /store/order/{order_id} | Find purchase order by ID diff --git a/samples/client/petstore/php/OpenAPIClient-php/docs/Api/PetApi.md b/samples/client/petstore/php/OpenAPIClient-php/docs/Api/PetApi.md index 3a832aa82a56..b81cba25df60 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/docs/Api/PetApi.md +++ b/samples/client/petstore/php/OpenAPIClient-php/docs/Api/PetApi.md @@ -13,6 +13,7 @@ All URIs are relative to http://petstore.swagger.io:80/v2, except if the operati | [**updatePetWithForm()**](PetApi.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data | | [**uploadFile()**](PetApi.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image | | [**uploadFileWithRequiredFile()**](PetApi.md#uploadFileWithRequiredFile) | **POST** /fake/{petId}/uploadImageWithRequiredFile | uploads an image (required) | +| [**uploadImageFullFormData()**](PetApi.md#uploadImageFullFormData) | **POST** /pet/{petId}/uploadImageFullFormData | uploads an image attached to a Pet object as formdata | ## `addPet()` @@ -612,3 +613,79 @@ try { [[Back to top]](#) [[Back to API list]](../../README.md#endpoints) [[Back to Model list]](../../README.md#models) [[Back to README]](../../README.md) + +## `uploadImageFullFormData()` + +```php +uploadImageFullFormData($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files): \OpenAPI\Client\Model\ApiResponse +``` + +uploads an image attached to a Pet object as formdata + + + +### Example + +```php +setAccessToken('YOUR_ACCESS_TOKEN'); + + +$apiInstance = new OpenAPI\Client\Api\PetApi( + // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`. + // This is optional, `GuzzleHttp\Client` will be used as default. + new GuzzleHttp\Client(), + $config +); +$pet_id = 56; // int | ID of pet to update +$name = 'name_example'; // string +$photo_urls = array('photo_urls_example'); // string[] +$id = 56; // int +$category = new \OpenAPI\Client\Model\Category(); // \OpenAPI\Client\Model\Category +$tags = array(new \OpenAPI\Client\Model\\OpenAPI\Client\Model\Tag()); // \OpenAPI\Client\Model\Tag[] +$status = 'status_example'; // string | pet status in the store +$file = '/path/to/file.txt'; // \SplFileObject | file to upload +$multiple_files = array('/path/to/file.txt'); // \SplFileObject[] + +try { + $result = $apiInstance->uploadImageFullFormData($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files); + print_r($result); +} catch (Exception $e) { + echo 'Exception when calling PetApi->uploadImageFullFormData: ', $e->getMessage(), PHP_EOL; +} +``` + +### Parameters + +| Name | Type | Description | Notes | +| ------------- | ------------- | ------------- | ------------- | +| **pet_id** | **int**| ID of pet to update | | +| **name** | **string**| | | +| **photo_urls** | [**string[]**](../Model/string.md)| | | +| **id** | **int**| | [optional] | +| **category** | [**\OpenAPI\Client\Model\Category**](../Model/Category.md)| | [optional] | +| **tags** | [**\OpenAPI\Client\Model\Tag[]**](../Model/\OpenAPI\Client\Model\Tag.md)| | [optional] | +| **status** | **string**| pet status in the store | [optional] | +| **file** | **\SplFileObject****\SplFileObject**| file to upload | [optional] | +| **multiple_files** | **\SplFileObject[]**| | [optional] | + +### Return type + +[**\OpenAPI\Client\Model\ApiResponse**](../Model/ApiResponse.md) + +### Authorization + +[petstore_auth](../../README.md#petstore_auth) + +### HTTP request headers + +- **Content-Type**: `multipart/form-data` +- **Accept**: `application/json` + +[[Back to top]](#) [[Back to API list]](../../README.md#endpoints) +[[Back to Model list]](../../README.md#models) +[[Back to README]](../../README.md) diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php index 60592be509c4..afc732bd153a 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/PetApi.php @@ -100,6 +100,9 @@ class PetApi 'uploadFileWithRequiredFile' => [ 'multipart/form-data', ], + 'uploadImageFullFormData' => [ + 'multipart/form-data', + ], ]; /** @@ -2976,6 +2979,427 @@ public function uploadFileWithRequiredFileRequest($pet_id, $required_file, $addi ); } + /** + * Operation uploadImageFullFormData + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name name (required) + * @param string[] $photo_urls photo_urls (required) + * @param int|null $id id (optional) + * @param \OpenAPI\Client\Model\Category|null $category category (optional) + * @param \OpenAPI\Client\Model\Tag[]|null $tags tags (optional) + * @param string|null $status pet status in the store (optional) + * @param \SplFileObject|null $file file to upload (optional) + * @param \SplFileObject[]|null $multiple_files multiple_files (optional) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImageFullFormData'] to see the possible values for this operation + * + * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format + * @throws \InvalidArgumentException + * @return \OpenAPI\Client\Model\ApiResponse + */ + public function uploadImageFullFormData($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null, string $contentType = self::contentTypes['uploadImageFullFormData'][0]) + { + list($response) = $this->uploadImageFullFormDataWithHttpInfo($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files, $contentType); + return $response; + } + + /** + * Operation uploadImageFullFormDataWithHttpInfo + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int|null $id (optional) + * @param \OpenAPI\Client\Model\Category|null $category (optional) + * @param \OpenAPI\Client\Model\Tag[]|null $tags (optional) + * @param string|null $status pet status in the store (optional) + * @param \SplFileObject|null $file file to upload (optional) + * @param \SplFileObject[]|null $multiple_files (optional) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImageFullFormData'] to see the possible values for this operation + * + * @throws \OpenAPI\Client\ApiException on non-2xx response or if the response body is not in the expected format + * @throws \InvalidArgumentException + * @return array of \OpenAPI\Client\Model\ApiResponse, HTTP status code, HTTP response headers (array of strings) + */ + public function uploadImageFullFormDataWithHttpInfo($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null, string $contentType = self::contentTypes['uploadImageFullFormData'][0]) + { + $request = $this->uploadImageFullFormDataRequest($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files, $contentType); + + try { + $options = $this->createHttpClientOption(); + try { + $response = $this->client->send($request, $options); + } catch (RequestException $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + $e->getResponse() ? $e->getResponse()->getHeaders() : null, + $e->getResponse() ? (string) $e->getResponse()->getBody() : null + ); + } catch (ConnectException $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + null, + null + ); + } + + $statusCode = $response->getStatusCode(); + + + switch($statusCode) { + case 200: + if ('\OpenAPI\Client\Model\ApiResponse' === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + if ('\OpenAPI\Client\Model\ApiResponse' !== 'string') { + try { + $content = json_decode($content, false, 512, JSON_THROW_ON_ERROR); + } catch (\JsonException $exception) { + throw new ApiException( + sprintf( + 'Error JSON decoding server response (%s)', + $request->getUri() + ), + $statusCode, + $response->getHeaders(), + $content + ); + } + } + } + + return [ + ObjectSerializer::deserialize($content, '\OpenAPI\Client\Model\ApiResponse', []), + $response->getStatusCode(), + $response->getHeaders() + ]; + } + + if ($statusCode < 200 || $statusCode > 299) { + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + (string) $request->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + + $returnType = '\OpenAPI\Client\Model\ApiResponse'; + if ($returnType === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + if ($returnType !== 'string') { + try { + $content = json_decode($content, false, 512, JSON_THROW_ON_ERROR); + } catch (\JsonException $exception) { + throw new ApiException( + sprintf( + 'Error JSON decoding server response (%s)', + $request->getUri() + ), + $statusCode, + $response->getHeaders(), + $content + ); + } + } + } + + return [ + ObjectSerializer::deserialize($content, $returnType, []), + $response->getStatusCode(), + $response->getHeaders() + ]; + + } catch (ApiException $e) { + switch ($e->getCode()) { + case 200: + $data = ObjectSerializer::deserialize( + $e->getResponseBody(), + '\OpenAPI\Client\Model\ApiResponse', + $e->getResponseHeaders() + ); + $e->setResponseObject($data); + break; + } + throw $e; + } + } + + /** + * Operation uploadImageFullFormDataAsync + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int|null $id (optional) + * @param \OpenAPI\Client\Model\Category|null $category (optional) + * @param \OpenAPI\Client\Model\Tag[]|null $tags (optional) + * @param string|null $status pet status in the store (optional) + * @param \SplFileObject|null $file file to upload (optional) + * @param \SplFileObject[]|null $multiple_files (optional) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImageFullFormData'] to see the possible values for this operation + * + * @throws \InvalidArgumentException + * @return \GuzzleHttp\Promise\PromiseInterface + */ + public function uploadImageFullFormDataAsync($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null, string $contentType = self::contentTypes['uploadImageFullFormData'][0]) + { + return $this->uploadImageFullFormDataAsyncWithHttpInfo($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files, $contentType) + ->then( + function ($response) { + return $response[0]; + } + ); + } + + /** + * Operation uploadImageFullFormDataAsyncWithHttpInfo + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int|null $id (optional) + * @param \OpenAPI\Client\Model\Category|null $category (optional) + * @param \OpenAPI\Client\Model\Tag[]|null $tags (optional) + * @param string|null $status pet status in the store (optional) + * @param \SplFileObject|null $file file to upload (optional) + * @param \SplFileObject[]|null $multiple_files (optional) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImageFullFormData'] to see the possible values for this operation + * + * @throws \InvalidArgumentException + * @return \GuzzleHttp\Promise\PromiseInterface + */ + public function uploadImageFullFormDataAsyncWithHttpInfo($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null, string $contentType = self::contentTypes['uploadImageFullFormData'][0]) + { + $returnType = '\OpenAPI\Client\Model\ApiResponse'; + $request = $this->uploadImageFullFormDataRequest($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files, $contentType); + + return $this->client + ->sendAsync($request, $this->createHttpClientOption()) + ->then( + function ($response) use ($returnType) { + if ($returnType === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + if ($returnType !== 'string') { + $content = json_decode($content); + } + } + + return [ + ObjectSerializer::deserialize($content, $returnType, []), + $response->getStatusCode(), + $response->getHeaders() + ]; + }, + function ($exception) { + $response = $exception->getResponse(); + $statusCode = $response->getStatusCode(); + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + $exception->getRequest()->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + ); + } + + /** + * Create request for operation 'uploadImageFullFormData' + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int|null $id (optional) + * @param \OpenAPI\Client\Model\Category|null $category (optional) + * @param \OpenAPI\Client\Model\Tag[]|null $tags (optional) + * @param string|null $status pet status in the store (optional) + * @param \SplFileObject|null $file file to upload (optional) + * @param \SplFileObject[]|null $multiple_files (optional) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['uploadImageFullFormData'] to see the possible values for this operation + * + * @throws \InvalidArgumentException + * @return \GuzzleHttp\Psr7\Request + */ + public function uploadImageFullFormDataRequest($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null, string $contentType = self::contentTypes['uploadImageFullFormData'][0]) + { + + // verify the required parameter 'pet_id' is set + if ($pet_id === null || (is_array($pet_id) && count($pet_id) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $pet_id when calling uploadImageFullFormData' + ); + } + + // verify the required parameter 'name' is set + if ($name === null || (is_array($name) && count($name) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $name when calling uploadImageFullFormData' + ); + } + + // verify the required parameter 'photo_urls' is set + if ($photo_urls === null || (is_array($photo_urls) && count($photo_urls) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $photo_urls when calling uploadImageFullFormData' + ); + } + + + + + + + + + $resourcePath = '/pet/{petId}/uploadImageFullFormData'; + $formParams = []; + $queryParams = []; + $headerParams = []; + $httpBody = ''; + $multipart = false; + + + + // path params + if ($pet_id !== null) { + $resourcePath = str_replace( + '{' . 'petId' . '}', + ObjectSerializer::toPathValue($pet_id), + $resourcePath + ); + } + + // form params + if ($id !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('id', $id)); + } + // form params + if ($category !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('category', $category)); + } + // form params + if ($name !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); + } + // form params + if ($photo_urls !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('photoUrls', $photo_urls)); + } + // form params + if ($tags !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('tags', $tags)); + } + // form params + if ($status !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('status', $status)); + } + // form params + if ($file !== null) { + $multipart = true; + $formParams['file'] = []; + $paramFiles = is_array($file) ? $file : [$file]; + foreach ($paramFiles as $paramFile) { + $formParams['file'][] = \GuzzleHttp\Psr7\Utils::tryFopen( + ObjectSerializer::toFormValue('file', $paramFile)['file'], + 'rb' + ); + } + } + // form params + if ($multiple_files !== null) { + $multipart = true; + $formParams['multiple_files'] = []; + $paramFiles = is_array($multiple_files) ? $multiple_files : [$multiple_files]; + foreach ($paramFiles as $paramFile) { + $formParams['multiple_files'][] = \GuzzleHttp\Psr7\Utils::tryFopen( + ObjectSerializer::toFormValue('multiple_files', $paramFile)['multiple_files'], + 'rb' + ); + } + } + + $multipart = true; + $headers = $this->headerSelector->selectHeaders( + ['application/json', ], + $contentType, + $multipart + ); + + // for model (json/xml) + if (count($formParams) > 0) { + if ($multipart) { + $multipartContents = []; + foreach ($formParams as $formParamName => $formParamValue) { + $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue]; + foreach ($formParamValueItems as $formParamValueItem) { + $multipartContents[] = [ + 'name' => $formParamName, + 'contents' => $formParamValueItem + ]; + } + } + // for HTTP post (form) + $httpBody = new MultipartStream($multipartContents); + + } elseif (stripos($headers['Content-Type'], 'application/json') !== false) { + # if Content-Type contains "application/json", json_encode the form parameters + $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams); + } else { + // for HTTP post (form) + $httpBody = ObjectSerializer::buildQuery($formParams); + } + } + + // this endpoint requires OAuth (access token) + if (!empty($this->config->getAccessToken())) { + $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken(); + } + + $defaultHeaders = []; + if ($this->config->getUserAgent()) { + $defaultHeaders['User-Agent'] = $this->config->getUserAgent(); + } + + $headers = array_merge( + $defaultHeaders, + $headerParams, + $headers + ); + + $operationHost = $this->config->getHost(); + $query = ObjectSerializer::buildQuery($queryParams); + return new Request( + 'POST', + $operationHost . $resourcePath . ($query ? "?{$query}" : ''), + $headers, + $httpBody + ); + } + /** * Create http client option * diff --git a/samples/client/petstore/php/OpenAPIClient-php/tests/PetApiTest.php b/samples/client/petstore/php/OpenAPIClient-php/tests/PetApiTest.php index e7a8b97419a5..463f36a78af0 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/tests/PetApiTest.php +++ b/samples/client/petstore/php/OpenAPIClient-php/tests/PetApiTest.php @@ -45,9 +45,6 @@ public static function setUpBeforeClass(): void $config = new Configuration(); $petApi = new Api\PetApi(null, $config); - // add a new pet (model) - list(, $status) = $petApi->addPetWithHttpInfo($newPet); - Assert::assertEquals(200, $status); } public function setUp(): void @@ -371,6 +368,84 @@ public function testInvalidArgument() $this->api->findPetsByStatus([]); } + public function testObjectInFormData() + { + $category = (new Model\Category()) + ->setId(12345) + ->setName("Category_Name"); + + $tags_1 = (new Model\Tag()) + ->setId(12345) + ->setName("tag_1"); + + $tags_2 = (new Model\Tag()) + ->setId(98765) + ->setName("tag_2"); + + /** @var Model\Tag[] $tags */ + $tags = [ + $tags_1, + $tags_2, + ]; + + $pet_id = 56; + $name = "My pet name"; + $photo_urls = [ + "https://example.com/picture_1.jpg", + "https://example.com/picture_2.jpg", + ]; + $id = 12345; + $status = Model\Pet::STATUS_AVAILABLE; + $file = new \SplFileObject(__DIR__ . '/../.openapi-generator/VERSION'); + $multiple_files = [ + $file, + $file, + ]; + + $request = (new Api\PetApi())->uploadImageFullFormDataRequest( + $pet_id, + $name, + $photo_urls, + $id, + $category, + $tags, + $status, + $file, + $multiple_files, + ); + + $contents = $request->getBody()->getContents(); + + $this->assertBodyContents('name', $name, $contents); + $this->assertBodyContents('photoUrls[0]', $photo_urls[0], $contents); + $this->assertBodyContents('photoUrls[1]', $photo_urls[1], $contents); + $this->assertBodyContents('category[id]', $category->getId(), $contents); + $this->assertBodyContents('category[name]', $category->getName(), $contents); + $this->assertBodyContents('tags[0][id]', $tags[0]->getId(), $contents); + $this->assertBodyContents('tags[0][name]', $tags[0]->getName(), $contents); + $this->assertBodyContents('tags[1][id]', $tags[1]->getId(), $contents); + $this->assertBodyContents('tags[1][name]', $tags[1]->getName(), $contents); + $this->assertBodyContents('status', $status, $contents); + } + + private function assertBodyContents( + string $name, + mixed $value, + string $contents, + ) { + $length = strlen((string) ($value)); + $contents = implode("\n", array_map('trim', explode("\n", $contents))); + + $expected = <<assertStringContainsString($expected, $contents); + } + // Disabled as currently we don't have any endpoint that would return file // For testing I just replaced url and return type in Api method. // public function testDownloadingLargeFile() diff --git a/samples/client/petstore/php/psr-18/README.md b/samples/client/petstore/php/psr-18/README.md index 0dde61cbcb76..1c8d4f2541ce 100644 --- a/samples/client/petstore/php/psr-18/README.md +++ b/samples/client/petstore/php/psr-18/README.md @@ -118,6 +118,7 @@ Class | Method | HTTP request | Description *PetApi* | [**updatePetWithForm**](docs/Api/PetApi.md#updatepetwithform) | **POST** /pet/{petId} | Updates a pet in the store with form data *PetApi* | [**uploadFile**](docs/Api/PetApi.md#uploadfile) | **POST** /pet/{petId}/uploadImage | uploads an image *PetApi* | [**uploadFileWithRequiredFile**](docs/Api/PetApi.md#uploadfilewithrequiredfile) | **POST** /fake/{petId}/uploadImageWithRequiredFile | uploads an image (required) +*PetApi* | [**uploadImageFullFormData**](docs/Api/PetApi.md#uploadimagefullformdata) | **POST** /pet/{petId}/uploadImageFullFormData | uploads an image attached to a Pet object as formdata *StoreApi* | [**deleteOrder**](docs/Api/StoreApi.md#deleteorder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID *StoreApi* | [**getInventory**](docs/Api/StoreApi.md#getinventory) | **GET** /store/inventory | Returns pet inventories by status *StoreApi* | [**getOrderById**](docs/Api/StoreApi.md#getorderbyid) | **GET** /store/order/{order_id} | Find purchase order by ID diff --git a/samples/client/petstore/php/psr-18/docs/Api/PetApi.md b/samples/client/petstore/php/psr-18/docs/Api/PetApi.md index 1c7add7728a6..1b5a4c942fd5 100644 --- a/samples/client/petstore/php/psr-18/docs/Api/PetApi.md +++ b/samples/client/petstore/php/psr-18/docs/Api/PetApi.md @@ -13,6 +13,7 @@ Method | HTTP request | Description [**updatePetWithForm()**](PetApi.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data [**uploadFile()**](PetApi.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image [**uploadFileWithRequiredFile()**](PetApi.md#uploadFileWithRequiredFile) | **POST** /fake/{petId}/uploadImageWithRequiredFile | uploads an image (required) +[**uploadImageFullFormData()**](PetApi.md#uploadImageFullFormData) | **POST** /pet/{petId}/uploadImageFullFormData | uploads an image attached to a Pet object as formdata ## `addPet()` @@ -566,3 +567,79 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../../README.md#endpoints) [[Back to Model list]](../../README.md#models) [[Back to README]](../../README.md) + +## `uploadImageFullFormData()` + +```php +uploadImageFullFormData($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files): \OpenAPI\Client\Model\ApiResponse +``` + +uploads an image attached to a Pet object as formdata + + + +### Example + +```php +setAccessToken('YOUR_ACCESS_TOKEN'); + + +$apiInstance = new OpenAPI\Client\Api\PetApi( + // If you want use custom http client, pass your client which implements `Psr\Http\Client\ClientInterface`. + // This is optional, `Psr18ClientDiscovery` will be used to find http client. For instance `GuzzleHttp\Client` implements that interface + new GuzzleHttp\Client(), + $config +); +$pet_id = 56; // int | ID of pet to update +$name = 'name_example'; // string +$photo_urls = array('photo_urls_example'); // string[] +$id = 56; // int +$category = new \OpenAPI\Client\Model\Category(); // \OpenAPI\Client\Model\Category +$tags = array(new \OpenAPI\Client\Model\\OpenAPI\Client\Model\Tag()); // \OpenAPI\Client\Model\Tag[] +$status = 'status_example'; // string | pet status in the store +$file = '/path/to/file.txt'; // \SplFileObject | file to upload +$multiple_files = array('/path/to/file.txt'); // \SplFileObject[] + +try { + $result = $apiInstance->uploadImageFullFormData($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files); + print_r($result); +} catch (Exception $e) { + echo 'Exception when calling PetApi->uploadImageFullFormData: ', $e->getMessage(), PHP_EOL; +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **pet_id** | **int**| ID of pet to update | + **name** | **string**| | + **photo_urls** | [**string[]**](../Model/string.md)| | + **id** | **int**| | [optional] + **category** | [**\OpenAPI\Client\Model\Category**](../Model/Category.md)| | [optional] + **tags** | [**\OpenAPI\Client\Model\Tag[]**](../Model/\OpenAPI\Client\Model\Tag.md)| | [optional] + **status** | **string**| pet status in the store | [optional] + **file** | **\SplFileObject****\SplFileObject**| file to upload | [optional] + **multiple_files** | **\SplFileObject[]**| | [optional] + +### Return type + +[**\OpenAPI\Client\Model\ApiResponse**](../Model/ApiResponse.md) + +### Authorization + +[petstore_auth](../../README.md#petstore_auth) + +### HTTP request headers + +- **Content-Type**: `multipart/form-data` +- **Accept**: `application/json` + +[[Back to top]](#) [[Back to API list]](../../README.md#endpoints) +[[Back to Model list]](../../README.md#models) +[[Back to README]](../../README.md) diff --git a/samples/client/petstore/php/psr-18/lib/Api/PetApi.php b/samples/client/petstore/php/psr-18/lib/Api/PetApi.php index 93805e939af4..29b35822dba0 100644 --- a/samples/client/petstore/php/psr-18/lib/Api/PetApi.php +++ b/samples/client/petstore/php/psr-18/lib/Api/PetApi.php @@ -2453,6 +2453,365 @@ public function uploadFileWithRequiredFileRequest($pet_id, $required_file, $addi return $this->createRequest('POST', $uri, $headers, $httpBody); } + /** + * Operation uploadImageFullFormData + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name name (required) + * @param string[] $photo_urls photo_urls (required) + * @param int $id id (optional) + * @param \OpenAPI\Client\Model\Category $category category (optional) + * @param \OpenAPI\Client\Model\Tag[] $tags tags (optional) + * @param string $status pet status in the store (optional) + * @param \SplFileObject $file file to upload (optional) + * @param \SplFileObject[] $multiple_files multiple_files (optional) + * + * @throws \OpenAPI\Client\ApiException on non-2xx response + * @throws \InvalidArgumentException + * @return \OpenAPI\Client\Model\ApiResponse + */ + public function uploadImageFullFormData($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null) + { + list($response) = $this->uploadImageFullFormDataWithHttpInfo($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files); + return $response; + } + + /** + * Operation uploadImageFullFormDataWithHttpInfo + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int $id (optional) + * @param \OpenAPI\Client\Model\Category $category (optional) + * @param \OpenAPI\Client\Model\Tag[] $tags (optional) + * @param string $status pet status in the store (optional) + * @param \SplFileObject $file file to upload (optional) + * @param \SplFileObject[] $multiple_files (optional) + * + * @throws \OpenAPI\Client\ApiException on non-2xx response + * @throws \InvalidArgumentException + * @return array of \OpenAPI\Client\Model\ApiResponse, HTTP status code, HTTP response headers (array of strings) + */ + public function uploadImageFullFormDataWithHttpInfo($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null) + { + $request = $this->uploadImageFullFormDataRequest($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files); + + try { + try { + $response = $this->httpClient->sendRequest($request); + } catch (HttpException $e) { + $response = $e->getResponse(); + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $response->getStatusCode(), + (string) $request->getUri() + ), + $request, + $response, + $e + ); + } catch (ClientExceptionInterface $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + $request, + null, + $e + ); + } + + $statusCode = $response->getStatusCode(); + + switch($statusCode) { + case 200: + if ('\OpenAPI\Client\Model\ApiResponse' === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, '\OpenAPI\Client\Model\ApiResponse', []), + $response->getStatusCode(), + $response->getHeaders() + ]; + } + + $returnType = '\OpenAPI\Client\Model\ApiResponse'; + if ($returnType === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, $returnType, []), + $response->getStatusCode(), + $response->getHeaders() + ]; + + } catch (ApiException $e) { + switch ($e->getCode()) { + case 200: + $data = ObjectSerializer::deserialize( + $e->getResponseBody(), + '\OpenAPI\Client\Model\ApiResponse', + $e->getResponseHeaders() + ); + $e->setResponseObject($data); + break; + } + throw $e; + } + } + + /** + * Operation uploadImageFullFormDataAsync + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int $id (optional) + * @param \OpenAPI\Client\Model\Category $category (optional) + * @param \OpenAPI\Client\Model\Tag[] $tags (optional) + * @param string $status pet status in the store (optional) + * @param \SplFileObject $file file to upload (optional) + * @param \SplFileObject[] $multiple_files (optional) + * + * @throws \InvalidArgumentException + * @return Promise + */ + public function uploadImageFullFormDataAsync($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null) + { + return $this->uploadImageFullFormDataAsyncWithHttpInfo($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files) + ->then( + function ($response) { + return $response[0]; + } + ); + } + + /** + * Operation uploadImageFullFormDataAsyncWithHttpInfo + * + * uploads an image attached to a Pet object as formdata + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int $id (optional) + * @param \OpenAPI\Client\Model\Category $category (optional) + * @param \OpenAPI\Client\Model\Tag[] $tags (optional) + * @param string $status pet status in the store (optional) + * @param \SplFileObject $file file to upload (optional) + * @param \SplFileObject[] $multiple_files (optional) + * + * @throws \InvalidArgumentException + * @return Promise + */ + public function uploadImageFullFormDataAsyncWithHttpInfo($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null) + { + $returnType = '\OpenAPI\Client\Model\ApiResponse'; + $request = $this->uploadImageFullFormDataRequest($pet_id, $name, $photo_urls, $id, $category, $tags, $status, $file, $multiple_files); + + return $this->httpAsyncClient->sendAsyncRequest($request) + ->then( + function ($response) use ($returnType) { + if ($returnType === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, $returnType, []), + $response->getStatusCode(), + $response->getHeaders() + ]; + }, + function (HttpException $exception) { + $response = $exception->getResponse(); + $statusCode = $response->getStatusCode(); + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + $exception->getRequest()->getUri() + ), + $exception->getRequest(), + $exception->getResponse(), + $exception + ); + } + ); + } + + /** + * Create request for operation 'uploadImageFullFormData' + * + * @param int $pet_id ID of pet to update (required) + * @param string $name (required) + * @param string[] $photo_urls (required) + * @param int $id (optional) + * @param \OpenAPI\Client\Model\Category $category (optional) + * @param \OpenAPI\Client\Model\Tag[] $tags (optional) + * @param string $status pet status in the store (optional) + * @param \SplFileObject $file file to upload (optional) + * @param \SplFileObject[] $multiple_files (optional) + * + * @throws \InvalidArgumentException + * @return RequestInterface + */ + public function uploadImageFullFormDataRequest($pet_id, $name, $photo_urls, $id = null, $category = null, $tags = null, $status = null, $file = null, $multiple_files = null) + { + // verify the required parameter 'pet_id' is set + if ($pet_id === null || (is_array($pet_id) && count($pet_id) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $pet_id when calling uploadImageFullFormData' + ); + } + // verify the required parameter 'name' is set + if ($name === null || (is_array($name) && count($name) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $name when calling uploadImageFullFormData' + ); + } + // verify the required parameter 'photo_urls' is set + if ($photo_urls === null || (is_array($photo_urls) && count($photo_urls) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $photo_urls when calling uploadImageFullFormData' + ); + } + + + $resourcePath = '/pet/{petId}/uploadImageFullFormData'; + $formParams = []; + $queryParams = []; + $headerParams = []; + $httpBody = null; + $multipart = false; + + + + // path params + if ($pet_id !== null) { + $resourcePath = str_replace( + '{' . 'petId' . '}', + ObjectSerializer::toPathValue($pet_id), + $resourcePath + ); + } + + // form params + if ($id !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('id', $id)); + } + // form params + if ($category !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('category', $category)); + } + // form params + if ($name !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); + } + // form params + if ($photo_urls !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('photoUrls', $photo_urls)); + } + // form params + if ($tags !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('tags', $tags)); + } + // form params + if ($status !== null) { + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('status', $status)); + } + // form params + if ($file !== null) { + $multipart = true; + $formParams['file'] = []; + $paramFiles = is_array($file) ? $file : [$file]; + foreach ($paramFiles as $paramFile) { + $formParams['file'][] = \GuzzleHttp\Psr7\try_fopen( + ObjectSerializer::toFormValue('file', $paramFile)['file'], + 'rb' + ); + } + } + // form params + if ($multiple_files !== null) { + $multipart = true; + $formParams['multiple_files'] = []; + $paramFiles = is_array($multiple_files) ? $multiple_files : [$multiple_files]; + foreach ($paramFiles as $paramFile) { + $formParams['multiple_files'][] = \GuzzleHttp\Psr7\try_fopen( + ObjectSerializer::toFormValue('multiple_files', $paramFile)['multiple_files'], + 'rb' + ); + } + } + + $headers = $this->headerSelector->selectHeaders( + ['application/json'], + 'multipart/form-data', + $multipart + ); + + // for model (json/xml) + if (count($formParams) > 0) { + if ($multipart) { + $multipartContents = []; + foreach ($formParams as $formParamName => $formParamValue) { + $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue]; + foreach ($formParamValueItems as $formParamValueItem) { + $multipartContents[] = [ + 'name' => $formParamName, + 'contents' => $formParamValueItem + ]; + } + } + // for HTTP post (form) + $httpBody = new MultipartStream($multipartContents); + + } elseif ($this->headerSelector->isJsonMime($headers['Content-Type'])) { + $httpBody = json_encode($formParams); + + } else { + // for HTTP post (form) + $httpBody = ObjectSerializer::buildQuery($formParams); + } + } + + // this endpoint requires OAuth (access token) + if ($this->config->getAccessToken() !== null) { + $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken(); + } + + $defaultHeaders = []; + if ($this->config->getUserAgent()) { + $defaultHeaders['User-Agent'] = $this->config->getUserAgent(); + } + + $headers = array_merge( + $defaultHeaders, + $headerParams, + $headers + ); + + $operationHost = $this->config->getHost(); + + $uri = $this->createUri($operationHost, $resourcePath, $queryParams); + + return $this->createRequest('POST', $uri, $headers, $httpBody); + } + /** * @param string $method From ff99320202456f254bc99982a5d74f10c83632d1 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Sat, 15 Mar 2025 15:58:27 -0500 Subject: [PATCH 08/12] Revert "Output of CLI commands per PR comments" This reverts commit 2eaa93731c354c9cb64a41187ba25a1b271cfdea. --- .../enum-single-value/.openapi-generator/FILES | 4 ++-- .../enum-single-value/models/ObjectSerializer.ts | 14 ++++++++------ .../builds/enum-single-value/models/all.ts | 4 ++-- .../enum-single-value/types/ObjectParamAPI.ts | 4 ++-- .../enum-single-value/types/ObservableAPI.ts | 4 ++-- .../builds/enum-single-value/types/PromiseAPI.ts | 4 ++-- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES b/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES index f586694f5f67..832d1d1b6d4d 100644 --- a/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES +++ b/samples/client/others/typescript/builds/enum-single-value/.openapi-generator/FILES @@ -11,8 +11,8 @@ http/isomorphic-fetch.ts index.ts middleware.ts models/ObjectSerializer.ts -models/SomeObject.ts -models/WithNullableType.ts +models/SingleValueEnum30.ts +models/SingleValueEnum31.ts models/all.ts package.json rxjsStub.ts diff --git a/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts b/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts index d44f397943e3..15b6c13639d3 100644 --- a/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts +++ b/samples/client/others/typescript/builds/enum-single-value/models/ObjectSerializer.ts @@ -1,8 +1,8 @@ -export * from '../models/SomeObject'; -export * from '../models/WithNullableType'; +export * from '../models/SingleValueEnum30'; +export * from '../models/SingleValueEnum31'; -import { SomeObject } from '../models/SomeObject'; -import { WithNullableType } from '../models/WithNullableType'; +import { SingleValueEnum30, SingleValueEnum30TypeEnum } from '../models/SingleValueEnum30'; +import { SingleValueEnum31, SingleValueEnum31TypeEnum } from '../models/SingleValueEnum31'; /* tslint:disable:no-unused-variable */ let primitives = [ @@ -17,11 +17,13 @@ let primitives = [ ]; let enumsMap: Set = new Set([ + "SingleValueEnum30TypeEnum", + "SingleValueEnum31TypeEnum", ]); let typeMap: {[index: string]: any} = { - "SomeObject": SomeObject, - "WithNullableType": WithNullableType, + "SingleValueEnum30": SingleValueEnum30, + "SingleValueEnum31": SingleValueEnum31, } type MimeTypeDescriptor = { diff --git a/samples/client/others/typescript/builds/enum-single-value/models/all.ts b/samples/client/others/typescript/builds/enum-single-value/models/all.ts index ed435990d1a4..dc9e55201d87 100644 --- a/samples/client/others/typescript/builds/enum-single-value/models/all.ts +++ b/samples/client/others/typescript/builds/enum-single-value/models/all.ts @@ -1,2 +1,2 @@ -export * from '../models/SomeObject' -export * from '../models/WithNullableType' +export * from '../models/SingleValueEnum30' +export * from '../models/SingleValueEnum31' diff --git a/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts b/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts index 5daa1b27ef4d..766e01f37104 100644 --- a/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts +++ b/samples/client/others/typescript/builds/enum-single-value/types/ObjectParamAPI.ts @@ -2,5 +2,5 @@ import { ResponseContext, RequestContext, HttpFile, HttpInfo } from '../http/htt import { Configuration, ConfigurationOptions } from '../configuration' import type { Middleware } from '../middleware'; -import { SomeObject } from '../models/SomeObject'; -import { WithNullableType } from '../models/WithNullableType'; +import { SingleValueEnum30 } from '../models/SingleValueEnum30'; +import { SingleValueEnum31 } from '../models/SingleValueEnum31'; diff --git a/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts b/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts index ddca5054778e..37167e1b30fa 100644 --- a/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts +++ b/samples/client/others/typescript/builds/enum-single-value/types/ObservableAPI.ts @@ -3,5 +3,5 @@ import { Configuration, ConfigurationOptions } from '../configuration' import type { Middleware } from '../middleware'; import { Observable, of, from } from '../rxjsStub'; import {mergeMap, map} from '../rxjsStub'; -import { SomeObject } from '../models/SomeObject'; -import { WithNullableType } from '../models/WithNullableType'; +import { SingleValueEnum30 } from '../models/SingleValueEnum30'; +import { SingleValueEnum31 } from '../models/SingleValueEnum31'; diff --git a/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts b/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts index d536e2b2790d..55b1d0e53e26 100644 --- a/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts +++ b/samples/client/others/typescript/builds/enum-single-value/types/PromiseAPI.ts @@ -2,5 +2,5 @@ import { ResponseContext, RequestContext, HttpFile, HttpInfo } from '../http/htt import { Configuration, ConfigurationOptions, PromiseConfigurationOptions } from '../configuration' import { PromiseMiddleware, Middleware, PromiseMiddlewareWrapper } from '../middleware'; -import { SomeObject } from '../models/SomeObject'; -import { WithNullableType } from '../models/WithNullableType'; +import { SingleValueEnum30 } from '../models/SingleValueEnum30'; +import { SingleValueEnum31 } from '../models/SingleValueEnum31'; From b3d9b3ffd5f86acca93f64257b940191338ff117 Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Mon, 17 Mar 2025 15:17:46 -0500 Subject: [PATCH 09/12] Includes php-nextgen; tightens up ::toFormValue() --- .../php-nextgen/ObjectSerializer.mustache | 82 +++++++++++++++++-- .../main/resources/php-nextgen/api.mustache | 4 +- .../resources/php/ObjectSerializer.mustache | 34 ++++---- .../php-nextgen-streaming/src/Api/BodyApi.php | 4 +- .../php-nextgen-streaming/src/Api/FormApi.php | 20 ++--- .../src/ObjectSerializer.php | 82 +++++++++++++++++-- .../echo_api/php-nextgen/src/Api/BodyApi.php | 4 +- .../echo_api/php-nextgen/src/Api/FormApi.php | 20 ++--- .../php-nextgen/src/ObjectSerializer.php | 82 +++++++++++++++++-- .../OpenAPIClient-php/src/Api/FakeApi.php | 36 ++++---- .../OpenAPIClient-php/src/Api/PetApi.php | 12 +-- .../src/ObjectSerializer.php | 82 +++++++++++++++++-- .../lib/ObjectSerializer.php | 34 ++++---- .../php/psr-18/lib/ObjectSerializer.php | 34 ++++---- 14 files changed, 395 insertions(+), 135 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/php-nextgen/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php-nextgen/ObjectSerializer.mustache index 4317aaf327ad..81dd8a50387f 100644 --- a/modules/openapi-generator/src/main/resources/php-nextgen/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php-nextgen/ObjectSerializer.mustache @@ -18,6 +18,7 @@ namespace {{invokerPackage}}; +use ArrayAccess; use DateTimeInterface; use DateTime; use GuzzleHttp\Psr7\Utils; @@ -316,20 +317,33 @@ class ObjectSerializer } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array [key => value] of formdata */ - public static function toFormValue(string|\SplFileObject $value): string - { + public static function toFormValue( + string $key, + string|bool|array|DateTime|ArrayAccess|\SplFileObject $value, + ): array { if ($value instanceof \SplFileObject) { - return $value->getRealPath(); + return [$key => $value->getRealPath()]; + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; + + self::flattenArray(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } + + return $result; } else { - return self::toString($value); + return [$key => self::toString($value)]; } } @@ -598,4 +612,58 @@ class ObjectSerializer return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flattenArray( + ArrayAccess|array $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flattenArray($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } diff --git a/modules/openapi-generator/src/main/resources/php-nextgen/api.mustache b/modules/openapi-generator/src/main/resources/php-nextgen/api.mustache index 7d679de68df8..96c394a31bb0 100644 --- a/modules/openapi-generator/src/main/resources/php-nextgen/api.mustache +++ b/modules/openapi-generator/src/main/resources/php-nextgen/api.mustache @@ -759,13 +759,13 @@ use {{invokerPackage}}\ObjectSerializer; $formParams['{{baseName}}'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('{{baseName}}', $paramFile)['{{baseName}}'], 'rb' ); } {{/isFile}} {{^isFile}} - $formParams['{{baseName}}'] = ObjectSerializer::toFormValue(${{paramName}}); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('{{baseName}}', ${{paramName}})); {{/isFile}} } {{/formParams}} diff --git a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache index d6010f005db3..f6350a157391 100644 --- a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache @@ -315,34 +315,32 @@ class ObjectSerializer } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return array + * @return array [key => value] of formdata */ public static function toFormValue(string $key, mixed $value) { - $stringable = self::toString($value); - - if ($stringable !== null) { - return [$key => $stringable]; - } elseif ($value instanceof \SplFileObject) { + if ($value instanceof \SplFileObject) { return [$key => $value->getRealPath()]; - } + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; - $flattened = []; - $result = []; + self::flattenArray(json_decode(json_encode($value), true), $flattened); - self::flattenArray(json_decode(json_encode($value), true), $flattened); + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } - foreach ($flattened as $k => $v) { - $result["{$key}{$k}"] = self::toString($v); + return $result; + } else { + return [$key => self::toString($value)]; } - - return $result; } /** @@ -353,14 +351,12 @@ class ObjectSerializer * * @param float|int|bool|\DateTime $value the value of the parameter * - * @return string|null the header string + * @return string the header string */ public static function toString($value) { if ($value instanceof \DateTime) { // datetime in ISO8601 format return $value->format(self::$dateTimeFormat); - } elseif (!is_scalar($value) && $value !== null) { - return null; } elseif (is_bool($value)) { return $value ? 'true' : 'false'; } else { diff --git a/samples/client/echo_api/php-nextgen-streaming/src/Api/BodyApi.php b/samples/client/echo_api/php-nextgen-streaming/src/Api/BodyApi.php index 38d54217fc14..78c0645f1ad0 100644 --- a/samples/client/echo_api/php-nextgen-streaming/src/Api/BodyApi.php +++ b/samples/client/echo_api/php-nextgen-streaming/src/Api/BodyApi.php @@ -1034,7 +1034,7 @@ public function testBodyMultipartFormdataArrayOfBinaryRequest( $formParams['files'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('files', $paramFile)['files'], 'rb' ); } @@ -1357,7 +1357,7 @@ public function testBodyMultipartFormdataSingleBinaryRequest( $formParams['my-file'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('my-file', $paramFile)['my-file'], 'rb' ); } diff --git a/samples/client/echo_api/php-nextgen-streaming/src/Api/FormApi.php b/samples/client/echo_api/php-nextgen-streaming/src/Api/FormApi.php index 2408c27bba4b..193033455ace 100644 --- a/samples/client/echo_api/php-nextgen-streaming/src/Api/FormApi.php +++ b/samples/client/echo_api/php-nextgen-streaming/src/Api/FormApi.php @@ -408,15 +408,15 @@ public function testFormIntegerBooleanStringRequest( // form params if ($integer_form !== null) { - $formParams['integer_form'] = ObjectSerializer::toFormValue($integer_form); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('integer_form', $integer_form)); } // form params if ($boolean_form !== null) { - $formParams['boolean_form'] = ObjectSerializer::toFormValue($boolean_form); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('boolean_form', $boolean_form)); } // form params if ($string_form !== null) { - $formParams['string_form'] = ObjectSerializer::toFormValue($string_form); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('string_form', $string_form)); } $headers = $this->headerSelector->selectHeaders( @@ -735,7 +735,7 @@ public function testFormObjectMultipartRequest( // form params if ($marker !== null) { - $formParams['marker'] = ObjectSerializer::toFormValue($marker); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('marker', $marker)); } $headers = $this->headerSelector->selectHeaders( @@ -1103,27 +1103,27 @@ public function testFormOneofRequest( // form params if ($form1 !== null) { - $formParams['form1'] = ObjectSerializer::toFormValue($form1); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form1', $form1)); } // form params if ($form2 !== null) { - $formParams['form2'] = ObjectSerializer::toFormValue($form2); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form2', $form2)); } // form params if ($form3 !== null) { - $formParams['form3'] = ObjectSerializer::toFormValue($form3); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form3', $form3)); } // form params if ($form4 !== null) { - $formParams['form4'] = ObjectSerializer::toFormValue($form4); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form4', $form4)); } // form params if ($id !== null) { - $formParams['id'] = ObjectSerializer::toFormValue($id); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('id', $id)); } // form params if ($name !== null) { - $formParams['name'] = ObjectSerializer::toFormValue($name); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); } $headers = $this->headerSelector->selectHeaders( diff --git a/samples/client/echo_api/php-nextgen-streaming/src/ObjectSerializer.php b/samples/client/echo_api/php-nextgen-streaming/src/ObjectSerializer.php index b4a6f39fa1a9..ac7cf8884fd6 100644 --- a/samples/client/echo_api/php-nextgen-streaming/src/ObjectSerializer.php +++ b/samples/client/echo_api/php-nextgen-streaming/src/ObjectSerializer.php @@ -28,6 +28,7 @@ namespace OpenAPI\Client; +use ArrayAccess; use DateTimeInterface; use DateTime; use GuzzleHttp\Psr7\Utils; @@ -326,20 +327,33 @@ public static function toHeaderValue(string $value): string } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array [key => value] of formdata */ - public static function toFormValue(string|\SplFileObject $value): string - { + public static function toFormValue( + string $key, + string|bool|array|DateTime|ArrayAccess|\SplFileObject $value, + ): array { if ($value instanceof \SplFileObject) { - return $value->getRealPath(); + return [$key => $value->getRealPath()]; + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; + + self::flattenArray(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } + + return $result; } else { - return self::toString($value); + return [$key => self::toString($value)]; } } @@ -608,4 +622,58 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flattenArray( + ArrayAccess|array $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flattenArray($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } diff --git a/samples/client/echo_api/php-nextgen/src/Api/BodyApi.php b/samples/client/echo_api/php-nextgen/src/Api/BodyApi.php index 2232ec257daf..c2459f1777eb 100644 --- a/samples/client/echo_api/php-nextgen/src/Api/BodyApi.php +++ b/samples/client/echo_api/php-nextgen/src/Api/BodyApi.php @@ -1034,7 +1034,7 @@ public function testBodyMultipartFormdataArrayOfBinaryRequest( $formParams['files'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('files', $paramFile)['files'], 'rb' ); } @@ -1357,7 +1357,7 @@ public function testBodyMultipartFormdataSingleBinaryRequest( $formParams['my-file'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('my-file', $paramFile)['my-file'], 'rb' ); } diff --git a/samples/client/echo_api/php-nextgen/src/Api/FormApi.php b/samples/client/echo_api/php-nextgen/src/Api/FormApi.php index 2408c27bba4b..193033455ace 100644 --- a/samples/client/echo_api/php-nextgen/src/Api/FormApi.php +++ b/samples/client/echo_api/php-nextgen/src/Api/FormApi.php @@ -408,15 +408,15 @@ public function testFormIntegerBooleanStringRequest( // form params if ($integer_form !== null) { - $formParams['integer_form'] = ObjectSerializer::toFormValue($integer_form); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('integer_form', $integer_form)); } // form params if ($boolean_form !== null) { - $formParams['boolean_form'] = ObjectSerializer::toFormValue($boolean_form); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('boolean_form', $boolean_form)); } // form params if ($string_form !== null) { - $formParams['string_form'] = ObjectSerializer::toFormValue($string_form); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('string_form', $string_form)); } $headers = $this->headerSelector->selectHeaders( @@ -735,7 +735,7 @@ public function testFormObjectMultipartRequest( // form params if ($marker !== null) { - $formParams['marker'] = ObjectSerializer::toFormValue($marker); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('marker', $marker)); } $headers = $this->headerSelector->selectHeaders( @@ -1103,27 +1103,27 @@ public function testFormOneofRequest( // form params if ($form1 !== null) { - $formParams['form1'] = ObjectSerializer::toFormValue($form1); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form1', $form1)); } // form params if ($form2 !== null) { - $formParams['form2'] = ObjectSerializer::toFormValue($form2); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form2', $form2)); } // form params if ($form3 !== null) { - $formParams['form3'] = ObjectSerializer::toFormValue($form3); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form3', $form3)); } // form params if ($form4 !== null) { - $formParams['form4'] = ObjectSerializer::toFormValue($form4); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('form4', $form4)); } // form params if ($id !== null) { - $formParams['id'] = ObjectSerializer::toFormValue($id); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('id', $id)); } // form params if ($name !== null) { - $formParams['name'] = ObjectSerializer::toFormValue($name); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); } $headers = $this->headerSelector->selectHeaders( diff --git a/samples/client/echo_api/php-nextgen/src/ObjectSerializer.php b/samples/client/echo_api/php-nextgen/src/ObjectSerializer.php index b4a6f39fa1a9..ac7cf8884fd6 100644 --- a/samples/client/echo_api/php-nextgen/src/ObjectSerializer.php +++ b/samples/client/echo_api/php-nextgen/src/ObjectSerializer.php @@ -28,6 +28,7 @@ namespace OpenAPI\Client; +use ArrayAccess; use DateTimeInterface; use DateTime; use GuzzleHttp\Psr7\Utils; @@ -326,20 +327,33 @@ public static function toHeaderValue(string $value): string } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array [key => value] of formdata */ - public static function toFormValue(string|\SplFileObject $value): string - { + public static function toFormValue( + string $key, + string|bool|array|DateTime|ArrayAccess|\SplFileObject $value, + ): array { if ($value instanceof \SplFileObject) { - return $value->getRealPath(); + return [$key => $value->getRealPath()]; + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; + + self::flattenArray(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } + + return $result; } else { - return self::toString($value); + return [$key => self::toString($value)]; } } @@ -608,4 +622,58 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flattenArray( + ArrayAccess|array $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flattenArray($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/FakeApi.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/FakeApi.php index 31defa1d7894..07ed43c9eaaf 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/FakeApi.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/FakeApi.php @@ -4585,39 +4585,39 @@ public function testEndpointParametersRequest( // form params if ($integer !== null) { - $formParams['integer'] = ObjectSerializer::toFormValue($integer); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('integer', $integer)); } // form params if ($int32 !== null) { - $formParams['int32'] = ObjectSerializer::toFormValue($int32); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('int32', $int32)); } // form params if ($int64 !== null) { - $formParams['int64'] = ObjectSerializer::toFormValue($int64); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('int64', $int64)); } // form params if ($number !== null) { - $formParams['number'] = ObjectSerializer::toFormValue($number); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('number', $number)); } // form params if ($float !== null) { - $formParams['float'] = ObjectSerializer::toFormValue($float); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('float', $float)); } // form params if ($double !== null) { - $formParams['double'] = ObjectSerializer::toFormValue($double); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('double', $double)); } // form params if ($string !== null) { - $formParams['string'] = ObjectSerializer::toFormValue($string); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('string', $string)); } // form params if ($pattern_without_delimiter !== null) { - $formParams['pattern_without_delimiter'] = ObjectSerializer::toFormValue($pattern_without_delimiter); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('pattern_without_delimiter', $pattern_without_delimiter)); } // form params if ($byte !== null) { - $formParams['byte'] = ObjectSerializer::toFormValue($byte); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('byte', $byte)); } // form params if ($binary !== null) { @@ -4628,26 +4628,26 @@ public function testEndpointParametersRequest( $formParams['binary'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('binary', $paramFile)['binary'], 'rb' ); } } // form params if ($date !== null) { - $formParams['date'] = ObjectSerializer::toFormValue($date); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('date', $date)); } // form params if ($date_time !== null) { - $formParams['dateTime'] = ObjectSerializer::toFormValue($date_time); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('dateTime', $date_time)); } // form params if ($password !== null) { - $formParams['password'] = ObjectSerializer::toFormValue($password); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('password', $password)); } // form params if ($callback !== null) { - $formParams['callback'] = ObjectSerializer::toFormValue($callback); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('callback', $callback)); } $headers = $this->headerSelector->selectHeaders( @@ -5017,11 +5017,11 @@ public function testEnumParametersRequest( // form params if ($enum_form_string_array !== null) { - $formParams['enum_form_string_array'] = ObjectSerializer::toFormValue($enum_form_string_array); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('enum_form_string_array', $enum_form_string_array)); } // form params if ($enum_form_string !== null) { - $formParams['enum_form_string'] = ObjectSerializer::toFormValue($enum_form_string); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('enum_form_string', $enum_form_string)); } $headers = $this->headerSelector->selectHeaders( @@ -6055,11 +6055,11 @@ public function testJsonFormDataRequest( // form params if ($param !== null) { - $formParams['param'] = ObjectSerializer::toFormValue($param); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('param', $param)); } // form params if ($param2 !== null) { - $formParams['param2'] = ObjectSerializer::toFormValue($param2); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('param2', $param2)); } $headers = $this->headerSelector->selectHeaders( diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/PetApi.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/PetApi.php index 2ad06b017ec5..564d43a7150e 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/PetApi.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/PetApi.php @@ -2364,11 +2364,11 @@ public function updatePetWithFormRequest( // form params if ($name !== null) { - $formParams['name'] = ObjectSerializer::toFormValue($name); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('name', $name)); } // form params if ($status !== null) { - $formParams['status'] = ObjectSerializer::toFormValue($status); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('status', $status)); } $headers = $this->headerSelector->selectHeaders( @@ -2721,7 +2721,7 @@ public function uploadFileRequest( // form params if ($additional_metadata !== null) { - $formParams['additionalMetadata'] = ObjectSerializer::toFormValue($additional_metadata); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('additionalMetadata', $additional_metadata)); } // form params if ($file !== null) { @@ -2732,7 +2732,7 @@ public function uploadFileRequest( $formParams['file'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('file', $paramFile)['file'], 'rb' ); } @@ -3094,7 +3094,7 @@ public function uploadFileWithRequiredFileRequest( // form params if ($additional_metadata !== null) { - $formParams['additionalMetadata'] = ObjectSerializer::toFormValue($additional_metadata); + $formParams = array_merge($formParams, ObjectSerializer::toFormValue('additionalMetadata', $additional_metadata)); } // form params if ($required_file !== null) { @@ -3105,7 +3105,7 @@ public function uploadFileWithRequiredFileRequest( $formParams['requiredFile'][] = $paramFile instanceof \Psr\Http\Message\StreamInterface ? $paramFile : \GuzzleHttp\Psr7\Utils::tryFopen( - ObjectSerializer::toFormValue($paramFile), + ObjectSerializer::toFormValue('requiredFile', $paramFile)['requiredFile'], 'rb' ); } diff --git a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/ObjectSerializer.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/ObjectSerializer.php index 6ebd32a22e86..a3f70ac9a987 100644 --- a/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/ObjectSerializer.php +++ b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/ObjectSerializer.php @@ -27,6 +27,7 @@ namespace OpenAPI\Client; +use ArrayAccess; use DateTimeInterface; use DateTime; use GuzzleHttp\Psr7\Utils; @@ -325,20 +326,33 @@ public static function toHeaderValue(string $value): string } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return string the form string + * @return array [key => value] of formdata */ - public static function toFormValue(string|\SplFileObject $value): string - { + public static function toFormValue( + string $key, + string|bool|array|DateTime|ArrayAccess|\SplFileObject $value, + ): array { if ($value instanceof \SplFileObject) { - return $value->getRealPath(); + return [$key => $value->getRealPath()]; + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; + + self::flattenArray(json_decode(json_encode($value), true), $flattened); + + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } + + return $result; } else { - return self::toString($value); + return [$key => self::toString($value)]; } } @@ -607,4 +621,58 @@ public static function buildQuery(array $params, $encoding = PHP_QUERY_RFC3986): return $qs ? (string) substr($qs, 0, -1) : ''; } + + /** + * Flattens an array of Model object and generates an array compatible + * with formdata - a single-level array where the keys use bracket + * notation to signify nested data. + * + * credit: https://github.com/FranBar1966/FlatPHP + */ + private static function flattenArray( + ArrayAccess|array $source, + array &$destination, + string $start = '', + ) { + $opt = [ + 'prefix' => '[', + 'suffix' => ']', + 'suffix-end' => true, + 'prefix-list' => '[', + 'suffix-list' => ']', + 'suffix-list-end' => true, + ]; + + if (!is_array($source)) { + $source = (array) $source; + } + + if (array_is_list($source)) { + $currentPrefix = $opt['prefix-list']; + $currentSuffix = $opt['suffix-list']; + $currentSuffixEnd = $opt['suffix-list-end']; + } else { + $currentPrefix = $opt['prefix']; + $currentSuffix = $opt['suffix']; + $currentSuffixEnd = $opt['suffix-end']; + } + + $currentName = $start; + + foreach ($source as $key => $val) { + $currentName .= $currentPrefix.$key; + + if (is_array($val) && !empty($val)) { + $currentName .= "{$currentSuffix}"; + self::flattenArray($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } } diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php index b5c79e57c125..b4606dec52b2 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php @@ -324,34 +324,32 @@ public static function toHeaderValue($value) } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return array + * @return array [key => value] of formdata */ public static function toFormValue(string $key, mixed $value) { - $stringable = self::toString($value); - - if ($stringable !== null) { - return [$key => $stringable]; - } elseif ($value instanceof \SplFileObject) { + if ($value instanceof \SplFileObject) { return [$key => $value->getRealPath()]; - } + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; - $flattened = []; - $result = []; + self::flattenArray(json_decode(json_encode($value), true), $flattened); - self::flattenArray(json_decode(json_encode($value), true), $flattened); + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } - foreach ($flattened as $k => $v) { - $result["{$key}{$k}"] = self::toString($v); + return $result; + } else { + return [$key => self::toString($value)]; } - - return $result; } /** @@ -362,14 +360,12 @@ public static function toFormValue(string $key, mixed $value) * * @param float|int|bool|\DateTime $value the value of the parameter * - * @return string|null the header string + * @return string the header string */ public static function toString($value) { if ($value instanceof \DateTime) { // datetime in ISO8601 format return $value->format(self::$dateTimeFormat); - } elseif (!is_scalar($value) && $value !== null) { - return null; } elseif (is_bool($value)) { return $value ? 'true' : 'false'; } else { diff --git a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php index b5c79e57c125..b4606dec52b2 100644 --- a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php @@ -324,34 +324,32 @@ public static function toHeaderValue($value) } /** - * Take value and turn it into a string suitable for inclusion in + * Take value and turn it into an array suitable for inclusion in * the http body (form parameter). If it's a string, pass through unchanged * If it's a datetime object, format it in ISO8601 * - * @param string|\SplFileObject $value the value of the form parameter + * @param string|bool|array|DateTime|ArrayAccess|\SplFileObject $value the value of the form parameter * - * @return array + * @return array [key => value] of formdata */ public static function toFormValue(string $key, mixed $value) { - $stringable = self::toString($value); - - if ($stringable !== null) { - return [$key => $stringable]; - } elseif ($value instanceof \SplFileObject) { + if ($value instanceof \SplFileObject) { return [$key => $value->getRealPath()]; - } + } elseif (is_array($value) || $value instanceof ArrayAccess) { + $flattened = []; + $result = []; - $flattened = []; - $result = []; + self::flattenArray(json_decode(json_encode($value), true), $flattened); - self::flattenArray(json_decode(json_encode($value), true), $flattened); + foreach ($flattened as $k => $v) { + $result["{$key}{$k}"] = self::toString($v); + } - foreach ($flattened as $k => $v) { - $result["{$key}{$k}"] = self::toString($v); + return $result; + } else { + return [$key => self::toString($value)]; } - - return $result; } /** @@ -362,14 +360,12 @@ public static function toFormValue(string $key, mixed $value) * * @param float|int|bool|\DateTime $value the value of the parameter * - * @return string|null the header string + * @return string the header string */ public static function toString($value) { if ($value instanceof \DateTime) { // datetime in ISO8601 format return $value->format(self::$dateTimeFormat); - } elseif (!is_scalar($value) && $value !== null) { - return null; } elseif (is_bool($value)) { return $value ? 'true' : 'false'; } else { From fddb0f233e8e68d5f14c8b72170533e4982eb8ec Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Mon, 17 Mar 2025 15:22:26 -0500 Subject: [PATCH 10/12] Missing ArrayAccess import --- .../src/main/resources/php/ObjectSerializer.mustache | 1 + .../petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php | 1 + samples/client/petstore/php/psr-18/lib/ObjectSerializer.php | 1 + 3 files changed, 3 insertions(+) diff --git a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache index f6350a157391..e25b25ce28d7 100644 --- a/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache +++ b/modules/openapi-generator/src/main/resources/php/ObjectSerializer.mustache @@ -19,6 +19,7 @@ namespace {{invokerPackage}}; +use ArrayAccess; use GuzzleHttp\Psr7\Utils; use {{modelPackage}}\ModelInterface; diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php index b4606dec52b2..3e1cbe8778bc 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php @@ -28,6 +28,7 @@ namespace OpenAPI\Client; +use ArrayAccess; use GuzzleHttp\Psr7\Utils; use OpenAPI\Client\Model\ModelInterface; diff --git a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php index b4606dec52b2..3e1cbe8778bc 100644 --- a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php +++ b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php @@ -28,6 +28,7 @@ namespace OpenAPI\Client; +use ArrayAccess; use GuzzleHttp\Psr7\Utils; use OpenAPI\Client\Model\ModelInterface; From b55f998914aa054e9c766683ce47f37fd894023f Mon Sep 17 00:00:00 2001 From: Juan Treminio Date: Tue, 18 Mar 2025 17:40:45 -0500 Subject: [PATCH 11/12] Adds test for refactored ObjectSerializer::toFormValue() --- .../tests/ObjectSerializerTest.php | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php b/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php index dc71cd108b85..47b94f12f4fa 100644 --- a/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php +++ b/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php @@ -636,4 +636,98 @@ public function testArrayGivenAsObjectForDeserialize(): void $tag = $tags[0]; $this->assertInstanceOf(Tag::class, $tag); } + + /** + * @dataProvider providerToFormValue + */ + public function testToFormValue( + mixed $data, + mixed $expected, + ): void { + $result = ObjectSerializer::toFormValue('key', $data); + + $this->assertEquals($expected, $result); + } + + public function providerToFormValue(): iterable + { + yield [ + 'data' => new DateTime('2021-10-06T20:17:16'), + 'expected' => ['key' => '2021-10-06T20:17:16+00:00'], + ]; + + yield [ + 'data' => true, + 'expected' => ['key' => 'true'], + ]; + + yield [ + 'data' => false, + 'expected' => ['key' => 'false'], + ]; + + yield [ + 'data' => 'some value', + 'expected' => ['key' => 'some value'], + ]; + + $filepath = realpath(__DIR__ . '/../.openapi-generator/VERSION'); + $file = new \SplFileObject($filepath); + + yield [ + 'data' => $file, + 'expected' => ['key' => $filepath], + ]; + + $id = 1234; + $name = 'Spike'; + + $category = (new Model\Category()) + ->setId(12345) + ->setName("Category_Name"); + + $tags_1 = (new Model\Tag()) + ->setId(12345) + ->setName("tag_1"); + + $tags_2 = (new Model\Tag()) + ->setId(98765) + ->setName("tag_2"); + + $tags = [ + $tags_1, + $tags_2, + ]; + + $photo_urls = [ + "https://example.com/picture_1.jpg", + "https://example.com/picture_2.jpg", + ]; + $status = Model\Pet::STATUS_AVAILABLE; + + $pet = new Model\Pet([]); + $pet->setId($id) + ->setName($name) + ->setPhotoUrls($photo_urls) + ->setStatus($status) + ->setCategory($category) + ->setTags($tags); + + yield [ + 'data' => $pet, + 'expected' => [ + 'key[id]' => "{$id}", + 'key[name]' => $name, + 'key[photoUrls][0]' => $photo_urls[0], + 'key[photoUrls][1]' => $photo_urls[1], + 'key[status]' => $status, + 'key[category][id]' => "{$category->getId()}", + 'key[category][name]' => $category->getName(), + 'key[tags][0][id]' => "{$tags_1->getId()}", + 'key[tags][0][name]' => $tags_1->getName(), + 'key[tags][1][id]' => "{$tags_2->getId()}", + 'key[tags][1][name]' => $tags_2->getName(), + ], + ]; + } } From 6042eac616cfdc7dee28248eb1fd57bf88bac284 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Wed, 19 Mar 2025 14:56:12 +0800 Subject: [PATCH 12/12] udpate global setting tests --- .../codegen/config/GlobalSettingsTest.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/config/GlobalSettingsTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/config/GlobalSettingsTest.java index fadea5ff40f8..8025484df9c4 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/config/GlobalSettingsTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/config/GlobalSettingsTest.java @@ -2,35 +2,37 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; + import java.util.Properties; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; + import org.slf4j.LoggerFactory; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * Test class for {@link GlobalSettings} + * * @author Edoardo Patti */ public class GlobalSettingsTest { - private static final Object OBJECT = new Object(); - - @BeforeClass - public void setUp() { - ((Logger) LoggerFactory.getLogger(GlobalSettings.class)).setLevel(Level.DEBUG); - Properties props = new Properties(2); - props.put("test1", OBJECT); - props.put(OBJECT, "test2"); - System.getProperties().putAll(props); - } - - @Test - public void testNonStringSystemProperties() { - assertThat(GlobalSettings.getProperty(OBJECT.toString())).isNotNull(); - assertThat(GlobalSettings.getProperty("test1")).isNotNull(); - assertThatNoException().isThrownBy(GlobalSettings::log); - } + @BeforeClass + public void setUp() { + ((Logger) LoggerFactory.getLogger(GlobalSettings.class)).setLevel(Level.DEBUG); + Properties props = new Properties(2); + props.put("test1", 789); + props.put(345, "test2"); + System.getProperties().putAll(props); + } + + @Test + public void testNonStringSystemProperties() { + assertThat(GlobalSettings.getProperty("345")).isEqualTo("test2"); + assertThat(GlobalSettings.getProperty("test1")).isEqualTo("789"); + assertThatNoException().isThrownBy(GlobalSettings::log); + } } \ No newline at end of file