Skip to content

Commit 5eba2c1

Browse files
committed
Allow Reference for Schema::additionalProperties
adding a ref here was not possible before and resulted in a broken Schema object.
1 parent 18fd035 commit 5eba2c1

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

src/SpecBaseObject.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ public function __construct(array $data)
125125
/**
126126
* @throws TypeErrorException
127127
*/
128-
private function instantiate($type, $data)
128+
protected function instantiate($type, $data)
129129
{
130-
if ($data instanceof $type) {
130+
if ($data instanceof $type || $data instanceof Reference) {
131131
return $data;
132132
}
133133

src/spec/Schema.php

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,21 +136,13 @@ public function __construct(array $data)
136136
{
137137
if (isset($data['additionalProperties'])) {
138138
if (is_array($data['additionalProperties'])) {
139-
try {
140-
$data['additionalProperties'] = new Schema($data['additionalProperties']);
141-
} catch (\TypeError $e) {
142-
throw new TypeErrorException(
143-
"Unable to instantiate Schema Object with data '" . print_r($data['additionalProperties'], true) . "'",
144-
$e->getCode(),
145-
$e
146-
);
147-
}
148-
} elseif (!($data['additionalProperties'] instanceof Schema || is_bool($data['additionalProperties']))) {
139+
$data['additionalProperties'] = $this->instantiate(Schema::class, $data['additionalProperties']);
140+
} elseif (!($data['additionalProperties'] instanceof Schema || $data['additionalProperties'] instanceof Reference || is_bool($data['additionalProperties']))) {
149141
$givenType = gettype($data['additionalProperties']);
150142
if ($givenType === 'object') {
151143
$givenType = get_class($data['additionalProperties']);
152144
}
153-
throw new TypeErrorException(sprintf('Schema::$additionalProperties MUST be either array, boolean or a Schema object, "%s" given', $givenType));
145+
throw new TypeErrorException(sprintf('Schema::$additionalProperties MUST be either boolean or a Schema/Reference object, "%s" given', $givenType));
154146
}
155147
}
156148
parent::__construct($data);

tests/spec/SchemaTest.php

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ public function badSchemaProvider()
167167
yield [['properties' => ['a' => false]], 'Unable to instantiate cebe\openapi\spec\Schema Object with data \'\''];
168168
yield [['properties' => ['a' => new stdClass()]], "Unable to instantiate cebe\openapi\spec\Schema Object with data 'stdClass Object\n(\n)\n'"];
169169

170-
yield [['additionalProperties' => 'foo'], 'Schema::$additionalProperties MUST be either array, boolean or a Schema object, "string" given'];
171-
yield [['additionalProperties' => 42], 'Schema::$additionalProperties MUST be either array, boolean or a Schema object, "integer" given'];
172-
yield [['additionalProperties' => new stdClass()], 'Schema::$additionalProperties MUST be either array, boolean or a Schema object, "stdClass" given'];
170+
yield [['additionalProperties' => 'foo'], 'Schema::$additionalProperties MUST be either boolean or a Schema/Reference object, "string" given'];
171+
yield [['additionalProperties' => 42], 'Schema::$additionalProperties MUST be either boolean or a Schema/Reference object, "integer" given'];
172+
yield [['additionalProperties' => new stdClass()], 'Schema::$additionalProperties MUST be either boolean or a Schema/Reference object, "stdClass" given'];
173173
// The last one can be supported in future, but now SpecBaseObjects::__construct() requires array explicitly
174174
}
175175

@@ -283,4 +283,41 @@ public function testSchemaProperties()
283283
$this->assertEquals($defaultValue, $schema->$property, "testing property '$property'");
284284
}
285285
}
286+
287+
public function testRefAdditionalProperties()
288+
{
289+
$json = <<<'JSON'
290+
{
291+
"components": {
292+
"schemas": {
293+
"booleanProperties": {
294+
"type": "boolean"
295+
},
296+
"person": {
297+
"type": "object",
298+
"properties": {
299+
"name": {
300+
"type": "string"
301+
}
302+
},
303+
"additionalProperties": {"$ref": "#/components/schemas/booleanProperties"}
304+
}
305+
}
306+
}
307+
}
308+
JSON;
309+
$openApi = Reader::readFromJson($json);
310+
$this->assertInstanceOf(Schema::class, $booleanProperties = $openApi->components->schemas['booleanProperties']);
311+
$this->assertInstanceOf(Schema::class, $person = $openApi->components->schemas['person']);
312+
313+
$this->assertEquals('boolean', $booleanProperties->type);
314+
$this->assertInstanceOf(Reference::class, $person->additionalProperties);
315+
316+
$this->assertInstanceOf(Schema::class, $refResolved = $person->additionalProperties->resolve(new ReferenceContext($openApi, 'tmp://openapi.yaml')));
317+
318+
$this->assertEquals('boolean', $refResolved->type);
319+
320+
$schema = new Schema(['additionalProperties' => new Reference(['$ref' => '#/here'], Schema::class)]);
321+
$this->assertInstanceOf(Reference::class, $schema->additionalProperties);
322+
}
286323
}

0 commit comments

Comments
 (0)