Description
Is your feature request related to a problem? Please describe.
I don't think the current implementation of discriminator actually works as expected. Passing an array of data to ObjectSerializer::deserialize()
does not instantiate the correct child class.
openapi: 3.0.3
info:
title: 'API'
version: 1.0.0
servers:
-
url: 'https://example.com'
paths:
/foo:
post:
tags:
- Bar
summary: 'Summary'
operationId: foo
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PetBaseObject'
responses:
'200':
description: 'successful operation'
components:
schemas:
PetBaseObject:
type: object
required:
- pet_type
properties:
pet_type:
type: string
discriminator:
propertyName: pet_type
mapping:
dog: '#/components/schemas/PetDog'
cat: '#/components/schemas/PetCat'
fish: '#/components/schemas/PetFish'
PetDog:
type: object
allOf:
- $ref: '#/components/schemas/PetBaseObject'
-
required:
- pet_type
properties:
pet_type:
type: string
default: dog
likes_fetch:
type: boolean
PetCat:
type: object
allOf:
- $ref: '#/components/schemas/PetBaseObject'
-
required:
- pet_type
properties:
pet_type:
type: string
default: cat
likes_catnip:
type: boolean
PetFish:
type: object
allOf:
- $ref: '#/components/schemas/PetBaseObject'
-
required:
- pet_type
properties:
pet_type:
type: string
default: fish
water_type:
type: string
<?php
require_once __DIR__ . '/vendor/autoload.php';
$pet = OpenAPI\Client\ObjectSerializer::deserialize([
'pet_type' => 'cat',
'likes_catnip' => false,
], OpenAPI\Client\Model\PetBaseObject::class);
var_dump($pet);
$ php test.php
object(OpenAPI\Client\Model\PetBaseObject)#3 (1) {
["container":protected]=>
array(1) {
["pet_type"]=>
string(13) "PetBaseObject"
}
}
Describe the solution you'd like
I would expect discriminator instantiation to work similarly to the typescript-fetch
generator. It reads the discriminator
field value and does a simple comparison and returns the correct class type.
In the PHP generator it would look like this:
class PetBaseObject implements ModelInterface, ArrayAccess, \JsonSerializable
{
// ...
public static function discriminatorClassName(array $data): ?string
{
if (!array_key_exists('pet_type', $data)) {
return null;
}
if ($data['pet_type'] === 'cat') {
return PetCat::class;
}
if ($data['pet_type'] === 'dog') {
return PetDog::class;
}
if ($data['pet_type'] === 'fish') {
return PetFish::class;
}
return null;
}
In my mind the whole point of passing an array of data to ObjectSerializer::deserialize()
is for it to do all instantiation for the user. Otherwise the user would simply do
$cat = new OpenAPI\Client\Model\PetCat();
$cat->setLikesCatnip(true);
Was this choice done on purpose? I have code ready for a PR if it is something you think would be a good addition to the generator:
$ php test.php
object(OpenAPI\Client\Model\PetCat)#3 (1) {
["container":protected]=>
array(2) {
["pet_type"]=>
string(3) "cat"
["likes_catnip"]=>
bool(false)
}
}
@jebentier @dkarlovi @mandrean @jfastnacht @ackintosh @ybelenko @renepardon