Skip to content

Fix SOAP stdClass conversion for array|string union types#287

Open
kambereBr wants to merge 3 commits into
Garethp:masterfrom
kambereBr:union-type-array-handling
Open

Fix SOAP stdClass conversion for array|string union types#287
kambereBr wants to merge 3 commits into
Garethp:masterfrom
kambereBr:union-type-array-handling

Conversation

@kambereBr

@kambereBr kambereBr commented Mar 29, 2026

Copy link
Copy Markdown

This PR fixes SOAP stdClass conversion when properties expect union types like array|string

Error message 1:

Fatal error: Uncaught SoapFault exception: [Client] During class fetch: Uncaught TypeError: garethp\ews\API\Type\ContactType::setEmailAddresses(): Argument #1 ($value) must be of type array|string, stdClass given, called in cypht/vendor/garethp/php-ews/src/API/MagicMethodsTrait.php on line 23 and defined in cypht/vendor/garethp/php-ews/src/API/Type/ContactType.php:206

Error message 2:

garethp\ews\API\Type\ItemType::setCategories(): Argument #1 ($value) must be of type array|string, stdClass given, called in /var/www/html/vendor/garethp/php-ews/src/API/MagicMethodsTrait.php on line 23

@kambereBr

Copy link
Copy Markdown
Author

Hi @Garethp

Whenever you have a moment, could you please take a look at this PR?

Thank you!

@Garethp

Garethp commented Mar 29, 2026

Copy link
Copy Markdown
Owner

Would you mind adding a test so that I can see what's actually causing the error?

@kambereBr

Copy link
Copy Markdown
Author

Would you mind adding a test so that I can see what's actually causing the error?

Yes, sure. I'm adding the test now.

@kambereBr kambereBr force-pushed the union-type-array-handling branch from 4dcae79 to 7794e3e Compare March 29, 2026 17:43
@kambereBr

Copy link
Copy Markdown
Author

Would you mind adding a test so that I can see what's actually causing the error?

@Garethp I've just added a test to cover this. Thanks!

@Garethp

Garethp commented Mar 29, 2026

Copy link
Copy Markdown
Owner

I'll take a look at this later, thanks! If it's not too much trouble, and if you have access to an Exchange account, would you be able to make that a test that actually contacts Exchange and records the response, rather than trying to construct a similar shape as you'd expect from the response?

I'm not 100% sure I'll end up doing this, but one of the features I wouldn't mind attempting before I publish a 1.0 version is swapping away from SoapClient::_classmap to SoapClient::typemap and statically generating the XML -> Object conversion with the model generation, so that I can move away from the magic setters for object construction. If I do end up doing that, having more tests that assert an object shape from a soap call rather than from the magic setters will be very useful. Since I develop infrequently I don't always have access to an exchange account I can record tests with.

That said, if you don't have access to Exchange, no worries and I'll still pick this up and get this merged in you.

@kambereBr

kambereBr commented Mar 29, 2026

Copy link
Copy Markdown
Author

I'll take a look at this later, thanks! If it's not too much trouble, and if you have access to an Exchange account, would you be able to make that a test that actually contacts Exchange and records the response, rather than trying to construct a similar shape as you'd expect from the response?

I'm not 100% sure I'll end up doing this, but one of the features I wouldn't mind attempting before I publish a 1.0 version is swapping away from SoapClient::_classmap to SoapClient::typemap and statically generating the XML -> Object conversion with the model generation, so that I can move away from the magic setters for object construction. If I do end up doing that, having more tests that assert an object shape from a soap call rather than from the magic setters will be very useful. Since I develop infrequently I don't always have access to an exchange account I can record tests with.

That said, if you don't have access to Exchange, no worries and I'll still pick this up and get this merged in you.

Sounds good! I have access to an Exchange account, so I'll record real SOAP responses and add recording tests that actually contact Exchange.

I'm switching this PR to draft while I work on the recordings. I'll request another review once it's complete.

Thank you!

@kambereBr kambereBr marked this pull request as draft March 29, 2026 19:27
@gazben

gazben commented Apr 9, 2026

Copy link
Copy Markdown

FYI, we are getting the same error:

garethp\ews\API\Type\ItemType::setCategories(): Argument #1 ($value) must be of type array|string, stdClass given, called in /var/www/html/vendor/garethp/php-ews/src/API/MagicMethodsTrait.php on line 23

When calling:

        $queriedEvent = $exchangeService->getItem($item->getCalendarItem()->getItemId(), [
            'ItemShape' => [
                'BodyType' => 'Text',
            ],
        ]);

@kambereBr kambereBr force-pushed the union-type-array-handling branch from e2af68b to 6c56def Compare April 9, 2026 20:30
@gazben

gazben commented Apr 9, 2026

Copy link
Copy Markdown

@kambereBr I've checked our logs further and found a similar problems:

TypeError: garethp\ews\API\Type\ContactType::setUrls(): Argument #1 ($value) must be of type array|string, stdClass given, called in /var/www/html/vendor/garethp/php-ews/src/API/MagicMethodsTrait.php on line 23
TypeError: garethp\ews\API\Type\CalendarPermissionSetType::setUnknownEntries(): Argument #1 ($value) must be of type array|string, stdClass given, called in /var/www/html/vendor/garethp/php-ews/src/API/MagicMethodsTrait.php on line 23

Maybe it helps.

@kambereBr

Copy link
Copy Markdown
Author

FYI, we are getting the same error:

garethp\ews\API\Type\ItemType::setCategories(): Argument #1 ($value) must be of type array|string, stdClass given, called in /var/www/html/vendor/garethp/php-ews/src/API/MagicMethodsTrait.php on line 23

When calling:

        $queriedEvent = $exchangeService->getItem($item->getCalendarItem()->getItemId(), [
            'ItemShape' => [
                'BodyType' => 'Text',
            ],
        ]);

Hello @gazben

Thanks for reporting this, it really helped to add a proper integration test. I had some trouble reproducing the original issue since the emails in the shared Exchange test account had been cleared, so I lacked the right data to trigger the error. Your example made it much easier to reproduce the issue.

@kambereBr kambereBr marked this pull request as ready for review April 9, 2026 20:46
@kambereBr

Copy link
Copy Markdown
Author

Hi @Garethp

This PR is ready for another review.

Thanks!

@kambereBr

Copy link
Copy Markdown
Author

Hi @Garethp,

Any feedback on this pull request when you get a chance?

Thanks!

@vc-pratik-padia

vc-pratik-padia commented Jul 2, 2026

Copy link
Copy Markdown

Facing the same issue!!

Root Cause
The error is clearly localized:

ItemType::setCategories(): Argument #1 ($value) must be of type array|string, stdClass given
What's happening: A calendar item in Exchange has at least one category assigned to it. PHP's SOAP client deserializes a single XML category element as a stdClass object instead of an array — this is a classic SOAP deserialization problem. The setCategories() method in the php-ews library expects array|string and therefore throws a TypeError.

Call chain:

Exchange returns calendar item with a category set
→ NTLMSoapClient deserializes single category as stdClass
→ MagicMethodsTrait::__set() (line 23) calls setCategories(stdClass)
→ TypeError in ItemType.php:607

Het @Garethp, any plan to merge @kambereBr PR?

@gazben

gazben commented Jul 8, 2026

Copy link
Copy Markdown

@Garethp can you check this MR or a fork would be preferred?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants