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 4317aaf327a..81dd8a50387 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 7d679de68df..96c394a31bb 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 7c2a64ee47b..e25b25ce28d 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; @@ -315,20 +316,31 @@ 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($value) + public static function toFormValue(string $key, mixed $value) { 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)]; } } @@ -605,4 +617,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 flattenArray( + 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::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/api.mustache b/modules/openapi-generator/src/main/resources/php/api.mustache index fedb7d53241..f6246863be4 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}} 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 7b286d94d03..16e76da9074 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/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 d9e47ca9ed8..e971a99dc26 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/echo_api/php-nextgen-streaming/src/Api/BodyApi.php b/samples/client/echo_api/php-nextgen-streaming/src/Api/BodyApi.php index 38d54217fc1..78c0645f1ad 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 @@ class BodyApi $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 @@ class BodyApi $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 2408c27bba4..193033455ac 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 @@ class FormApi // 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 @@ class FormApi // 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 @@ class FormApi // 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 b4a6f39fa1a..ac7cf8884fd 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 @@ 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)]; } } @@ -608,4 +622,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/samples/client/echo_api/php-nextgen/src/Api/BodyApi.php b/samples/client/echo_api/php-nextgen/src/Api/BodyApi.php index 2232ec257da..c2459f1777e 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 @@ class BodyApi $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 @@ class BodyApi $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 2408c27bba4..193033455ac 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 @@ class FormApi // 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 @@ class FormApi // 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 @@ class FormApi // 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 b4a6f39fa1a..ac7cf8884fd 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 @@ 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)]; } } @@ -608,4 +622,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/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/FakeApi.php b/samples/client/petstore/php-nextgen/OpenAPIClient-php/src/Api/FakeApi.php index 31defa1d789..07ed43c9eaa 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 @@ class FakeApi // 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 @@ class FakeApi $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 @@ class FakeApi // 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 @@ class FakeApi // 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 2ad06b017ec..564d43a7150 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 @@ class PetApi // 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 @@ class PetApi // 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 @@ class PetApi $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 @@ class PetApi // 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 @@ class PetApi $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 6ebd32a22e8..a3f70ac9a98 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 @@ 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)]; } } @@ -607,4 +621,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/samples/client/petstore/php/OpenAPIClient-php/README.md b/samples/client/petstore/php/OpenAPIClient-php/README.md index 18918e09409..d6f67751a75 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 3a832aa82a5..b81cba25df6 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/FakeApi.php b/samples/client/petstore/php/OpenAPIClient-php/lib/Api/FakeApi.php index 8c2cde794df..a89d506fec6 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 @@ class FakeApi // 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 @@ class FakeApi $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 @@ class FakeApi // 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 @@ class FakeApi // 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 9313bf4f635..afc732bd153 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', + ], ]; /** @@ -2224,11 +2227,11 @@ class PetApi // 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 +2559,7 @@ class PetApi // 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 +2568,7 @@ class PetApi $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 +2906,7 @@ class PetApi // 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 +2915,428 @@ class PetApi $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' + ); + } + } + + $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 + ); + } + + /** + * 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' ); } diff --git a/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php b/samples/client/petstore/php/OpenAPIClient-php/lib/ObjectSerializer.php index 440a243a41a..3e1cbe8778b 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; @@ -324,20 +325,31 @@ 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($value) + public static function toFormValue(string $key, mixed $value) { 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)]; } } @@ -614,4 +626,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 flattenArray( + 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::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/tests/ObjectSerializerTest.php b/samples/client/petstore/php/OpenAPIClient-php/tests/ObjectSerializerTest.php index dc71cd108b8..47b94f12f4f 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 @@ class ObjectSerializerTest extends TestCase $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(), + ], + ]; + } } diff --git a/samples/client/petstore/php/OpenAPIClient-php/tests/PetApiTest.php b/samples/client/petstore/php/OpenAPIClient-php/tests/PetApiTest.php index e7a8b97419a..463f36a78af 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 @@ class PetApiTest extends TestCase $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 @@ class PetApiTest extends TestCase $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 0dde61cbcb7..1c8d4f2541c 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 1c7add7728a..1b5a4c942fd 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/FakeApi.php b/samples/client/petstore/php/psr-18/lib/Api/FakeApi.php index bc23dc9481f..360a3b16f4c 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 @@ class FakeApi // 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 @@ class FakeApi $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 @@ class FakeApi // 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 @@ class FakeApi // 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 09faf067888..29b35822dba 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 @@ class PetApi // 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 @@ class PetApi // 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 @@ class PetApi $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 @@ class PetApi // 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,366 @@ class PetApi $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' + ); + } + } + + $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); + } + + /** + * 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' ); } diff --git a/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php b/samples/client/petstore/php/psr-18/lib/ObjectSerializer.php index 440a243a41a..3e1cbe8778b 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; @@ -324,20 +325,31 @@ 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($value) + public static function toFormValue(string $key, mixed $value) { 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)]; } } @@ -614,4 +626,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 flattenArray( + 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::flattenArray($val, $destination, $currentName); + } else { + if ($currentSuffixEnd) { + $currentName .= $currentSuffix; + } + $destination[$currentName] = self::toString($val); + } + + $currentName = $start; + } + } }