Skip to content

Commit 0b63838

Browse files
haddowgbastien-phi
authored andcommitted
fix: correctly cast valid boolean parameter values
fix: correctly validate "falsey" not null parameters values
1 parent 5625cf8 commit 0b63838

File tree

4 files changed

+182
-2
lines changed

4 files changed

+182
-2
lines changed

src/Validation/RequestValidator.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ protected function validateParameters(): void
106106
$parameterValue = $this->request->cookies->get($parameter->name);
107107
}
108108

109-
if ($parameterValue) {
109+
if ($parameterValue !== null) {
110110
$parameterValue = $this->castParameterValue($parameterValue, $expectedParameterSchema);
111111

112112
$result = $validator->validate($this->toObject($parameterValue), $expectedParameterSchema);
@@ -221,6 +221,9 @@ private function castParameterValue(mixed $parameterValue, ?stdClass $expectedSc
221221
$parameterValue,
222222
fn (mixed $value) => $this->castParameterValue($value, $expectedSchema->items)
223223
);
224+
} elseif ($expectedSchema->type === 'boolean') {
225+
$asBool = filter_var($parameterValue, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
226+
return $asBool === null ? $parameterValue : $asBool;
224227
}
225228

226229
return $parameterValue;

tests/Fixtures/Boolean.v1.json

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
{
2+
"openapi": "3.0.0",
3+
"info": {
4+
"title": "Numbers.v1",
5+
"version": "1.0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost:3000"
10+
}
11+
],
12+
"paths": {
13+
"/users": {
14+
"get": {
15+
"summary": "Get users",
16+
"tags": [],
17+
"responses": {
18+
"200": {
19+
"description": "OK",
20+
"content": {
21+
"application/json": {
22+
"schema": {
23+
"type": "array",
24+
"items": {
25+
"type": "object",
26+
"properties": {
27+
"id": {
28+
"type": "number",
29+
"description": "User ID",
30+
"example": 1
31+
},
32+
"name": {
33+
"type": "string",
34+
"description": "User name",
35+
"example": "Adam Campbell"
36+
},
37+
"email": {
38+
"type": "string",
39+
"description": "User email address",
40+
"format": "email",
41+
"example": "[email protected]"
42+
}
43+
}
44+
}
45+
},
46+
"examples": {
47+
"example-1": {
48+
"value": [
49+
{
50+
"id": 1,
51+
"name": "Adam Campbell",
52+
"email": "[email protected]"
53+
}
54+
]
55+
}
56+
}
57+
}
58+
}
59+
},
60+
"422": {
61+
"description": "Unprocessable entity",
62+
"content": {
63+
"application/problem+json": {
64+
"schema": {
65+
"type": "array",
66+
"items": {
67+
"type": "object",
68+
"properties": {
69+
"id": {
70+
"type": "number",
71+
"description": "User ID",
72+
"example": 1
73+
},
74+
"name": {
75+
"type": "string",
76+
"description": "User name",
77+
"example": "Adam Campbell"
78+
},
79+
"email": {
80+
"type": "string",
81+
"description": "User email address",
82+
"format": "email",
83+
"example": "[email protected]"
84+
}
85+
}
86+
}
87+
},
88+
"examples": {
89+
"example-1": {
90+
"value": [
91+
{
92+
"id": 1,
93+
"name": "Adam Campbell",
94+
"email": "[email protected]"
95+
}
96+
]
97+
}
98+
}
99+
}
100+
}
101+
}
102+
},
103+
"operationId": "get-users",
104+
"parameters": [
105+
{
106+
"name": "boolParam",
107+
"in": "query",
108+
"description": "",
109+
"example": "true",
110+
"schema": {
111+
"type": "boolean"
112+
}
113+
}
114+
]
115+
}
116+
}
117+
},
118+
"components": {
119+
"schemas": {}
120+
}
121+
}

tests/Fixtures/Numbers.v1.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@
108108
"description": "",
109109
"example": 1,
110110
"schema": {
111-
"type": "number"
111+
"type": "number",
112+
"minimum": 1
112113
}
113114
},
114115
{

tests/RequestValidatorTest.php

+55
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,10 @@ public function test_handles_query_parameters(): void
519519
->assertValidationMessage('The data should match one item from enum')
520520
->assertInvalidRequest();
521521

522+
$this->get('/users?order=0')
523+
->assertValidationMessage('The data should match one item from enum')
524+
->assertInvalidRequest();
525+
522526
$this->get('/users?order=')
523527
->assertValidRequest();
524528

@@ -719,6 +723,57 @@ public function test_numeric_values()
719723
->assertStatus(200)
720724
->assertValidRequest()
721725
->assertValidResponse();
726+
727+
$this->getJson('/users?page=0&per_page=10&float_param=3.14')
728+
->assertStatus(200)
729+
->assertInvalidRequest()
730+
->assertValidResponse();
731+
}
732+
733+
/**
734+
* @dataProvider booleanProvider
735+
*/
736+
public function test_boolean_values($value, $isValid)
737+
{
738+
Spectator::using('Boolean.v1.json');
739+
740+
Route::get('/users', function () {
741+
return [
742+
[
743+
'id' => 1,
744+
'name' => 'Jim',
745+
'email' => '[email protected]',
746+
],
747+
];
748+
})
749+
->middleware(Middleware::class);
750+
751+
$response = $this->getJson('/users?boolParam='.$value);
752+
if ($isValid) {
753+
$response->assertValidRequest();
754+
} else {
755+
$response->assertInvalidRequest();
756+
}
757+
$response->assertValidResponse(200);
758+
759+
}
760+
761+
public static function booleanProvider(): array
762+
{
763+
return [
764+
['true', true],
765+
['false', true],
766+
['1', true],
767+
['0', true],
768+
['yes', true],
769+
['no', true],
770+
['on', true],
771+
['off', true],
772+
['', true],
773+
['null', false],
774+
['invalid', false],
775+
776+
];
722777
}
723778

724779
public function test_comma_separated_values()

0 commit comments

Comments
 (0)