php-ews icon indicating copy to clipboard operation
php-ews copied to clipboard

WSDL Regeneration

Open Garethp opened this issue 3 months ago • 7 comments

Turns out that after the WSDL update was contributed last year I forgot to regenerate the API to match it. This PR solves that, adding all the new types with the newer WSDL.

For future note (although I doubt we'll need to worry about this again), we had an issue where on the first pass some types were trying to extend other types that hadn't been generated yet (but would be in that run). This was throwing some errors, so instead of trying to have the code either assume that those classes would eventually exist, or trying to order the generation in a way that prevented such dependencies we just opt to skip using those classes. As a result, we need to generate the items twice. The first pass creates all the items and the second pass adds the extends and references that were skipped in the first pass.

Garethp avatar Sep 05 '25 01:09 Garethp

@kambereBr This PR contains the types you needed, as well as all the other missed types. Would be able to test this and see if it solves your issues?

Garethp avatar Sep 05 '25 01:09 Garethp

Just for the sake of it, I did try to sort the item generation in such a way that we'd always go top-down in the dependency tree so that by the time each class goes into generation then what they reference is already generated. This works fine when we only look at what the class extends, but once we look into what types they reference through their properties (Which we do need to do, for generating the getters and setters), we end up with circular dependencies.

We could resolve that by doing a two-pass generation where we generate the classes first and then the getters/setters afterwards but it's almost definitely not worth the effort. It's not as though EWS is in active development and will be receiving more WSDL updates or anything, and running the generateModels.php twice isn't exactly onerous as is.

Garethp avatar Sep 05 '25 02:09 Garethp

@kambereBr This PR contains the types you needed, as well as all the other missed types. Would be able to test this and see if it solves your issues?

@Garethp, thanks for this PR! I’m testing it now and will share feedback as soon as possible. Appreciate your support on this.

kambereBr avatar Sep 05 '25 08:09 kambereBr

@kambereBr This PR contains the types you needed, as well as all the other missed types. Would be able to test this and see if it solves your issues?

Hi @Garethp,

After testing this PR, the archiving issue still persists. I tested using the example code from: https://github.com/Garethp/php-ews/blob/master/examples/mail/archiveItems.php

Unfortunately, it returns the following error:

All the items should be from the primary mailbox. Cannot archive items belonging to different mailboxes.
File: /src/API/ExchangeWebServices.php Line: 497
Stack trace:
#0 /src/API/ExchangeWebServices.php(455): garethp\ews\API\ExchangeWebServices::getItemsFromResponse(Object(garethp\ews\API\Message\ItemInfoResponseMessageType))
#1 /src/API/ExchangeWebServices.php(467): garethp\ews\API\ExchangeWebServices::drillDownResponseLevels(Object(garethp\ews\API\Message\ItemInfoResponseMessageType))
#2 /src/API/ExchangeWebServices.php(467): garethp\ews\API\ExchangeWebServices::drillDownResponseLevels(Object(garethp\ews\API\Message\ItemInfoResponseMessageType))
#3 /src/API/ExchangeWebServices.php(443): garethp\ews\API\ExchangeWebServices::drillDownResponseLevels(Array)
#4 /src/API/ExchangeWebServices/MiddlewareFactory.php(57): garethp\ews\API\ExchangeWebServices->processResponse(Object(garethp\ews\API\Message\ArrayOfResponseMessagesType))
#5 /src/API/ExchangeWebServices.php(580): garethp\ews\API\ExchangeWebServices->garethp\ews\API\ExchangeWebServices\{closure}(Object(garethp\ews\API\MiddlewareRequest), Object(Closure))
#6 /src/API/ExchangeWebServices/MiddlewareFactory.php(66): garethp\ews\API\ExchangeWebServices->garethp\ews\API\{closure}(Object(garethp\ews\API\MiddlewareRequest))
#7 /src/API/ExchangeWebServices.php(580): garethp\ews\API\ExchangeWebServices->garethp\ews\API\ExchangeWebServices\{closure}(Object(garethp\ews\API\MiddlewareRequest), Object(Closure))
#8 /src/API/ExchangeWebServices.php(590): garethp\ews\API\ExchangeWebServices->garethp\ews\API\{closure}(Object(garethp\ews\API\MiddlewareRequest))
#9 /src/API/ExchangeWebServices.php(377): garethp\ews\API\ExchangeWebServices->executeMiddlewareStack(Array, Object(garethp\ews\API\MiddlewareRequest))
#10 /archive-script.php(271): garethp\ews\API\ExchangeWebServices->__call('ArchiveItem', Array)
#11 {main}

kambereBr avatar Sep 09 '25 21:09 kambereBr

@kambereBr Can you post the full code that you're using to test? I know you said it's coming from the archiveItems example, but I'm assuming you're pulling the ItemIds in another way. Are you using impersonation somewhere? The error you posted doesn't look like it's related to a lack of types but rather an error from Exchange itself about the items you're trying to archive belonging to the wrong mailbox.

Garethp avatar Sep 09 '25 22:09 Garethp

@kambereBr Can you post the full code that you're using to test? I know you said it's coming from the archiveItems example, but I'm assuming you're pulling the ItemIds in another way. Are you using impersonation somewhere? The error you posted doesn't look like it's related to a lack of types but rather an error from Exchange itself about the items you're trying to archive belonging to the wrong mailbox.

@Garethp you’re right, the initial type issue is no longer occurring.

Here’s a sample of the code I’m currently using:

require_once "vendor/autoload.php";

use garethp\ews\API\Enumeration\DistinguishedFolderIdNameType;
use garethp\ews\API\ExchangeWebServices;
use garethp\ews\API\Type;
use garethp\ews\API\Type\DistinguishedFolderIdType;

$ews = ExchangeWebServices::fromUsernameAndPassword('xxxxxxx', 'xxxxxxxxxx', 'xxxxxxxxx',['version' => ExchangeWebServices::VERSION_2016]);

try {    
    $findRequest = [
        'Traversal' => 'Shallow',
        'ItemShape' => [
            'BaseShape' => 'IdOnly',
            'AdditionalProperties' => [
                'FieldURI' => [
                    ['FieldURI' => 'item:Subject']
                ]
            ]
        ],
        'ParentFolderIds' => (new DistinguishedFolderIdType(DistinguishedFolderIdNameType::INBOX))->toArray(true)
    ];
    
    $findRequest = Type::buildFromArray($findRequest);
    $findResult = $ews->FindItem($findRequest);
    
    $items = $findResult->getItems()->getMessage() ?? [];    
    if (count($items) > 0) {
        // Get the first item ID
        $firstItem = $items[0];
        $itemId = $firstItem->getItemId()->getId();

        $archiveRequest = [
            'ArchiveSourceFolderId' => (new DistinguishedFolderIdType(DistinguishedFolderIdNameType::INBOX))->toArray(true),
            'ItemIds' => [
                'ItemId' => [$itemId],
            ]
        ];

        $archiveRequest = Type::buildFromArray($archiveRequest);
        $result = $ews->ArchiveItem($archiveRequest);
        
    } else {
        echo "No items found in INBOX to archive\n";
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

kambereBr avatar Sep 09 '25 22:09 kambereBr

@Garethp Why is the use garethp\ews\API\Enumeration; line missing from the RoutingType? I see that all other classes have it, and it throws an error for me when I try to use it.

https://github.com/Garethp/php-ews/blob/wsdl-regeneration/src/API/Enumeration/RoutingType.php

gazben avatar Oct 16 '25 14:10 gazben