@@ -19,6 +19,9 @@ func (g *Generator) buildServiceBlock(tagKey string, operations []*operation) st
1919 var buf strings.Builder
2020 buf .WriteString ("namespace SumUp\\ Services;\n \n " )
2121 buf .WriteString ("use SumUp\\ HttpClient\\ HttpClientInterface;\n " )
22+ if serviceHasRequestBody (operations ) {
23+ buf .WriteString ("use SumUp\\ RequestEncoder;\n " )
24+ }
2225 buf .WriteString ("use SumUp\\ ResponseDecoder;\n " )
2326 buf .WriteString ("use SumUp\\ SdkInfo;\n \n " )
2427
@@ -35,6 +38,26 @@ func (g *Generator) buildServiceBlock(tagKey string, operations []*operation) st
3538 }
3639 }
3740
41+ seenRequestBodies := make (map [string ]struct {})
42+ for _ , op := range operations {
43+ if ! shouldGenerateRequestBodyClass (op ) {
44+ continue
45+ }
46+
47+ requestClass := requestBodyClassName (className , op )
48+ if _ , ok := seenRequestBodies [requestClass ]; ok {
49+ op .BodyType = requestClass
50+ op .BodyDocType = requestClass
51+ continue
52+ }
53+ seenRequestBodies [requestClass ] = struct {}{}
54+ op .BodyType = requestClass
55+ op .BodyDocType = requestClass
56+
57+ buf .WriteString (g .buildPHPClass (requestClass , op .BodySchema , "SumUp\\ Services" ))
58+ buf .WriteString ("\n " )
59+ }
60+
3861 seenParams := make (map [string ]struct {})
3962 for _ , op := range operations {
4063 if op == nil || ! op .HasQuery {
@@ -124,7 +147,7 @@ func (g *Generator) renderServiceMethod(serviceClass string, op *operation) stri
124147 }
125148
126149 if op .HasBody {
127- buf . WriteString ( " * @param array|null $body Optional request payload\n " )
150+ fmt . Fprintf ( & buf , " * @param %s $body %s request payload\n " , renderBodyDocType ( op ), renderBodyDocQualifier ( op ) )
128151 }
129152 buf .WriteString (" * @param array|null $requestOptions Optional request options (timeout, connect_timeout, retries, retry_backoff_ms)\n " )
130153
@@ -146,7 +169,7 @@ func (g *Generator) renderServiceMethod(serviceClass string, op *operation) stri
146169 args = append (args , fmt .Sprintf ("?%s $queryParams = null" , queryParamsClassName (serviceClass , op )))
147170 }
148171 if op .HasBody {
149- args = append (args , "?array $body = null" )
172+ args = append (args , renderBodyArgument ( op ) )
150173 }
151174 args = append (args , "?array $requestOptions = null" )
152175
@@ -186,9 +209,13 @@ func (g *Generator) renderServiceMethod(serviceClass string, op *operation) stri
186209
187210 buf .WriteString (" $payload = [];\n " )
188211 if op .HasBody {
189- buf .WriteString (" if ($body !== null) {\n " )
190- buf .WriteString (" $payload = $body;\n " )
191- buf .WriteString (" }\n " )
212+ if op .BodyRequired {
213+ buf .WriteString (" $payload = RequestEncoder::encode($body);\n " )
214+ } else {
215+ buf .WriteString (" if ($body !== null) {\n " )
216+ buf .WriteString (" $payload = RequestEncoder::encode($body);\n " )
217+ buf .WriteString (" }\n " )
218+ }
192219 }
193220
194221 buf .WriteString (" $headers = ['Content-Type' => 'application/json', 'User-Agent' => SdkInfo::getUserAgent()];\n " )
@@ -323,6 +350,45 @@ func collectInlineResponseSchemas(operations []*operation) map[string]*base.Sche
323350 return result
324351}
325352
353+ func serviceHasRequestBody (operations []* operation ) bool {
354+ for _ , op := range operations {
355+ if op != nil && op .HasBody {
356+ return true
357+ }
358+ }
359+
360+ return false
361+ }
362+
363+ func shouldGenerateRequestBodyClass (op * operation ) bool {
364+ if op == nil || ! op .HasBody || op .BodySchema == nil {
365+ return false
366+ }
367+
368+ if op .BodySchema .GetReference () != "" {
369+ return false
370+ }
371+
372+ if ! schemaIsObject (op .BodySchema ) {
373+ return false
374+ }
375+
376+ return ! schemaIsAdditionalPropertiesOnly (op .BodySchema )
377+ }
378+
379+ func requestBodyClassName (serviceClass string , op * operation ) string {
380+ methodName := op .methodName ()
381+ if methodName == "" {
382+ methodName = "Operation"
383+ }
384+
385+ if serviceClass != "" {
386+ return fmt .Sprintf ("%s%sRequest" , serviceClass , strcase .ToCamel (methodName ))
387+ }
388+
389+ return fmt .Sprintf ("%sRequest" , strcase .ToCamel (methodName ))
390+ }
391+
326392func collectInlineResponseSchema (rt * responseType , acc map [string ]* base.SchemaProxy ) {
327393 if rt == nil {
328394 return
@@ -597,3 +663,76 @@ func renderPathAssignment(op *operation) string {
597663
598664 return builder .String ()
599665}
666+
667+ func renderBodyDocQualifier (op * operation ) string {
668+ if op != nil && op .BodyRequired {
669+ return "Required"
670+ }
671+
672+ return "Optional"
673+ }
674+
675+ func renderBodyDocType (op * operation ) string {
676+ if op == nil {
677+ return "array|null"
678+ }
679+
680+ baseType := op .BodyDocType
681+ if baseType == "" {
682+ baseType = "array"
683+ }
684+
685+ if bodyTypeAllowsArray (op .BodyType ) {
686+ baseType = baseType + "|array"
687+ }
688+
689+ if ! op .BodyRequired && ! strings .Contains (baseType , "null" ) {
690+ baseType += "|null"
691+ }
692+
693+ return baseType
694+ }
695+
696+ func renderBodyArgument (op * operation ) string {
697+ if op == nil {
698+ return "?array $body = null"
699+ }
700+
701+ baseType := op .BodyType
702+ if baseType == "" || baseType == "mixed" {
703+ baseType = "array"
704+ }
705+
706+ if bodyTypeAllowsArray (baseType ) {
707+ baseType = baseType + "|array"
708+ }
709+
710+ if ! op .BodyRequired {
711+ if baseType == "array" {
712+ return "?array $body = null"
713+ }
714+ if ! strings .Contains (baseType , "null" ) {
715+ baseType += "|null"
716+ }
717+ return fmt .Sprintf ("%s $body = null" , baseType )
718+ }
719+
720+ return fmt .Sprintf ("%s $body" , baseType )
721+ }
722+
723+ func bodyTypeAllowsArray (typeName string ) bool {
724+ if typeName == "" {
725+ return false
726+ }
727+ typeName = strings .TrimPrefix (typeName , "?" )
728+ if strings .Contains (typeName , "|" ) {
729+ return false
730+ }
731+
732+ switch typeName {
733+ case "array" , "mixed" , "string" , "int" , "float" , "bool" , "null" , "void" :
734+ return false
735+ default :
736+ return true
737+ }
738+ }
0 commit comments