Skip to content

Commit 8bb683d

Browse files
committed
Silently cast numeric property keys to string
This counteracts `json_encode` silently casting numeric strings to numbers.
1 parent 710d062 commit 8bb683d

3 files changed

Lines changed: 62 additions & 19 deletions

File tree

src/ValueObject/Valid/V30/Keywords.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -423,16 +423,10 @@ private function validateProperties(?array $properties): array
423423

424424
$result = [];
425425
foreach ($properties as $key => $subSchema) {
426-
if (!is_string($key)) {
427-
throw InvalidOpenAPI::mustHaveStringKeys(
428-
$this->getIdentifier(),
429-
'properties',
430-
);
431-
}
432-
433-
$result[$key] = new Schema(
426+
// json_decode casts numeric string keys to numbers
427+
$result[(string) $key] = new Schema(
434428
$this->getIdentifier()->append("properties($key)"),
435-
$subSchema
429+
$subSchema,
436430
);
437431
}
438432

src/ValueObject/Valid/V31/Keywords.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -445,16 +445,10 @@ private function validateProperties(?array $properties): array
445445

446446
$result = [];
447447
foreach ($properties as $key => $subSchema) {
448-
if (!is_string($key)) {
449-
throw InvalidOpenAPI::mustHaveStringKeys(
450-
$this->getIdentifier(),
451-
'properties',
452-
);
453-
}
454-
455-
$result[$key] = new Schema(
448+
// json_decode casts numeric string keys to numbers
449+
$result[(string) $key] = new Schema(
456450
$this->getIdentifier()->append("properties($key)"),
457-
$subSchema
451+
$subSchema,
458452
);
459453
}
460454

tests/MembraneReaderTest.php

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use Membrane\OpenAPIReader\Factory\V30\FromCebe;
1515
use Membrane\OpenAPIReader\MembraneReader;
1616
use Membrane\OpenAPIReader\Tests\Fixtures\Helper\OpenAPIProvider;
17-
use Membrane\OpenAPIReader\Tests\Fixtures\Helper\PartialHelper;
1817
use Membrane\OpenAPIReader\ValueObject\Partial;
1918
use Membrane\OpenAPIReader\ValueObject\Valid;
2019
use Membrane\OpenAPIReader\ValueObject\Valid\Enum\Method;
@@ -373,6 +372,62 @@ public function itReadsRealExamples(
373372
self::assertEquals($expected, $actual);
374373
}
375374

375+
#[Test]
376+
public function itReadsStringNumericKeysAsStrings(): void
377+
{
378+
$sut = new MembraneReader([
379+
OpenAPIVersion::Version_3_0,
380+
OpenAPIVersion::Version_3_1,
381+
]);
382+
383+
$api = json_encode([
384+
'openapi' => '3.0.3',
385+
'info' => [
386+
'title' => 'Numeric Property Keys',
387+
'version' => '1.0.0',
388+
],
389+
'paths' => ['/foo' => ['parameters' => [[
390+
'name' => 'object-with-numeric-keys',
391+
'in' => 'query',
392+
'schema' => [
393+
'type' => 'object',
394+
'properties' => [
395+
'1' => ['type' => 'string'],
396+
]
397+
]
398+
]]]]
399+
]);
400+
401+
$expected = OpenAPI::fromPartial(new Partial\OpenAPI(
402+
openAPI: '3.0.3',
403+
title: 'Numeric Property Keys',
404+
version: '1.0.0',
405+
paths: [
406+
new Partial\PathItem(
407+
path: '/foo',
408+
parameters: [
409+
new Partial\Parameter(
410+
name: 'object-with-numeric-keys',
411+
in: 'query',
412+
schema: new Partial\Schema(
413+
type: 'object',
414+
properties: [
415+
'1' => new Partial\Schema(type: 'string'),
416+
],
417+
)
418+
),
419+
]
420+
)
421+
]
422+
));
423+
424+
$actual = $sut->readFromString($api, FileFormat::Json);
425+
426+
427+
428+
self::assertEquals($expected, $actual);
429+
}
430+
376431
public static function provideInvalidFormatting(): Generator
377432
{
378433
yield 'Empty string to be interpreted as json' => ['', FileFormat::Json];

0 commit comments

Comments
 (0)