Skip to content

Commit 042c213

Browse files
committedJan 8, 2023
4.11.0
1 parent 709282e commit 042c213

File tree

4 files changed

+42
-37
lines changed

4 files changed

+42
-37
lines changed
 

‎.github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
strategy:
1212
matrix:
1313
php:
14-
- 8.0
14+
- 8.1
1515

1616
name: Lint code (PHP ${{ matrix.php }})
1717

‎CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1212

1313
### Removed
1414

15+
# 4.11.0 (8 December 2023)
16+
## Added
17+
- Pass `$default` parameter to URL normalizer callback ([8fe91d86](https://github.com/knuckleswtf/scribe/commit/8fe91d86e63e227873d7d37ad1677f622d9b7ef8))
18+
- OpenAPI spec: set `properties` of objects nested in arrays ([#600](https://github.com/knuckleswtf/scribe/pull/600))
19+
20+
1521
# 4.10.1 (14 December 2022)
1622
## Fixed
1723
- Set HTTP method correctly for FormRequests (fixes #532, #585). ([e8098714](https://github.com/knuckleswtf/scribe/commit/e80987145f50719156d1497a74f68139e9602593))

‎src/Scribe.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
class Scribe
1111
{
12-
public const VERSION = '4.10.1';
12+
public const VERSION = '4.11.0';
1313

1414
/**
1515
* Specify a callback that will be executed just before a response call is made

‎src/Writing/OpenAPISpecWriter.php

+34-35
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ protected function generateResponseContentSpec(?string $responseContent, OutputE
378378

379379
case 'object':
380380
$properties = collect($decoded)->mapWithKeys(function ($value, $key) use ($endpoint) {
381-
return $this->generateObjectPropertiesResponseSpec($value, $endpoint, $key);
381+
return [$key => $this->generateSchemaForValue($value, $endpoint, $key)];
382382
})->toArray();
383383

384384
if (!count($properties)) {
@@ -521,59 +521,58 @@ public function generateFieldData($field): array
521521
}
522522
}
523523

524-
function operationId(OutputEndpointData $endpoint): string
524+
protected function operationId(OutputEndpointData $endpoint): string
525525
{
526526
if ($endpoint->metadata->title) return preg_replace('/[^\w+]/', '', Str::camel($endpoint->metadata->title));
527527

528528
$parts = preg_split('/[^\w+]/', $endpoint->uri, -1, PREG_SPLIT_NO_EMPTY);
529529
return Str::lower($endpoint->httpMethods[0]) . join('', array_map(fn ($part) => ucfirst($part), $parts));
530530
}
531531

532-
533-
public function generateObjectPropertiesResponseSpec($value, OutputEndpointData $endpoint, $key): array
532+
/**
533+
* Given a value, generate the schema for it. The schema consists of: {type:, example:, properties: (if value is an object)},
534+
* and possibly a description for each property.
535+
* The $endpoint and $path are used for looking up response field descriptions.
536+
*/
537+
public function generateSchemaForValue(mixed $value, OutputEndpointData $endpoint, string $path): array
534538
{
535-
//Field is object
536539
if ($value instanceof \stdClass) {
537-
$value = (array)$value;
538-
$fieldObjectSpec = [];
539-
$fieldObjectSpec['type'] = 'object';
540-
$fieldObjectSpec['properties']= [];
541-
foreach($value as $subKey => $subValue){
542-
$newKey = sprintf('%s.%s', $key, $subKey);
543-
$generateResponseContentFieldSpec = $this->generateObjectPropertiesResponseSpec(
544-
$subValue,
545-
$endpoint,
546-
$newKey
547-
);
548-
$fieldObjectSpec['properties'][$subKey] = $generateResponseContentFieldSpec[$newKey];
549-
540+
$value = (array) $value;
541+
$schema = [
542+
'type' => 'object',
543+
'properties' => [],
544+
];
545+
// Recurse into the object
546+
foreach($value as $subField => $subValue){
547+
$subFieldPath = sprintf('%s.%s', $path, $subField);
548+
$schema['properties'][$subField] = $this->generateSchemaForValue($subValue, $endpoint, $subFieldPath);
550549
}
551-
return [$key => $fieldObjectSpec];
550+
551+
return $schema;
552552
}
553553

554-
$spec = [
554+
$schema = [
555555
'type' => $this->convertScribeOrPHPTypeToOpenAPIType(gettype($value)),
556556
'example' => $value,
557-
558557
];
559-
if (isset($endpoint->responseFields[$key]->description)) {
560-
$spec['description'] = $endpoint->responseFields[$key]->description;
558+
if (isset($endpoint->responseFields[$path]->description)) {
559+
$schema['description'] = $endpoint->responseFields[$path]->description;
561560
}
562-
if ($spec['type'] === 'array' && !empty($value)) {
563-
$handle = $value[0];
564-
$type = $this->convertScribeOrPHPTypeToOpenAPIType(gettype($handle));
565-
$spec['items']['type'] = $type;
566-
$spec['example'] = json_decode(json_encode($spec['example']), true);//Convert stdClass to array
567-
568-
if ($type === 'object') {
569-
$spec['items']['properties'] = collect($handle)->mapWithKeys(function ($v, $k) use ($endpoint) {
570-
return $this->generateObjectPropertiesResponseSpec($v, $endpoint, $k);
561+
562+
if ($schema['type'] === 'array' && !empty($value)) {
563+
$schema['example'] = json_decode(json_encode($schema['example']), true); // Convert stdClass to array
564+
565+
$sample = $value[0];
566+
$typeOfEachItem = $this->convertScribeOrPHPTypeToOpenAPIType(gettype($sample));
567+
$schema['items']['type'] = $typeOfEachItem;
568+
569+
if ($typeOfEachItem === 'object') {
570+
$schema['items']['properties'] = collect($sample)->mapWithKeys(function ($v, $k) use ($endpoint, $path) {
571+
return [$k => $this->generateSchemaForValue($v, $endpoint, "$path.$k")];
571572
})->toArray();
572573
}
573574
}
574575

575-
return [
576-
$key => $spec,
577-
];
576+
return $schema;
578577
}
579578
}

0 commit comments

Comments
 (0)
Please sign in to comment.