From ba7e0427f9d74016f26dbb2c3451a2a79362bc87 Mon Sep 17 00:00:00 2001 From: Rick Sharp Date: Mon, 7 Jun 2021 11:12:53 +0100 Subject: [PATCH 1/2] Fixed an issue processing body parameters when the request body itself is an array of objects. --- src/Extracting/Generator.php | 18 +++++++++++++--- tests/Unit/GeneratorTest.php | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/Extracting/Generator.php b/src/Extracting/Generator.php index 4d094c2c..1c57d6c3 100644 --- a/src/Extracting/Generator.php +++ b/src/Extracting/Generator.php @@ -301,7 +301,7 @@ public static function setObject(array &$results, string $path, $value, array $s { $parts = explode('.', $path); - array_pop($parts); // Get rid of the field name + $paramName = array_pop($parts); // Remove the field name $baseName = join('.', $parts); // For array fields, the type should be indicated in the source object by now; @@ -313,7 +313,14 @@ public static function setObject(array &$results, string $path, $value, array $s $baseNameInOriginalParams = substr($baseNameInOriginalParams, 0, -2); } - if (Arr::has($source, $baseNameInOriginalParams)) { + if (empty($baseNameInOriginalParams)) { + // This indicates that the body is an array of objects, so each parameter should be a key in the first object in that array + $results[0][$paramName] = $value; + } elseif (array_key_exists(0, $results)) { + // The body is an array of objects, so every parameter must be an element of the array object. + $dotPath = '0.'.substr($path, 3); + Arr::set($results, $dotPath, $value); + } elseif (Arr::has($source, $baseNameInOriginalParams)) { $parentData = Arr::get($source, $baseNameInOriginalParams); // Path we use for data_set $dotPath = str_replace('[]', '.0', $path); @@ -418,7 +425,7 @@ public static function nestArrayAndObjectFields(array $parameters) // If the user didn't add a parent field, we'll conveniently add it for them $parentName = rtrim(join('.', $parts), '[]'); - if (empty($parameters[$parentName])) { + if (!empty($parentName) && empty($parameters[$parentName])) { $normalisedParameters[$parentName] = [ "name" => $parentName, "type" => "object", @@ -427,6 +434,11 @@ public static function nestArrayAndObjectFields(array $parameters) "value" => [$fieldName => $parameter['value']], ]; } + + // If the body is an array, the parameter array must use sequential keys + if (Str::startsWith($name, '[].')) { + $name = count($normalisedParameters); + } } $normalisedParameters[$name] = $parameter; } diff --git a/tests/Unit/GeneratorTest.php b/tests/Unit/GeneratorTest.php index ad814731..10154fd1 100644 --- a/tests/Unit/GeneratorTest.php +++ b/tests/Unit/GeneratorTest.php @@ -129,6 +129,47 @@ public function clean_can_properly_parse_array_keys() ], $cleanBodyParameters); } + /** @test */ + public function clean_can_properly_parse_a_body_array() + { + $parameters = [ + '[].key1' => [ + 'type' => 'string', + 'value' => '43', + ], + '[].key2' => [ + 'type' => 'integer', + 'value' => 77, + ], + '[].key3' => [ + 'type' => 'object', + 'value'=> [], + ], + '[].key3.key1' => [ + 'type' => 'object', + 'value' => [], + ], + '[].key3.key1.objkey1' => [ + 'type' => 'string', + 'value' => 'hoho', + ], + ]; + + $cleanBodyParameters = Generator::cleanParams($parameters); + + $this->assertEquals([ + [ + 'key1' => '43', + 'key2' => 77, + 'key3' => [ + 'key1' => [ + 'objkey1' => 'hoho', + ] + ] + ], + ], $cleanBodyParameters); + } + /** @test */ public function does_not_generate_values_for_excluded_params_and_excludes_them_from_clean_params() { From 05aaba1877e9ca3dbf7a130dcbd12a2ba9438136 Mon Sep 17 00:00:00 2001 From: Rick Sharp Date: Tue, 8 Jun 2021 15:32:44 +0100 Subject: [PATCH 2/2] Properly support child array parameters in body arrays, and make the comments clearer. --- src/Extracting/Generator.php | 14 ++++++++++---- tests/Unit/GeneratorTest.php | 17 +++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Extracting/Generator.php b/src/Extracting/Generator.php index 1c57d6c3..cbafc2ff 100644 --- a/src/Extracting/Generator.php +++ b/src/Extracting/Generator.php @@ -314,11 +314,17 @@ public static function setObject(array &$results, string $path, $value, array $s } if (empty($baseNameInOriginalParams)) { - // This indicates that the body is an array of objects, so each parameter should be a key in the first object in that array + // If this is empty, it indicates that the body is an array of objects. (i.e. "[].param") + // Therefore, each parameter should be an element of the first object in that array. $results[0][$paramName] = $value; - } elseif (array_key_exists(0, $results)) { - // The body is an array of objects, so every parameter must be an element of the array object. - $dotPath = '0.'.substr($path, 3); + } elseif (Str::startsWith($path, '[]')) { + // If the body is an array, then any top level parameters (i.e. "[].param") would have been handled by the previous block + // Therefore, we assume that this is a child parameter (i.e. "[].parent.child" or "[].parent[].child" + + // Remove the top-level array brackets + $dotPath = substr($path, 3); + // Use correct dot notation for any child arrays + $dotPath = '0.' . str_replace('[]', '.0', $dotPath); Arr::set($results, $dotPath, $value); } elseif (Arr::has($source, $baseNameInOriginalParams)) { $parentData = Arr::get($source, $baseNameInOriginalParams); diff --git a/tests/Unit/GeneratorTest.php b/tests/Unit/GeneratorTest.php index 10154fd1..11541dfc 100644 --- a/tests/Unit/GeneratorTest.php +++ b/tests/Unit/GeneratorTest.php @@ -153,6 +153,14 @@ public function clean_can_properly_parse_a_body_array() 'type' => 'string', 'value' => 'hoho', ], + '[].key3.key2' => [ + 'type' => 'array', + 'value' => [], + ], + '[].key3.key2[].subkey1' => [ + 'type' => 'string', + 'value' => 'haha', + ], ]; $cleanBodyParameters = Generator::cleanParams($parameters); @@ -163,8 +171,13 @@ public function clean_can_properly_parse_a_body_array() 'key2' => 77, 'key3' => [ 'key1' => [ - 'objkey1' => 'hoho', - ] + 'objkey1' => 'hoho', + ], + 'key2' => [ + [ + 'subkey1' => 'haha', + ] + ], ] ], ], $cleanBodyParameters);