Skip to content

Commit 1bee348

Browse files
authored
Merge pull request #234 from SOHELAHMED7/155-aribros-referenced-parameters-compiling-to-object-instead-of-array
Fix: Referenced Parameters compiling to Object instead of Array
2 parents e691d93 + eeb37f0 commit 1bee348

File tree

8 files changed

+450
-2
lines changed

8 files changed

+450
-2
lines changed

bin/php-openapi

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ switch ($command) {
215215

216216
if ($outputFile === null) {
217217
if ($outputFormat === null) {
218-
error("No output fromat specified, please specify --write-json or --write-yaml.", "usage");
218+
error("No output format specified, please specify --write-json or --write-yaml.", "usage");
219219
} elseif ($outputFormat === 'json') {
220220
fwrite(STDOUT, \cebe\openapi\Writer::writeToJson($openApi));
221221
} else {

src/spec/PathItem.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public function resolveReferences(ReferenceContext $context = null)
180180
foreach ($this->$attribute as $k => $item) {
181181
if ($item instanceof Reference) {
182182
$referencedObject = $item->resolve();
183-
$this->$attribute = [$k => $referencedObject] + $this->$attribute;
183+
$this->$attribute = $this->$attribute + [$k => $referencedObject];
184184
if (!$referencedObject instanceof Reference && $referencedObject !== null) {
185185
$referencedObject->resolveReferences();
186186
}
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
openapi: 3.0.0
2+
info:
3+
title: 'Test REST API'
4+
description: 'Specifications for the Test REST API.'
5+
contact:
6+
name: bplainia
7+
8+
version: '2021-05-18'
9+
servers:
10+
-
11+
url: 'http://localhost:8000'
12+
description: Test
13+
paths:
14+
'/v1/organizations/{organizationId}/user':
15+
post:
16+
tags:
17+
- pets
18+
summary: 'Creates a user'
19+
requestBody:
20+
content:
21+
application/json:
22+
schema:
23+
type: object
24+
properties:
25+
data:
26+
type: object
27+
properties:
28+
id:
29+
type: string
30+
format: uuid
31+
name:
32+
type: string
33+
required: true
34+
responses:
35+
'201':
36+
description: Created
37+
content:
38+
application/json:
39+
schema:
40+
type: object
41+
properties:
42+
data:
43+
type: object
44+
properties:
45+
id:
46+
type: string
47+
format: uuid
48+
name:
49+
type: string
50+
'400':
51+
description: 'Bad Request'
52+
'403':
53+
description: Forbidden
54+
security:
55+
-
56+
BearerAuth: []
57+
parameters:
58+
-
59+
name: api-version
60+
in: header
61+
description: 'The API version'
62+
required: false
63+
schema:
64+
type: string
65+
format: date
66+
example: '2021-05-18'
67+
-
68+
name: organizationId
69+
in: path
70+
description: 'The Organization ID'
71+
required: true
72+
schema:
73+
type: string
74+
format: uuid
75+
'/v1/organizations/{organizationId}/user/{id}':
76+
get:
77+
summary: 'Gets a user'
78+
responses:
79+
'200':
80+
description: 'A bar'
81+
content:
82+
application/json:
83+
schema:
84+
type: object
85+
properties:
86+
data:
87+
type: object
88+
properties:
89+
id:
90+
type: string
91+
format: uuid
92+
name:
93+
type: string
94+
'400':
95+
description: 'Bad Request'
96+
'403':
97+
description: Forbidden
98+
'404':
99+
description: 'Not Found'
100+
security:
101+
-
102+
BearerAuth: []
103+
parameters:
104+
-
105+
name: api-version
106+
in: header
107+
description: 'The API version'
108+
required: false
109+
schema:
110+
type: string
111+
format: date
112+
example: '2021-05-18'
113+
-
114+
name: organizationId
115+
in: path
116+
description: 'The Organization ID'
117+
required: true
118+
schema:
119+
type: string
120+
format: uuid
121+
-
122+
name: id
123+
in: path
124+
description: 'User''s ID'
125+
required: true
126+
schema:
127+
type: string
128+
format: uuid
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
openapi: 3.0.0
2+
info:
3+
title: 'Test REST API'
4+
description: 'Specifications for the Test REST API.'
5+
contact:
6+
name: bplainia
7+
8+
version: '2021-05-18'
9+
servers:
10+
-
11+
url: 'http://localhost:8000'
12+
description: Test
13+
paths:
14+
'/v1/organizations/{organizationId}/user':
15+
post:
16+
tags:
17+
- pets
18+
summary: 'Creates a user'
19+
requestBody:
20+
content:
21+
application/json:
22+
schema:
23+
type: object
24+
properties:
25+
data:
26+
type: object
27+
properties:
28+
id:
29+
type: string
30+
format: uuid
31+
name:
32+
type: string
33+
required: true
34+
responses:
35+
'201':
36+
description: Created
37+
content:
38+
application/json:
39+
schema:
40+
type: object
41+
properties:
42+
data:
43+
type: object
44+
properties:
45+
id:
46+
type: string
47+
format: uuid
48+
name:
49+
type: string
50+
'400':
51+
description: 'Bad Request'
52+
'403':
53+
description: Forbidden
54+
security:
55+
-
56+
BearerAuth: []
57+
parameters:
58+
-
59+
name: api-version
60+
in: header
61+
description: 'The API version'
62+
required: false
63+
schema:
64+
type: string
65+
format: date
66+
example: '2021-05-18'
67+
-
68+
name: organizationId
69+
in: path
70+
description: 'The Organization ID'
71+
required: true
72+
schema:
73+
type: string
74+
format: uuid
75+
'/v1/organizations/{organizationId}/user/{id}':
76+
get:
77+
summary: 'Gets a user'
78+
responses:
79+
'200':
80+
description: 'A bar'
81+
content:
82+
application/json:
83+
schema:
84+
type: object
85+
properties:
86+
data:
87+
type: object
88+
properties:
89+
id:
90+
type: string
91+
format: uuid
92+
name:
93+
type: string
94+
'400':
95+
description: 'Bad Request'
96+
'403':
97+
description: Forbidden
98+
'404':
99+
description: 'Not Found'
100+
security:
101+
-
102+
BearerAuth: []
103+
parameters:
104+
-
105+
name: api-version
106+
in: header
107+
description: 'The API version'
108+
required: false
109+
schema:
110+
type: string
111+
format: date
112+
example: '2021-05-18'
113+
-
114+
name: organizationId
115+
in: path
116+
description: 'The Organization ID'
117+
required: true
118+
schema:
119+
type: string
120+
format: uuid
121+
-
122+
name: id
123+
in: path
124+
description: "User's ID"
125+
required: true
126+
schema:
127+
type: string
128+
format: uuid

tests/spec/PathTest.php

+67
Original file line numberDiff line numberDiff line change
@@ -192,4 +192,71 @@ public function testPathItemReference()
192192
$this->assertEquals('A bar', $barPath->get->responses['200']->description);
193193
$this->assertEquals('non-existing resource', $barPath->get->responses['404']->description);
194194
}
195+
196+
public function testPathParametersAreArrays()
197+
{
198+
$file = __DIR__ . '/data/path-params/openapi.yaml';
199+
/** @var $openapi \cebe\openapi\spec\OpenApi */
200+
$openapi = Reader::readFromYamlFile($file, \cebe\openapi\spec\OpenApi::class, true);
201+
202+
$result = $openapi->validate();
203+
$this->assertEquals([], $openapi->getErrors(), print_r($openapi->getErrors(), true));
204+
$this->assertTrue($result);
205+
206+
$this->assertInstanceOf(Paths::class, $openapi->paths);
207+
$this->assertSame(gettype($openapi->paths->getPaths()), 'array');
208+
$this->assertInstanceOf(PathItem::class, $usersPath = $openapi->paths['/v1/organizations/{organizationId}/user']);
209+
$this->assertInstanceOf(PathItem::class, $userIdPath = $openapi->paths['/v1/organizations/{organizationId}/user/{id}']);
210+
211+
$result = $usersPath->validate();
212+
$this->assertTrue($result);
213+
$this->assertSame(gettype($usersPath->parameters), 'array');
214+
$this->assertInstanceOf(\cebe\openapi\spec\Parameter::class, $usersPath->parameters[0]);
215+
$this->assertInstanceOf(\cebe\openapi\spec\Parameter::class, $usersPath->parameters[1]);
216+
$this->assertEquals('api-version', $usersPath->parameters[0]->name);
217+
218+
$result = $userIdPath->validate();
219+
$this->assertTrue($result);
220+
$this->assertSame(gettype($userIdPath->parameters), 'array');
221+
$this->assertInstanceOf(\cebe\openapi\spec\Parameter::class, $userIdPath->parameters[0]);
222+
$this->assertInstanceOf(\cebe\openapi\spec\Parameter::class, $userIdPath->parameters[1]);
223+
$this->assertEquals('id', $userIdPath->parameters[2]->name);
224+
225+
$dirSep = DIRECTORY_SEPARATOR;
226+
$output = dirname(__DIR__) . $dirSep . 'compiled.yml';
227+
shell_exec('php ' . dirname(__DIR__, 2) . "{$dirSep}bin{$dirSep}php-openapi inline " . $file . ' ' . $output);
228+
229+
$baseExpected = dirname(__DIR__)."{$dirSep}data{$dirSep}issue{$dirSep}155{$dirSep}";
230+
$expected = $baseExpected.'compiled-symfony-7.yml';
231+
$version = static::symfonyYamlVersion();
232+
$majorVersion = explode('.', $version)[0];
233+
234+
if ($majorVersion == 6) {
235+
$expected = $baseExpected."compiled-symfony-6.yml";
236+
if (version_compare(PHP_VERSION, '8.1', '>=') && version_compare($version, '6.0.0', '!=')) {
237+
$expected = $baseExpected."compiled-symfony-7.yml";
238+
}
239+
} elseif ($majorVersion == 5) {
240+
$expected = $baseExpected."compiled-symfony-6.yml";
241+
}
242+
if (stripos(PHP_OS, 'WIN') === 0) { # fixes https://github.com/cebe/php-openapi/actions/runs/14808968938/job/41581244210
243+
file_put_contents($expected, preg_replace('~\R~', "\n", file_get_contents($expected))); # not an ideal solution, can be refactored
244+
}
245+
246+
$this->assertFileEquals($output, $expected);
247+
unlink($output);
248+
}
249+
250+
protected static function symfonyYamlVersion()
251+
{
252+
$package = 'symfony/yaml';
253+
$installed = json_decode(file_get_contents(__DIR__ . '/../../composer.lock'), true);
254+
255+
foreach ($installed['packages'] as $pkg) {
256+
if ($pkg['name'] === $package) {
257+
return str_replace('v', '', $pkg['version']);
258+
}
259+
}
260+
return '7.0.0';
261+
}
195262
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
components:
2+
parameters:
3+
Version:
4+
in: header
5+
name: api-version
6+
required: false
7+
schema:
8+
type: string
9+
format: date
10+
example: '2021-05-18'
11+
description: The API version
12+
OrganizationId:
13+
in: path
14+
name: organizationId
15+
required: true
16+
schema:
17+
type: string
18+
format: uuid
19+
description: The Organization ID
20+
responses:
21+
BadRequest:
22+
description: Bad Request
23+
Forbidden:
24+
description: Forbidden
25+
NotFound:
26+
description: Not Found
27+
Success:
28+
description: Success
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
openapi: 3.0.0
2+
info:
3+
version: "2021-05-18"
4+
title: Test REST API
5+
description: Specifications for the Test REST API.
6+
contact:
7+
name: bplainia
8+
9+
10+
servers:
11+
- url: 'http://localhost:8000'
12+
description: 'Test'
13+
14+
paths:
15+
/v1/organizations/{organizationId}/user:
16+
$ref: 'user.yaml#/paths/Users'
17+
/v1/organizations/{organizationId}/user/{id}:
18+
$ref: 'user.yaml#/paths/UserId'

0 commit comments

Comments
 (0)