Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serialisation/deserialisation no longer works #1556

Open
ianef opened this issue Jul 11, 2024 · 2 comments
Open

Serialisation/deserialisation no longer works #1556

ianef opened this issue Jul 11, 2024 · 2 comments
Labels
type:enhancement Enhancement request targeting an existing experience

Comments

@ianef
Copy link

ianef commented Jul 11, 2024

Describe the bug

Native serialisation and deserialisation of models no longer works in v2.

In the msgraph-sdk-php-core readme.md file it states:

We provide Microsoft Graph models for easy serialization and deserialization.

If you would like to leverage the models we provide, please take a look at the [Microsoft Graph PHP SDK](https://packagist.org/packages/microsoft/microsoft-graph) and for beta models - the [Microsoft Graph Beta PHP SDK](https://packagist.org/packages/microsoft/microsoft-graph-beta).

Sadly this is no longer the case. As soon as any nested object is added to a model, serialisation fails as the embedded closures cannot be serialised.

Admittedly this text is obviously written for V1 as it references Graph Beta, but I don't think it has been intentional to remove the ability to natively serialise models. If that is the case, I think that is a bad move. I don't think there in anything in the upgrade.md file that suggests you can no longer natively serialize and, importantly, deserialize models. No examples exist describing how to do this using the SDK.

Take for example the Message model, in it's basic form you can serialise it, however as soon as you add an ItemBody element you can't because the backing store now contains a subscriber for changes to the ItemBody, which is implemented as a closure. This prevents the Message model from being serialised using native PHP serialize/unserialize methods.

My usage case is that I need to offload the sending of messages to a background task. The messages are created when forms are submitted etc. and saved to a scheduler list which picks them up via a command line background task, and then performs the actual sending of the Message object.

There are already issues that hint towards this problem but not to the actual cause of the error:
#1471
#1470
#1452

Expected behavior

Native serialize and unserialize methods should work with all SDK models.

How to reproduce

This simple code will crash when attempting to serialise the Message object:

    $message = new Message();
    $message->setSubject('Test');
    $body = new ItemBody();
    $body->setContentType(new BodyType(BodyType::HTML));
    $body->setContent('<p>Test</p>');
    $message->setBody($body); // Causes a subscription to be set on ItemBody
    $test = serialize($message); // This would be stored for the background task.

SDK Version

v2.12.0

Latest version known to work for scenario above?

v1

Known Workarounds

None.

Debug output

Click to expand log object(Exception)#705 (7) { ["message":protected]=> string(41) "Serialization of 'Closure' is not allowed" ["string":"Exception":private]=> string(0) "" ["code":protected]=> int(0) ["file":protected]=> string(64) "redacted.php" ["line":protected]=> int(220) ["trace":"Exception":private]=> array(5) { ... } ```

Configuration

No response

Other information

No response

@ianef ianef added status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience labels Jul 11, 2024
@Ndiritu
Copy link
Contributor

Ndiritu commented Jul 12, 2024

Hi @ianef, thanks for reaching out.
Apologies for this experience. This will be taken into consideration.

A temporary work-around would be:

$serializationWriter = new JsonSerializationWriter();
$serializationWriter->writeObjectValue("", $message);
$jsonString = $serializationWriter->getSerializedContent()->getContents();

@Ndiritu Ndiritu added type:enhancement Enhancement request targeting an existing experience and removed status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience labels Jul 12, 2024
@ianef
Copy link
Author

ianef commented Jul 12, 2024

Many thanks @Ndiritu I'll have a go with your code. I didn't realise you could instantiate the writers like that. I hacked around a bit and and came up with this serializer helper, but ideally I'd like to use native PHP serialisation not JSON.

class EntityJsonSerializer
{
    public static function serialize(Parsable $model): string
    {
            $writer = SerializationWriterFactoryRegistry::getDefaultInstance()->getSerializationWriter('application/json');
            $writer->writeObjectValue(null, $model);
            return (string)$writer->getSerializedContent();
    }

    /**
     * @param class-string<\Microsoft\Kiota\Abstractions\Serialization\Parsable> $entityClass
     */
    public static function deserialize(string $jsonModel, string $entityClass): Parsable
    {
        $node = ParseNodeFactoryRegistry::getDefaultInstance()->getRootParseNode('application/json', Utils::streamFor($jsonModel));
        $result = $node->getObjectValue([$entityClass, 'createFromDiscriminatorValue']);
        if ($result === null) {
            throw SerializerException::couldNotDeserialize($entityClass);
        }
        return $result;
    }
}

I did wonder if we created an ArraySerializationWriter and added that to the BaseGraphClient constructor, then call this in the Entity class __serailize and __unserialize methods to return or set the backing store array of actual property values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:enhancement Enhancement request targeting an existing experience
Projects
None yet
Development

No branches or pull requests

2 participants