Open jtreminio opened 2 years ago
Upvote on this. The discriminator is also not set automatically correctly.
@SebastianStehle would you like to contribute a PR or sponsor a fix?
I don't know yet. But I think I have the solution that works for me. I had custom templates anyway.
Right now the generator assumes that the discriminator value is the same as the class name, which is often not the case. Therefore I create 2 properties per class with the mappings:
In model__generic.mustache
/**
* Array of mapping. Used for (de)serialization
*
* @var string[]
*/
protected static $openAPIMappings = [
{{#discriminator}}
{{#mappedModels}}'{{mappingName}}' => '{{{modelName}}}'{{^-last}},
{{/-last}}{{/mappedModels}}
{{/discriminator}}
];
/**
* Array of mapping. Used for (de)serialization
*
* @var string[]
*/
protected static $openAPIMappingsReverse = [
{{#discriminator}}
{{#mappedModels}}'{{modelName}}' => '{{{mappingName}}}'{{^-last}},
{{/-last}}{{/mappedModels}}
{{/discriminator}}
];
/**
* Array of discriminator mappings. Used for (de)serialization
*
* @return array
*/
public static function openAPIMappings()
{
return self::$openAPIMappings;
}
Inherited classes do not set the discriminator value. I was able to fix that with:
In model__generic.mustache
public function __construct(array $data = null)
{
....
{{#parentModel}}
{{#discriminator}}
// Initialize discriminator property with the model name.
$this->container['{{discriminatorName}}'] = parent::$openAPIMappingsReverse['{{model.classname}}'];
{{/discriminator}}
{{/parentModel}}
{{/discriminator}}
}
Next we have to fix the serializer to use the mapping:
In ObjectSerializer.mustache:
// If a discriminator is defined and points to a valid subclass, use it.
$discriminator = $class::DISCRIMINATOR;
if (!empty($discriminator)) {
$discriminatorProperty = $class::attributeMap()[$discriminator];
if (isset($data->{$discriminatorProperty}) && is_string($data->{$discriminatorProperty})) {
$discriminatorValue = $data->{$discriminatorProperty};
$discriminatorType = $class::openAPIMAppings()[$discriminatorValue];
$subclass = '\{{invokerPackage}}\Model\\' . $discriminatorType;
if (is_subclass_of($subclass, $class)) {
$class = $subclass;
}
}
}
So far this works for me, but I don't understand if I have found all cases and I would like to focus on my client for now.
Thank you @SebastianStehle ! We used your code to patch the client generator. It seems to work fine and now we are able to use discriminators with mappings. Thank you for sharing!
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.Describe the solution you'd like
I would expect discriminator instantiation to work similarly to the
typescript-fetch
generator. It reads thediscriminator
field value and does a simple comparison and returns the correct class type.In the PHP generator it would look like this:
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 doWas 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:
@jebentier @dkarlovi @mandrean @jfastnacht @ackintosh @ybelenko @renepardon