@@ -50,6 +50,11 @@ class RestXmlParser implements Parser
50
50
*/
51
51
private $ imports = [];
52
52
53
+ /**
54
+ * @var array<string, true>
55
+ */
56
+ private $ generatedFunctions = [];
57
+
53
58
public function __construct (NamespaceRegistry $ namespaceRegistry , RequirementsRegistry $ requirementsRegistry , TypeGenerator $ typeGenerator )
54
59
{
55
60
$ this ->namespaceRegistry = $ namespaceRegistry ;
@@ -61,6 +66,7 @@ public function generate(StructureShape $shape, bool $throwOnError = true): Pars
61
66
{
62
67
$ properties = [];
63
68
$ this ->functions = [];
69
+ $ this ->generatedFunctions = [];
64
70
$ this ->imports = [];
65
71
if (null !== $ payload = $ shape ->getPayload ()) {
66
72
$ member = $ shape ->getMember ($ payload );
@@ -80,19 +86,10 @@ public function generate(StructureShape $shape, bool $throwOnError = true): Pars
80
86
continue ;
81
87
}
82
88
83
- if (!$ member ->isNullable () && !$ member ->isRequired ()) {
84
- $ properties [] = strtr ('if (null !== $v = (PROPERTY_ACCESSOR)) {
85
- $this->PROPERTY_NAME = $v;
86
- } ' , [
87
- 'PROPERTY_NAME ' => GeneratorHelper::normalizeName ($ member ->getName ()),
88
- 'PROPERTY_ACCESSOR ' => $ this ->parseXmlElement ($ this ->getInputAccessor ('$data ' , $ member ), $ member ->getShape (), $ member ->isRequired (), false ),
89
- ]);
90
- } else {
91
- $ properties [] = strtr ('$this->PROPERTY_NAME = PROPERTY_ACCESSOR; ' , [
92
- 'PROPERTY_NAME ' => GeneratorHelper::normalizeName ($ member ->getName ()),
93
- 'PROPERTY_ACCESSOR ' => $ this ->parseXmlElement ($ this ->getInputAccessor ('$data ' , $ member ), $ member ->getShape (), $ member ->isRequired (), false ),
94
- ]);
95
- }
89
+ $ properties [] = strtr ('$this->PROPERTY_NAME = PROPERTY_ACCESSOR; ' , [
90
+ 'PROPERTY_NAME ' => GeneratorHelper::normalizeName ($ member ->getName ()),
91
+ 'PROPERTY_ACCESSOR ' => $ this ->parseXmlElement ($ this ->getInputAccessor ('$data ' , $ member ), $ member ->getShape (), $ member ->isRequired (), false ),
92
+ ]);
96
93
}
97
94
}
98
95
@@ -204,20 +201,35 @@ private function parseXmlElement(string $input, Shape $shape, bool $required, bo
204
201
205
202
private function parseXmlResponseStructure (StructureShape $ shape , string $ input , bool $ required ): string
206
203
{
207
- $ properties = [];
208
- foreach ($ shape ->getMembers () as $ member ) {
209
- $ properties [] = strtr ('PROPERTY_NAME => PROPERTY_ACCESSOR, ' , [
210
- 'PROPERTY_NAME ' => var_export ($ member ->getName (), true ),
211
- 'PROPERTY_ACCESSOR ' => $ this ->parseXmlElement ($ this ->getInputAccessor ($ input , $ member ), $ member ->getShape (), $ member ->isRequired (), true ),
212
- ]);
204
+ $ functionName = 'populateResult ' . ucfirst ($ shape ->getName ());
205
+ if (!isset ($ this ->generatedFunctions [$ functionName ])) {
206
+ // prevent recursion
207
+ $ this ->generatedFunctions [$ functionName ] = true ;
208
+
209
+ $ properties = [];
210
+ foreach ($ shape ->getMembers () as $ member ) {
211
+ $ properties [] = strtr ('PROPERTY_NAME => PROPERTY_ACCESSOR, ' , [
212
+ 'PROPERTY_NAME ' => var_export ($ member ->getName (), true ),
213
+ 'PROPERTY_ACCESSOR ' => $ this ->parseXmlElement ($ this ->getInputAccessor ('$xml ' , $ member ), $ member ->getShape (), $ member ->isRequired (), true ),
214
+ ]);
215
+ }
216
+
217
+ $ body = 'return new CLASS_NAME([
218
+ PROPERTIES
219
+ ]); ' ;
220
+
221
+ $ className = $ this ->namespaceRegistry ->getObject ($ shape );
222
+ $ this ->imports [] = $ className ;
223
+
224
+ $ this ->functions [$ functionName ] = $ this ->createPopulateMethod ($ functionName , strtr ($ body , [
225
+ 'CLASS_NAME ' => $ className ->getName (),
226
+ 'PROPERTIES ' => implode ("\n" , $ properties ),
227
+ ]), $ shape );
213
228
}
214
229
215
- return strtr ('REQUIRED new CLASS_NAME([
216
- PROPERTIES
217
- ]) ' , [
218
- 'REQUIRED ' => $ required ? '' : '! ' . $ input . ' ? null : ' ,
219
- 'CLASS_NAME ' => $ this ->namespaceRegistry ->getObject ($ shape )->getName (),
220
- 'PROPERTIES ' => implode ("\n" , $ properties ),
230
+ return strtr ($ required ? '$this->FUNCTION_NAME(INPUT) ' : '0 === INPUT->count() ? null : $this->FUNCTION_NAME(INPUT) ' , [
231
+ 'INPUT ' => $ input ,
232
+ 'FUNCTION_NAME ' => $ functionName ,
221
233
]);
222
234
}
223
235
@@ -227,7 +239,7 @@ private function parseXmlResponseString(string $input, bool $required): string
227
239
return strtr ('(string) INPUT ' , ['INPUT ' => $ input ]);
228
240
}
229
241
230
- return strtr ('($v = INPUT) ? (string) $v : null ' , ['INPUT ' => $ input ]);
242
+ return strtr ('(null !== $v = INPUT[0] ) ? (string) $v : null ' , ['INPUT ' => $ input ]);
231
243
}
232
244
233
245
private function parseXmlResponseInteger (string $ input , bool $ required ): string
@@ -236,7 +248,7 @@ private function parseXmlResponseInteger(string $input, bool $required): string
236
248
return strtr ('(int) (string) INPUT ' , ['INPUT ' => $ input ]);
237
249
}
238
250
239
- return strtr ('($v = INPUT) ? (int) (string) $v : null ' , ['INPUT ' => $ input ]);
251
+ return strtr ('(null !== $v = INPUT[0] ) ? (int) (string) $v : null ' , ['INPUT ' => $ input ]);
240
252
}
241
253
242
254
private function parseXmlResponseFloat (string $ input , bool $ required ): string
@@ -245,7 +257,7 @@ private function parseXmlResponseFloat(string $input, bool $required): string
245
257
return strtr ('(float) (string) INPUT ' , ['INPUT ' => $ input ]);
246
258
}
247
259
248
- return strtr ('($v = INPUT) ? (float) (string) $v : null ' , ['INPUT ' => $ input ]);
260
+ return strtr ('(null !== $v = INPUT[0] ) ? (float) (string) $v : null ' , ['INPUT ' => $ input ]);
249
261
}
250
262
251
263
private function parseXmlResponseBool (string $ input , bool $ required ): string
@@ -256,7 +268,7 @@ private function parseXmlResponseBool(string $input, bool $required): string
256
268
return strtr ('filter_var((string) INPUT, FILTER_VALIDATE_BOOLEAN) ' , ['INPUT ' => $ input ]);
257
269
}
258
270
259
- return strtr ('($v = INPUT) ? filter_var((string) $v, FILTER_VALIDATE_BOOLEAN) : null ' , ['INPUT ' => $ input ]);
271
+ return strtr ('(null !== $v = INPUT[0] ) ? filter_var((string) $v, FILTER_VALIDATE_BOOLEAN) : null ' , ['INPUT ' => $ input ]);
260
272
}
261
273
262
274
private function parseXmlResponseBlob (string $ input , bool $ required ): string
@@ -265,7 +277,7 @@ private function parseXmlResponseBlob(string $input, bool $required): string
265
277
return strtr ('base64_decode((string) INPUT) ' , ['INPUT ' => $ input ]);
266
278
}
267
279
268
- return strtr ('($v = INPUT) ? base64_decode((string) $v) : null ' , ['INPUT ' => $ input ]);
280
+ return strtr ('(null !== $v = INPUT[0] ) ? base64_decode((string) $v) : null ' , ['INPUT ' => $ input ]);
269
281
}
270
282
271
283
private function parseXmlResponseTimestamp (Shape $ shape , string $ input , bool $ required ): string
@@ -281,47 +293,52 @@ private function parseXmlResponseTimestamp(Shape $shape, string $input, bool $re
281
293
}
282
294
283
295
if (!$ required ) {
284
- $ body = '($v = INPUT) ? ' . strtr ($ body , ['INPUT ' => '$v ' ]) . ' : null ' ;
296
+ $ body = '(null !== $v = INPUT[0] ) ? ' . strtr ($ body , ['INPUT ' => '$v ' ]) . ' : null ' ;
285
297
}
286
298
287
299
return strtr ($ body , ['INPUT ' => $ input ]);
288
300
}
289
301
290
302
private function parseXmlResponseList (ListShape $ shape , string $ input , bool $ required , bool $ inObject ): string
291
303
{
292
- $ shapeMember = $ shape ->getMember ();
293
- if ($ shapeMember ->getShape () instanceof StructureShape) {
294
- $ listAccessorRequired = true ;
295
- $ body = '
296
- $items = [];
297
- foreach (INPUT_PROPERTY as $item) {
298
- $items[] = LIST_ACCESSOR;
299
- }
304
+ $ functionName = 'populateResult ' . ucfirst ($ shape ->getName ());
305
+ if (!isset ($ this ->generatedFunctions [$ functionName ])) {
306
+ // prevent recursion
307
+ $ this ->generatedFunctions [$ functionName ] = true ;
308
+
309
+ $ shapeMember = $ shape ->getMember ();
310
+ if ($ shapeMember ->getShape () instanceof ListShape || $ shapeMember ->getShape () instanceof MapShape) {
311
+ $ listAccessorRequired = false ;
312
+ $ body = '
313
+ $items = [];
314
+ foreach (INPUT_PROPERTY as $item) {
315
+ $a = LIST_ACCESSOR;
316
+ if (null !== $a) {
317
+ $items[] = $a;
318
+ }
319
+ }
300
320
301
- return $items;
302
- ' ;
303
- } else {
304
- $ listAccessorRequired = false ;
305
- $ body = '
306
- $items = [];
307
- foreach (INPUT_PROPERTY as $item) {
308
- $a = LIST_ACCESSOR;
309
- if (null !== $a) {
310
- $items[] = $a;
321
+ return $items;
322
+ ' ;
323
+ } else {
324
+ $ listAccessorRequired = true ;
325
+ $ body = '
326
+ $items = [];
327
+ foreach (INPUT_PROPERTY as $item) {
328
+ $items[] = LIST_ACCESSOR;
311
329
}
312
- }
313
330
314
- return $items;
315
- ' ;
316
- }
331
+ return $items;
332
+ ' ;
333
+ }
317
334
318
- $ functionName = ' populateResult ' . ucfirst ( $ shape -> getName ());
319
- $ this -> functions [ $ functionName ] = $ this ->createPopulateMethod ( $ functionName , strtr ( $ body , [
320
- ' LIST_ACCESSOR ' => $ this -> parseXmlElement ( ' $item ' , $ shapeMember ->getShape (), $ listAccessorRequired , $ inObject ),
321
- ' INPUT_PROPERTY ' => $ shape-> isFlattened () ? ' $xml ' : ( ' $xml-> ' . ( $ shapeMember -> getLocationName () ? $ shapeMember -> getLocationName () : ' member ' )),
322
- ]), $ shape );
335
+ $ this -> functions [ $ functionName] = $ this -> createPopulateMethod ( $ functionName , strtr ( $ body , [
336
+ ' LIST_ACCESSOR ' => $ this ->parseXmlElement ( ' $item ' , $ shapeMember -> getShape (), $ listAccessorRequired , $ inObject ),
337
+ ' INPUT_PROPERTY ' => $ shape -> isFlattened () ? ' $xml ' : ( ' $xml-> ' . ( $ shapeMember ->getLocationName () ? $ shapeMember -> getLocationName () : ' member ' ) ),
338
+ ]), $ shape);
339
+ }
323
340
324
- return strtr ($ required ? '$this->FUNCTION_NAME(INPUT) ' : '! INPUT ? EMPTY : $this->FUNCTION_NAME(INPUT ) ' , [
341
+ return strtr ($ required ? '$this->FUNCTION_NAME(INPUT) ' : '(0 === ($v = INPUT)->count()) ? EMPTY : $this->FUNCTION_NAME($v ) ' , [
325
342
'EMPTY ' => !$ inObject ? '[] ' : 'null ' ,
326
343
'INPUT ' => $ input ,
327
344
'FUNCTION_NAME ' => $ functionName ,
@@ -330,26 +347,31 @@ private function parseXmlResponseList(ListShape $shape, string $input, bool $req
330
347
331
348
private function parseXmlResponseMap (MapShape $ shape , string $ input , bool $ required , bool $ inObject ): string
332
349
{
333
- $ shapeValue = $ shape ->getValue ();
334
- $ body = '
335
- $items = [];
336
- foreach (INPUT as $item) {
337
- $a = $item->MAP_VALUE;
338
- $items[$item->MAP_KEY->__toString()] = MAP_ACCESSOR;
339
- }
350
+ $ functionName = 'populateResult ' . ucfirst ($ shape ->getName ());
351
+ if (!isset ($ this ->generatedFunctions [$ functionName ])) {
352
+ // prevent recursion
353
+ $ this ->generatedFunctions [$ functionName ] = true ;
340
354
341
- return $items;
342
- ' ;
355
+ $ shapeValue = $ shape ->getValue ();
356
+ $ body = '
357
+ $items = [];
358
+ foreach (INPUT as $item) {
359
+ $a = $item->MAP_VALUE;
360
+ $items[$item->MAP_KEY->__toString()] = MAP_ACCESSOR;
361
+ }
343
362
344
- $ functionName = 'populateResult ' . ucfirst ($ shape ->getName ());
345
- $ this ->functions [$ functionName ] = $ this ->createPopulateMethod ($ functionName , strtr ($ body , [
346
- 'INPUT ' => $ shape ->isFlattened () ? '$xml ' : '$xml->entry ' ,
347
- 'MAP_KEY ' => $ shape ->getKey ()->getLocationName () ?? 'key ' ,
348
- 'MAP_VALUE ' => $ shape ->getValue ()->getLocationName () ?? 'value ' ,
349
- 'MAP_ACCESSOR ' => $ this ->parseXmlElement ('$a ' , $ shapeValue ->getShape (), true , $ inObject ),
350
- ]), $ shape );
351
-
352
- return strtr ($ required ? '$this->FUNCTION_NAME(INPUT) ' : '!INPUT ? EMPTY : $this->FUNCTION_NAME(INPUT) ' , [
363
+ return $items;
364
+ ' ;
365
+
366
+ $ this ->functions [$ functionName ] = $ this ->createPopulateMethod ($ functionName , strtr ($ body , [
367
+ 'INPUT ' => $ shape ->isFlattened () ? '$xml ' : '$xml->entry ' ,
368
+ 'MAP_KEY ' => $ shape ->getKey ()->getLocationName () ?? 'key ' ,
369
+ 'MAP_VALUE ' => $ shape ->getValue ()->getLocationName () ?? 'value ' ,
370
+ 'MAP_ACCESSOR ' => $ this ->parseXmlElement ('$a ' , $ shapeValue ->getShape (), true , $ inObject ),
371
+ ]), $ shape );
372
+ }
373
+
374
+ return strtr ($ required ? '$this->FUNCTION_NAME(INPUT) ' : '(0 === ($v = INPUT)->count()) ? EMPTY : $this->FUNCTION_NAME($v) ' , [
353
375
'EMPTY ' => !$ inObject ? '[] ' : 'null ' ,
354
376
'INPUT ' => $ input ,
355
377
'FUNCTION_NAME ' => $ functionName ,
@@ -368,6 +390,7 @@ private function createPopulateMethod(string $functionName, string $body, Shape
368
390
369
391
[$ returnType , $ parameterType , $ memberClassNames ] = $ this ->typeGenerator ->getPhpType ($ shape );
370
392
$ method
393
+ ->setReturnType ($ returnType )
371
394
->setComment ('@return ' . $ parameterType );
372
395
$ this ->imports = array_merge ($ this ->imports , $ memberClassNames );
373
396
0 commit comments