shalvah 2 yıl önce
ebeveyn
işleme
042c2137e4
4 değiştirilmiş dosya ile 42 ekleme ve 37 silme
  1. 1 1
      .github/workflows/lint.yml
  2. 6 0
      CHANGELOG.md
  3. 1 1
      src/Scribe.php
  4. 34 35
      src/Writing/OpenAPISpecWriter.php

+ 1 - 1
.github/workflows/lint.yml

@@ -11,7 +11,7 @@ jobs:
     strategy:
       matrix:
         php:
-        - 8.0
+        - 8.1
 
     name: Lint code (PHP ${{ matrix.php }})
 

+ 6 - 0
CHANGELOG.md

@@ -12,6 +12,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 
 ### Removed
 
+# 4.11.0 (8 December 2023)
+## Added
+- Pass `$default` parameter to URL normalizer callback ([8fe91d86](https://github.com/knuckleswtf/scribe/commit/8fe91d86e63e227873d7d37ad1677f622d9b7ef8))
+- OpenAPI spec: set `properties` of objects nested in arrays ([#600](https://github.com/knuckleswtf/scribe/pull/600))
+
+
 # 4.10.1 (14 December 2022)
 ## Fixed
 - Set HTTP method correctly for FormRequests (fixes #532, #585). ([e8098714](https://github.com/knuckleswtf/scribe/commit/e80987145f50719156d1497a74f68139e9602593))

+ 1 - 1
src/Scribe.php

@@ -9,7 +9,7 @@ use Symfony\Component\HttpFoundation\Request;
 
 class Scribe
 {
-    public const VERSION = '4.10.1';
+    public const VERSION = '4.11.0';
 
     /**
      * Specify a callback that will be executed just before a response call is made

+ 34 - 35
src/Writing/OpenAPISpecWriter.php

@@ -378,7 +378,7 @@ class OpenAPISpecWriter
 
             case 'object':
                 $properties = collect($decoded)->mapWithKeys(function ($value, $key) use ($endpoint) {
-                    return $this->generateObjectPropertiesResponseSpec($value, $endpoint, $key);
+                    return [$key => $this->generateSchemaForValue($value, $endpoint, $key)];
                 })->toArray();
 
                 if (!count($properties)) {
@@ -521,7 +521,7 @@ class OpenAPISpecWriter
         }
     }
 
-    function operationId(OutputEndpointData $endpoint): string
+    protected function operationId(OutputEndpointData $endpoint): string
     {
         if ($endpoint->metadata->title) return preg_replace('/[^\w+]/', '', Str::camel($endpoint->metadata->title));
 
@@ -529,51 +529,50 @@ class OpenAPISpecWriter
         return Str::lower($endpoint->httpMethods[0]) . join('', array_map(fn ($part) => ucfirst($part), $parts));
     }
 
-
-    public function generateObjectPropertiesResponseSpec($value, OutputEndpointData $endpoint, $key): array
+    /**
+     * Given a value, generate the schema for it. The schema consists of: {type:, example:, properties: (if value is an object)},
+     * and possibly a description for each property.
+     * The $endpoint and $path are used for looking up response field descriptions.
+     */
+    public function generateSchemaForValue(mixed $value, OutputEndpointData $endpoint, string $path): array
     {
-        //Field is object
         if ($value instanceof \stdClass) {
-            $value = (array)$value;
-            $fieldObjectSpec = [];
-            $fieldObjectSpec['type'] = 'object';
-            $fieldObjectSpec['properties']= [];
-            foreach($value as $subKey => $subValue){
-                $newKey = sprintf('%s.%s', $key, $subKey);
-                $generateResponseContentFieldSpec = $this->generateObjectPropertiesResponseSpec(
-                    $subValue,
-                    $endpoint,
-                    $newKey
-                );
-                $fieldObjectSpec['properties'][$subKey] = $generateResponseContentFieldSpec[$newKey];
-
+            $value = (array) $value;
+            $schema = [
+                'type' => 'object',
+                'properties' => [],
+            ];
+            // Recurse into the object
+            foreach($value as $subField => $subValue){
+                $subFieldPath = sprintf('%s.%s', $path, $subField);
+                $schema['properties'][$subField] = $this->generateSchemaForValue($subValue, $endpoint, $subFieldPath);
             }
-            return  [$key => $fieldObjectSpec];
+
+            return $schema;
         }
 
-        $spec = [
+        $schema = [
             'type' => $this->convertScribeOrPHPTypeToOpenAPIType(gettype($value)),
             'example' => $value,
-
         ];
-        if (isset($endpoint->responseFields[$key]->description)) {
-            $spec['description'] = $endpoint->responseFields[$key]->description;
+        if (isset($endpoint->responseFields[$path]->description)) {
+            $schema['description'] = $endpoint->responseFields[$path]->description;
         }
-        if ($spec['type'] === 'array' && !empty($value)) {
-            $handle = $value[0];
-            $type = $this->convertScribeOrPHPTypeToOpenAPIType(gettype($handle));
-            $spec['items']['type'] = $type;
-            $spec['example'] = json_decode(json_encode($spec['example']), true);//Convert stdClass to array
-
-            if ($type === 'object') {
-                $spec['items']['properties'] = collect($handle)->mapWithKeys(function ($v, $k) use ($endpoint) {
-                    return $this->generateObjectPropertiesResponseSpec($v, $endpoint, $k);
+
+        if ($schema['type'] === 'array' && !empty($value)) {
+            $schema['example'] = json_decode(json_encode($schema['example']), true); // Convert stdClass to array
+
+            $sample = $value[0];
+            $typeOfEachItem = $this->convertScribeOrPHPTypeToOpenAPIType(gettype($sample));
+            $schema['items']['type'] = $typeOfEachItem;
+
+            if ($typeOfEachItem === 'object') {
+                $schema['items']['properties'] = collect($sample)->mapWithKeys(function ($v, $k) use ($endpoint, $path) {
+                    return [$k => $this->generateSchemaForValue($v, $endpoint, "$path.$k")];
                 })->toArray();
             }
         }
 
-        return [
-            $key => $spec,
-        ];
+        return $schema;
     }
 }