Skip to content

Commit 4d4a44e

Browse files
ArtisanXLshalvah
andauthored
added feature/nullable (#834)
Co-authored-by: Shalvah <[email protected]>
1 parent 8274a80 commit 4d4a44e

File tree

11 files changed

+136
-5
lines changed

11 files changed

+136
-5
lines changed

camel/Extraction/Parameter.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Parameter extends BaseDTO
1414
public string $type = 'string';
1515
public array $enumValues = [];
1616
public bool $exampleWasSpecified = false;
17+
public bool $nullable = false;
1718

1819
public function __construct(array $parameters = [])
1920
{

src/Attributes/GenericParam.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public function __construct(
1414
public ?bool $required = true,
1515
public mixed $example = null, /* Pass 'No-example' to omit the example */
1616
public mixed $enum = null, // Can pass a list of values, or a native PHP enum
17+
public ?bool $nullable = false,
1718
) {
1819
}
1920

@@ -26,6 +27,7 @@ public function toArray()
2627
"required" => $this->required,
2728
"example" => $this->example,
2829
"enumValues" => $this->getEnumValues(),
30+
'nullable' => $this->nullable,
2931
];
3032
}
3133

src/Attributes/ResponseField.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public function __construct(
1515
public ?string $description = '',
1616
public ?bool $required = true,
1717
public mixed $example = null, /* Pass 'No-example' to omit the example */
18-
public mixed $enum = null, // Can pass a list of values, or a native PHP enum
18+
public mixed $enum = null, // Can pass a list of values, or a native PHP enum,
19+
public ?bool $nullable = false,
1920
) {
2021
}
2122
}

src/Extracting/ParsesValidationRules.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function getParametersFromValidationRules(array $validationRules, array $
5050
'type' => null,
5151
'example' => self::$MISSING_VALUE,
5252
'description' => $description,
53+
'nullable' => false,
5354
];
5455
$dependentRules[$parameter] = [];
5556

@@ -69,6 +70,11 @@ public function getParametersFromValidationRules(array $validationRules, array $
6970
}
7071

7172
$parameterData['name'] = $parameter;
73+
74+
if ($parameterData['required'] === true){
75+
$parameterData['nullable'] = false;
76+
}
77+
7278
$parameters[$parameter] = $parameterData;
7379
} catch (Throwable $e) {
7480
if ($e instanceof ScribeException) {
@@ -531,6 +537,9 @@ protected function parseRule($rule, array &$parameterData, bool $independentOnly
531537
case 'different':
532538
$parameterData['description'] .= " The value and <code>{$arguments[0]}</code> must be different.";
533539
break;
540+
case 'nullable':
541+
$parameterData['nullable'] = true;
542+
break;
534543
case 'exists':
535544
$parameterData['description'] .= " The <code>{$arguments[1]}</code> of an existing record in the {$arguments[0]} table.";
536545
break;

src/Extracting/Strategies/GetParamsFromAttributeStrategy.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ protected function normalizeParameterData(array $data): array
3838
$data['example'] = null;
3939
}
4040

41+
if ($data['required']){
42+
$data['nullable'] = false;
43+
}
44+
4145
$data['description'] = trim($data['description'] ?? '');
4246
return $data;
4347
}

src/Writing/OpenAPISpecWriter.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ public function generateFieldData($field): array
488488
'type' => 'string',
489489
'format' => 'binary',
490490
'description' => $field->description ?: '',
491+
'nullable' => $field->nullable,
491492
];
492493
} else if (Utils::isArrayType($field->type)) {
493494
$baseType = Utils::getBaseTypeFromArrayType($field->type);
@@ -500,6 +501,10 @@ public function generateFieldData($field): array
500501
$baseItem['enum'] = $field->enumValues;
501502
}
502503

504+
if ($field->nullable) {
505+
$baseItem['nullable'] = true;
506+
}
507+
503508
$fieldData = [
504509
'type' => 'array',
505510
'description' => $field->description ?: '',
@@ -509,6 +514,7 @@ public function generateFieldData($field): array
509514
'name' => '',
510515
'type' => $baseType,
511516
'example' => ($field->example ?: [null])[0],
517+
'nullable' => $field->nullable,
512518
])
513519
: $baseItem,
514520
];
@@ -535,6 +541,7 @@ public function generateFieldData($field): array
535541
'type' => 'object',
536542
'description' => $field->description ?: '',
537543
'example' => $field->example,
544+
'nullable'=> $field->nullable,
538545
'properties' => $this->objectIfEmpty(collect($field->__fields)->mapWithKeys(function ($subfield, $subfieldName) {
539546
return [$subfieldName => $this->generateFieldData($subfield)];
540547
})->all()),
@@ -544,6 +551,7 @@ public function generateFieldData($field): array
544551
'type' => static::normalizeTypeName($field->type),
545552
'description' => $field->description ?: '',
546553
'example' => $field->example,
554+
'nullable' => $field->nullable,
547555
];
548556
if (!empty($field->enumValues)) {
549557
$schema['enum'] = $field->enumValues;

tests/Fixtures/openapi.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ paths:
3434
type: string
3535
description: 'Name of image.'
3636
example: cat.jpg
37+
nullable: false
3738
image:
3839
type: string
3940
format: binary
4041
description: 'The image.'
42+
nullable: false
4143
required:
4244
- name
4345
- image
@@ -95,6 +97,7 @@ paths:
9597
type: string
9698
description: 'The id of the location.'
9799
example: consequatur
100+
nullable: false
98101
-
99102
in: query
100103
name: user_id
@@ -105,6 +108,7 @@ paths:
105108
type: string
106109
description: 'The id of the user.'
107110
example: me
111+
nullable: false
108112
-
109113
in: query
110114
name: page
@@ -115,6 +119,7 @@ paths:
115119
type: string
116120
description: 'The page number.'
117121
example: '4'
122+
nullable: false
118123
-
119124
in: query
120125
name: filters
@@ -125,6 +130,7 @@ paths:
125130
type: string
126131
description: 'The filters.'
127132
example: consequatur
133+
nullable: false
128134
-
129135
in: query
130136
name: url_encoded
@@ -135,6 +141,7 @@ paths:
135141
type: string
136142
description: 'Used for testing that URL parameters will be URL-encoded where needed.'
137143
example: '+ []&='
144+
nullable: false
138145
-
139146
in: header
140147
name: Custom-Header
@@ -192,6 +199,7 @@ paths:
192199
type: string
193200
description: ''
194201
example: consequatur
202+
nullable: false
195203
-
196204
in: header
197205
name: Custom-Header
@@ -293,9 +301,9 @@ paths:
293301
items:
294302
type: object
295303
properties:
296-
first_name: { type: string, description: 'The first name of the user.', example: John }
297-
last_name: { type: string, description: 'The last name of the user.', example: Doe }
298-
contacts: { type: array, description: 'Contact info', example: [ [ ] ], items: { type: object, properties: { first_name: { type: string, description: 'The first name of the contact.', example: Janelle }, last_name: { type: string, description: 'The last name of the contact.', example: Monáe } }, required: [ first_name, last_name ] } }
304+
first_name: { type: string, description: 'The first name of the user.', example: John, nullable: false }
305+
last_name: { type: string, description: 'The last name of the user.', example: Doe, nullable: false}
306+
contacts: { type: array, description: 'Contact info', example: [ [ ] ], items: { type: object, properties: { first_name: { type: string, description: 'The first name of the contact.', example: Janelle, nullable: false }, last_name: { type: string, description: 'The last name of the contact.', example: Monáe, nullable: false } }, required: [ first_name, last_name ] } }
299307
roles: { type: array, description: 'The name of the role.', example: [ Admin ], items: { type: string } }
300308
required:
301309
- first_name

tests/GenerateDocumentation/OutputTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ public function will_not_overwrite_manually_modified_content_unless_force_flag_i
475475
'enumValues' => [],
476476
'custom' => [],
477477
'exampleWasSpecified' => false,
478+
'nullable' => false,
478479
];
479480
$group['endpoints'][0]['urlParameters']['a_param'] = $extraParam;
480481
file_put_contents($firstGroupFilePath, Yaml::dump(

tests/Strategies/BodyParameters/GetFromBodyParamAttributeTest.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,85 +32,115 @@ public function can_fetch_from_bodyparam_attribute()
3232
'required' => true,
3333
'description' => 'The id of the user.',
3434
'example' => 9,
35+
'nullable' => false,
3536
],
3637
'room_id' => [
3738
'type' => 'string',
3839
'required' => false,
3940
'description' => 'The id of the room.',
41+
'nullable' => false,
4042
],
4143
'forever' => [
4244
'type' => 'boolean',
4345
'required' => false,
4446
'description' => 'Whether to ban the user forever.',
4547
'example' => false,
48+
'nullable' => false,
4649
],
4750
'another_one' => [
4851
'type' => 'number',
4952
'required' => false,
5053
'description' => 'Just need something here.',
54+
'nullable' => false,
5155
],
5256
'yet_another_param' => [
5357
'type' => 'object',
5458
'required' => true,
5559
'description' => 'Some object params.',
60+
'nullable' => false,
5661
],
5762
'yet_another_param.name' => [
5863
'type' => 'string',
5964
'description' => '',
6065
'required' => true,
66+
'nullable' => false,
6167
],
6268
'even_more_param' => [
6369
'type' => 'number[]',
6470
'description' => 'A list of numbers',
6571
'required' => false,
72+
'nullable' => false,
6673
],
6774
'book' => [
6875
'type' => 'object',
6976
'description' => 'Book information',
7077
'required' => false,
78+
'nullable' => false,
7179
],
7280
'book.name' => [
7381
'type' => 'string',
7482
'description' => '',
7583
'required' => true,
84+
'nullable' => false,
7685
],
7786
'book.author_id' => [
7887
'type' => 'integer',
7988
'description' => '',
8089
'required' => true,
90+
'nullable' => false,
8191
],
8292
'book.pages_count' => [
8393
'type' => 'integer',
8494
'description' => '',
8595
'required' => true,
96+
'nullable' => false,
8697
],
8798
'ids' => [
8899
'type' => 'integer[]',
89100
'description' => '',
90101
'required' => true,
102+
'nullable' => false,
91103
],
92104
'state' => [
93105
'type' => 'string',
94106
'description' => '',
95107
'required' => true,
96-
'enumValues' => ["active", "pending"]
108+
'enumValues' => ["active", "pending"],
109+
'nullable' => false,
97110
],
98111
'users' => [
99112
'type' => 'object[]',
100113
'description' => 'Users\' details',
101114
'required' => false,
115+
'nullable' => false,
102116
],
103117
'users[].first_name' => [
104118
'type' => 'string',
105119
'description' => 'The first name of the user.',
106120
'required' => false,
107121
'example' => 'John',
122+
'nullable' => false,
108123
],
109124
'users[].last_name' => [
110125
'type' => 'string',
111126
'description' => 'The last name of the user.',
112127
'required' => false,
113128
'example' => 'Doe',
129+
'nullable' => false,
130+
],
131+
'note' => [
132+
'type' => 'string',
133+
'description' => '',
134+
'required' => false,
135+
'example' => 'This is a note.',
136+
'nullable' => true,
137+
],
138+
'required_note' => [
139+
'type' => 'string',
140+
'description' => '',
141+
'required' => true,
142+
'example' => 'This is a note.',
143+
'nullable' => false,
114144
],
115145
], $results);
116146
}
@@ -226,6 +256,8 @@ class BodyParamAttributeTestController
226256
#[BodyParam("users", "object[]", "Users' details", required: false)]
227257
#[BodyParam("users[].first_name", "string", "The first name of the user.", example: "John", required: false)]
228258
#[BodyParam("users[].last_name", "string", "The last name of the user.", example: "Doe", required: false)]
259+
#[BodyParam("note", example: "This is a note.", required: false, nullable: true)]
260+
#[BodyParam("required_note", example: "This is a note.", required: true, nullable: true)]
229261
public function methodWithAttributes()
230262
{
231263

0 commit comments

Comments
 (0)