Skip to content

[REQ][PHP] Discriminator does not actually work when using ObjectSerializer::deserialize() #11432

Open
@jtreminio

Description

@jtreminio

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions