Crell / Serde

Robust Serde (serialization/deserialization) library for PHP 8.
Other
299 stars 14 forks source link

Deserialize arrays of objects when used as values in dictionaries #4

Closed hnrch02 closed 2 years ago

hnrch02 commented 2 years ago

Hi, loving the library so far!

I'm struggling to properly deserialize dictionaries whose values are arrays of objects. This is where I'm at:

use Crell\Serde\Attributes as Serde;

class Note {
    public string $text;
}

class Test {
    /**
     * @var array<string, Note[]>
     */
    #[Serde\DictionaryField(arrayType: 'array')]
    public array $notes = [];
}

As the PHPDoc specifies, the $notes member of the Test class is supposed to be a dictionary with string keys and Note arrays as values.

I managed to get it to work by introducing a Notes intermediary class, which I can then specify as the arrayType like so:

class Notes {
    #[Serde\SequenceField(arrayType: Note::class)]
    public array $notes = [];
}

class Test {
    /**
     * @var array<string, Notes>
     */
    #[Serde\DictionaryField(arrayType: Notes::class)]
    public array $notes = [];
}

but this is not ideal, since it complicates the serialized output unnecessarily, and makes it harder to address the individual elements as I have to go through the Notes class. I also tried applying type maps, but I didn't get far with that either.

So my question is: Can I do this in a better way? Maybe I'm missing an obvious solution here, so I would be grateful if someone could point me in the right direction.

Crell commented 2 years ago

Oh hey, people are using this library! :smile:

Unfortunately, I don't think what you're doing is possible directly. Serde doesn't know from the docblocks, only the attributes, and there's no way to document the type of the inner array. The deserializer will see the incoming array but have no idea that it's supposed to map it to something. Objects nested inside arrays are just not sufficiently self-describing.

Possible workarounds to try:

Off hand, I suspect a custom importer is the most promising.