Bladeren bron

Missing object fields: set ancestors, not just parents (Fixes #581)

shalvah 2 jaren geleden
bovenliggende
commit
056f071df9
2 gewijzigde bestanden met toevoegingen van 74 en 8 verwijderingen
  1. 25 8
      src/Extracting/Extractor.php
  2. 49 0
      tests/Unit/ExtractorTest.php

+ 25 - 8
src/Extracting/Extractor.php

@@ -434,11 +434,11 @@ class Extractor
         $normalisedParameters = [];
         foreach ($parameters as $name => $parameter) {
             if (Str::contains($name, '.')) {
-                // Get the various pieces of the name
+                // If the user didn't add a parent field, we'll helpfully add it for them
+                $ancestors = [];
+
                 $parts = explode('.', $name);
                 $fieldName = array_pop($parts);
-
-                // If the user didn't add a parent field, we'll helpfully add it for them
                 $parentName = rtrim(join('.', $parts), '[]');
 
                 // When the body is an array, param names will be "[].paramname",
@@ -447,21 +447,38 @@ class Extractor
                     $parentName = '[]';
                 }
 
-                if (empty($normalisedParameters[$parentName])) {
+                while ($parentName) {
+                    if (!empty($normalisedParameters[$parentName])) {
+                        break;
+                    }
+
                     $details = [
                         "name" => $parentName,
                         "type" => $parentName === '[]' ? "object[]" : "object",
                         "description" => "",
-                        "required" => true,
+                        "required" => false,
                     ];
 
-                    if (!$parameter instanceof ResponseField)
-                        $details["example"] = [$fieldName => $parameter->example];
+                    if ($parameter instanceof ResponseField) {
+                        $ancestors[] = [$parentName, new ResponseField($details)];
+                    } else {
+                        $lastParentExample = $details["example"] =
+                            [$fieldName => $lastParentExample ?? $parameter->example];
+                        $ancestors[] = [$parentName, new Parameter($details)];
+                    }
+
+                    $fieldName = array_pop($parts);
+                    $parentName = rtrim(join('.', $parts), '[]');
+                }
 
-                    $normalisedParameters[$parentName] = new Parameter($details);
+                // We add ancestors in reverse so we can iterate over parents first in the next section
+                foreach (array_reverse($ancestors) as [$ancestorName, $ancestor]) {
+                    $normalisedParameters[$ancestorName] = $ancestor;
                 }
             }
+
             $normalisedParameters[$name] = $parameter;
+            unset($lastParentExample);
         }
 
         $finalParameters = [];

+ 49 - 0
tests/Unit/ExtractorTest.php

@@ -320,6 +320,7 @@ class ExtractorTest extends TestCase
         $this->assertEquals(["dad"], array_keys($nested));
         $this->assertArraySubset([
             "dad" => [
+                "name" => "dad",
                 "__fields" => [
                     "age" => [
                         "name" => "dad.age",
@@ -338,7 +339,55 @@ class ExtractorTest extends TestCase
                 ],
             ],
         ], $nested);
+    }
 
+    /** @test */
+    public function sets_missing_ancestors_for_object_fields_properly()
+    {
+        $parameters = [
+            "dad.cars[]" => Parameter::create([
+                "name" => 'dad.cars[]',
+            ]),
+            "dad.cars[].model" => Parameter::create([
+                "name" => 'dad.cars[].model',
+            ]),
+            "parent.not.specified" => Parameter::create([
+                "name" => "parent.not.specified",
+            ]),
+        ];
+        $cleanParameters = [];
+
+        $nested = Extractor::nestArrayAndObjectFields($parameters, $cleanParameters);
+
+        $this->assertEquals(["dad", "parent"], array_keys($nested));
+        $this->assertArraySubset([
+            "dad" => [
+                "name" => "dad",
+                "__fields" => [
+                    "cars" => [
+                        "name" => "dad.cars",
+                        "__fields" => [
+                            "model" => [
+                                "name" => "dad.cars[].model",
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            "parent" => [
+                "name" => "parent",
+                "__fields" => [
+                    "not" => [
+                        "name" => "parent.not",
+                        "__fields" => [
+                            "specified" => [
+                                "name" => "parent.not.specified",
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ], $nested);
     }
 
     public function createRoute(string $httpMethod, string $path, string $controllerMethod, $class = TestController::class)