Skip to content

GuzzleHttp\Psr7\Stream properties in models NOT serialized to request body #1052

@mbabker

Description

@mbabker

Using v1.81.0 of the SDK, trying to add attachments to an email fails when providing the Microsoft\Graph\Model\FileAttachment::setContentBytes() method a GuzzleHttp\Psr7\Stream instance as its single parameter. Passing through a string results in things working correctly.

Minimal reproducer:

function send_email(\Symfony\Component\Mime\Email $email): void
{
    $graph = new \Microsoft\Graph\Graph();
    $graph->setAccessToken($accessToken);

    $graphMessageResponse = $graph->createRequest('POST', sprintf('/users/%s/messages', $userEmail))
        ->attachBody(build_graph_message_request($email))
        ->setReturnType(\Microsoft\Graph\Model\Message::class)
        ->execute();

    foreach ($email->getAttachments() as $dataPart) {
        $attachmentStream = \GuzzleHttp\Psr7\UtilsUtils::streamFor(base64_encode($dataPart->getBody()));
        $attachmentSize   = $attachmentStream->getSize();

        if ($attachmentSize <= (MEGABYTE_IN_BYTES * 3)) {
            $attachment = new \Microsoft\Graph\Model\FileAttachment();
            $attachment->setODataType('#microsoft.graph.fileAttachment');
            $attachment->setName($dataPart->getFilename());
            $attachment->setContentType($dataPart->getContentType());
            $attachment->setContentBytes($attachmentStream);
            // $attachment->setContentBytes(base64_encode($dataPart->getBody())); <-- This version works
            $attachment->setContentId(\Illuminate\Support\Str::random(10));

            $graph->createRequest('POST', sprintf('/users/%s/messages/%s/attachments', $userEmail, $graphMessageResponse->getId()))
                ->attachBody($attachment)
                ->setReturnType(\Microsoft\Graph\Model\FileAttachment::class)
                ->execute();
        } else {
            // Large file upload branch, not related to this issue
        }
    }

    $graph->createRequest('POST', sprintf('/users/%s/messages/%s/send', $userEmail, $graphMessageResponse->getId()))
        ->execute();
}

Suggested fixes:

Option 1 - The Microsoft\Graph\Model\FileAttachment::setContentBytes() method should be documented as requiring a string instead of a GuzzleHttp\Psr7\Stream instance if it is not intended for developers to pass through a stream they've created themselves
Option 2 - The Microsoft\Graph\Model\Entity::jsonSerialize() method should be updated to include another condition for a GuzzleHttp\Psr7\Stream instance and manually typecast it to a string:

public function jsonSerialize()
{
    $serializableProperties = $this->getProperties();
    foreach ($serializableProperties as $property => $val) {
        if (is_a($val, "\DateTime")) {
            $serializableProperties[$property] = $val->format(\DateTime::RFC3339);
        } else if (is_a($val, "\Microsoft\Graph\Core\Enum")) {
            $serializableProperties[$property] = $val->value();
        } else if (is_a($val, "\Entity")) {
            $serializableProperties[$property] = $val->jsonSerialize();
        } else if (is_a($val, "\GuzzleHttp\Psr7\Stream")) {
            $serializableProperties[$property] = (string) $val;
        }
    }
    return $serializableProperties;
}

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions