From d8626c273522701a4c9270010d67104ad80a9f30 Mon Sep 17 00:00:00 2001 From: Christopher Davis Date: Mon, 1 Feb 2021 08:37:20 -0600 Subject: [PATCH] Introduce a Trait to Build OpenAPI Discriminators See https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/ This is the adapter layer that will be included in the various model describers. The creation of the discriminator and the `oneOf` values is a little finicky and I wanted it to be tested and centralized. --- .../ApplyOpenApiDiscriminatorTrait.php | 60 +++++++++++++ .../ApplyOpenApiDiscriminatorTraitTest.php | 88 +++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 ModelDescriber/ApplyOpenApiDiscriminatorTrait.php create mode 100644 Tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php diff --git a/ModelDescriber/ApplyOpenApiDiscriminatorTrait.php b/ModelDescriber/ApplyOpenApiDiscriminatorTrait.php new file mode 100644 index 0000000..dd551fd --- /dev/null +++ b/ModelDescriber/ApplyOpenApiDiscriminatorTrait.php @@ -0,0 +1,60 @@ + $typeMap the map of $discriminatorProperty values to their + * types + */ + protected function applyOpenApiDiscriminator( + Model $model, + OA\Schema $schema, + ModelRegistry $modelRegistry, + string $discriminatorProperty, + array $typeMap + ) : void { + $schema->oneOf = []; + $schema->discriminator = new OA\Discriminator([]); + $schema->discriminator->propertyName = $discriminatorProperty; + $schema->discriminator->mapping = []; + foreach ($typeMap as $propertyValue => $className) { + $oneOfSchema = new OA\Schema([]); + $oneOfSchema->ref = $modelRegistry->register(new Model( + new Type(Type::BUILTIN_TYPE_OBJECT, false, $className), + $model->getGroups(), + $model->getOptions() + )); + $schema->oneOf[] = $oneOfSchema; + $schema->discriminator->mapping[$propertyValue] = clone $oneOfSchema; + + } + } +} diff --git a/Tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php b/Tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php new file mode 100644 index 0000000..0644a8b --- /dev/null +++ b/Tests/ModelDescriber/ApplyOpenApiDiscriminatorTraitTest.php @@ -0,0 +1,88 @@ + 123]; + + private $schema; + + private $model; + + public function testApplyAddsDiscriminatorProperty() + { + $this->applyOpenApiDiscriminator($this->model, $this->schema, $this->modelRegistry, 'type', [ + 'one' => 'FirstType', + 'two' => 'SecondType', + ]); + + $this->assertInstanceOf(OA\Discriminator::class, $this->schema->discriminator); + $this->assertSame('type', $this->schema->discriminator->propertyName); + $this->assertArrayHasKey('one', $this->schema->discriminator->mapping); + $this->assertSame( + $this->modelRegistry->register($this->createModel('FirstType')), + $this->schema->discriminator->mapping['one']->ref + ); + $this->assertArrayHasKey('two', $this->schema->discriminator->mapping); + $this->assertSame( + $this->modelRegistry->register($this->createModel('SecondType')), + $this->schema->discriminator->mapping['two']->ref + ); + } + + public function testApplyAddsOneOfFieldToSchema() + { + $this->applyOpenApiDiscriminator($this->model, $this->schema, $this->modelRegistry, 'type', [ + 'one' => 'FirstType', + 'two' => 'SecondType', + ]); + + $this->assertNotSame(OA\UNDEFINED, $this->schema->oneOf); + $this->assertCount(2, $this->schema->oneOf); + $this->assertSame( + $this->modelRegistry->register($this->createModel('FirstType')), + $this->schema->oneOf[0]->ref + ); + $this->assertSame( + $this->modelRegistry->register($this->createModel('SecondType')), + $this->schema->oneOf[1]->ref + ); + } + + protected function setUp() : void + { + $this->schema = new OA\Schema([]); + $this->model = $this->createModel(__CLASS__); + $this->modelRegistry = new ModelRegistry([], new OA\OpenApi([])); + } + + private function createModel(string $className) : Model + { + return new Model( + new Type(Type::BUILTIN_TYPE_OBJECT, false, $className), + self::GROUPS, + self::OPTIONS + ); + } +}