问题
I have an abstract parent (mapped super-)class which has several children with different properties which I'd like to deserialize. I'm storing the data using MongoDB and Doctrine ODM, so I also have a discriminator field which tells doctrine which subclass is used (and also have a custom "type" property ontop which is used elsewhere to determine which class is currently processed).
When deserializing my model, I get an exception telling me that its impossible to create an instance of an abstract class (ofcourse) - now I'm wondering how I can tell the JMS Deserializer which inherited class it should use (that is why I use a custom type
instance variable for example - because I have no access to doctrine's discriminator field mapping).
I can successfully hook into the preDeserializeEvent
- so maybe it is possible to make some switch/cases there (or using the )?
My Model in short (abstract class):
<?php
namespace VBCMS\Bundle\AdminBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use JMS\Serializer\Annotation as Serializer;
/**
* abstract Class Module
* @Serializer\AccessType("public_method")
* @MongoDB\MappedSuperclass
* @MongoDB\InheritanceType("SINGLE_COLLECTION")
* @MongoDB\DiscriminatorField(fieldName="_discriminator_field")
* @MongoDB\DiscriminatorMap({
* "module"="Module",
* "text_module"="TextModule",
* "menu_module"="MenuModule",
* "image_module"="ImageModule"
* })
*/
abstract class Module {
const TYPE_MODULE_TEXT = 'module.text';
const TYPE_MODULE_MENU = 'module.menu';
const TYPE_MODULE_MEDIA_ITEM = 'module.media.item';
/**
* @Serializer\Type("string")
* @MongoDB\Field(type="string")
* @var String
*/
protected $type;
/**
* @Serializer\Type("boolean")
* @MongoDB\Field(type="boolean")
* @var boolean
*/
protected $visible;
// getter/setter methods etc..
}
?>
One of the subclasses
<?php
namespace VBCMS\Bundle\AdminBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use JMS\Serializer\Annotation as Serializer;
/**
* Class TextModule
* @package VBCMS\Bundle\AdminBundle\Document
* @Serializer\AccessType("public_method")
* @MongoDB\EmbeddedDocument
*/
class TextModule extends Module {
const TEXT_TYPE_SPLASH_HEADLINE = 'splashscreen.headline';
const TEXT_TYPE_SPLASH_SUBLINE = 'splashscreen.subline';
/**
* the actual text
*
* @var string
* @Serializer\Type("string")
* @MongoDB\Field(type="string")
*/
protected $text;
/**
* how it is called in the admin interface
*
* @var string
* @Serializer\Type("string")
* @MongoDB\Field(type="string")
*/
protected $label;
/**
* @var string
* @Serializer\Type("string")
* @MongoDB\Field(type="string")
*/
protected $textType;
// getter/setter methods etc..
?>
Another test was to not make the Module class abstract and to create a custom static method
/**
*
* @Serializer\HandlerCallback("json", direction="deserialization")
* @param JsonDeserializationVisitor $visitor
*/
public static function deserializeToObject(JsonDeserializationVisitor $visitor)
{
// modify visitor somehow to return an instance of the desired inherited module class??
}
any ideas?
回答1:
I found a discriminator mapping in the Tests directory of the plugin, unfortunately, this is not yet documented: https://github.com/schmittjoh/serializer/blob/master/tests/JMS/Serializer/Tests/Fixtures/Discriminator/Vehicle.php
Documentation is updated http://jmsyst.com/libs/serializer/master/reference/annotations#discriminator
namespace JMS\Serializer\Tests\Fixtures\Discriminator;
use JMS\Serializer\Annotation as Serializer;
/**
* @Serializer\Discriminator(field = "type", map = {
* "car": "JMS\Serializer\Tests\Fixtures\Discriminator\Car",
* "moped": "JMS\Serializer\Tests\Fixtures\Discriminator\Moped",
* })
*/
abstract class Vehicle
{
/** @Serializer\Type("integer") */
public $km;
public function __construct($km)
{
$this->km = (integer) $km;
}
}
来源:https://stackoverflow.com/questions/17275117/jms-serializer-deserialize-with-abstract-parent-class