views:

773

answers:

3

I'm working on an integration between our web application and Microsoft Exchange 2007. I am using Exchange Web Services (EWS) to communicate to the Exchange Server. However, I am running into some issues with the WSDL. There are several types defined in the WSDL that have elements of abstract types. For example:

<xs:complexType name="RestrictionType">
  <xs:sequence>
    <xs:element ref="t:SearchExpression"/>
  </xs:sequence>
</xs:complexType>

SearchExpression is an abtract type. There are several types that extend SearchExpression such as ExistsType:

<xs:complexType name="ExistsType"> 
  <xs:complexContent> 
    <xs:extension base="t:SearchExpressionType"> 
      ...
    </xs:extension>
  </xs:complexContent>
</xs:complexType>
<xs:element name="Exists" type="t:ExistsType" substitutionGroup="t:SearchExpression"/>

I would expect to be able to make a valid call that produces the following XML:

<Restriction>
  <Exists>
    ...
  </Exists>
</Restriction>

However, when I attempt to make the call using PHP's SoapClient class I receive the following error:

The request failed schema validation: The element 'http://schemas.microsoft.com/exchange/services/2006/types%3ASearchExpression' is abstract or its type is abstract.

If I modify the definition of the RestrictionType type to the follow, the call works:

<xs:element name="Exists" type="t:ExistsType"/>

Is PHP's SOAP handling not able to properly handle abstract types in the WSDL, or could there be something wrong with the WSDL itself? The WSDL is stored locally so I can make edits to it if the need arrises.

Thank you for your help in advance.

Edit:
I just wanted to clarify that I am not forming the XML myself. I am using the following code that should be creating the proper XML:

$request->Restriction->IsGreaterThan->FieldURI->FieldURI =
  'item:DateTimeReceived';
$request->Restriction->IsGreaterThan->FieldURIOrConstant
  ->Constant->Value = date('c', $last_checked_time);
+1  A: 

I found the answer to my own question. Apparently PHP's SOAP object cannot properly form XML from the object structure I am using when there are abstract types. To combat the issue, I edited the WSDL and replaced references to any abstract types with references to the concrete types that extend them. So for the RestrictionType example above, I changed the schema definition to match the following:

<xs:complexType name="RestrictionType"> 
  <xs:choice maxOccurs ="unbounded">
    <xs:element ref="t:Exists"/>
    <xs:element ref="t:Excludes"/>
    <xs:element ref="t:IsEqualTo"/>
    <xs:element ref="t:IsNotEqualTo"/>
    <xs:element ref="t:IsGreaterThan"/>
    <xs:element ref="t:IsGreaterThanOrEqualTo"/>
    <xs:element ref="t:IsLessThan"/>
    <xs:element ref="t:IsLessThanOrEqualTo"/>
    <xs:element ref="t:Not"/>
    <xs:element ref="t:And"/>
    <xs:element ref="t:Or"/>
  </xs:choice>
</xs:complexType>

I hope this helps somebody else out. Thanks to all who took the time to at least read my post.

JamesArmes
A: 

I'm having a very similar problem trying to add additional properties with the FieldURI element. Php's SoapClient is creating the xml as:

<Path FieldURI='folder:DisplayName'>

when it should be creating it as:

<FieldURI FieldURI='folder:DisplayName'>

As a side note, I used wsdl2php to create proxy classes in an attempt to fix the problem, but it did not help. So I'm now wondering if the wsdl exchange returns is wrong, if php's SoapClient is buggy, or if wsdl2php created incorrect proxy classes. If anyone has any insight into this issue, please let us know.

Thanks, Jake Levitt

Jake Levitt
@Jake I ran into this problem as well. I was able to use the solution below to replace any references to Path in types.xsd with the types that extend it. I have been working on a library to make working with Exchange easier as I go along with my current project and I have already added my solution to the library. You may want to have a look to see if it will be useful to you: http://code.google.com/p/php-ews/.
JamesArmes
Thanks man. I actually stumbled upon your library a few days ago but just now realize that you are the author. I decided not to use your library, because I couldn't tell what state of doneness it was in and I was thinking about doing some things slightly differently. However, if you are actively working on it, it may make sense for us to collaborate on it.-Jake Levitt
Jake Levitt
If you are sincere about collaberating, feel free to contact me via the link to the project above.
JamesArmes
A: 

You can use substitutionGroup only with global elements not with types. The same with

<xs:element ref="t:SearchExpression"/>

if you use a ref reference you need a element and not a type!

<xsd:complexType name="PublicationType"/>
<xsd:element name="Publication" abstract="true" type="PublicationType"/>

<xsd:element name="Book" substitutionGroup="Publication" type="BookType"/>
<xsd:element name="Magazine" substitutionGroup="Publication"  type="MagazineType"/>

A other approache is just to use abstract types and XMLSchema-instance (xsi:type) instead and leave the substitutionGroup as you did.

<xsd:complexType name="PublicationType" abstract="true"/>
<xsd:element name="Publication" type="PublicationType"/>

<xsd:element name="Book"type="BookType"/>
<xsd:element name="Magazine" type="MagazineType"/>

<Publication" xsi:type="MagazineType">

This may explain that a bit better as i did. http://www.xfront.com/ExtensibleContentModels.pdf

RedAssBaboon
@RedAssBaboon Your explanation makes sense, but this would require me to form the XML myself.
JamesArmes
If you mean with "form the XML myself" that you need to modify your XML schema, you're right.But, as you are using PHP Soap extension. PHP's SoapClient/Server class will do that for you, if you are using the classmap option! http://de2.php.net/manual/de/soapclient.soapclient.php
RedAssBaboon