Doc #78749 [Ver]: No comprehensive documentation on how SoapClient serializes data per the WSDL
| From: | requinix@php.net | Date: | Tue, 05 Nov 2019 19:45:58 +0000 |
| Subject: | Doc #78749 [Ver]: No comprehensive documentation on how SoapClient serializes data per the WSDL | ||
| References: | 1 | Groups: | php.doc.bugs |
| Request: | Send a blank email to doc-bugs+get-17044@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78749&edit=1
ID: 78749
Updated by: requinix@php.net
Reported by: tony at marston-home dot demon dot co dot uk
Summary: No comprehensive documentation on how SoapClient
serializes data per the WSDL
Status: Verified
Type: Documentation Problem
Package: SOAP related
Operating System: Windows 10
PHP Version: 7.3.11
Block user comment: N
Private report: N
New Comment:
> It is a container for any number of <contact> elements,
Not according to the WSDLs. The one in your report very clearly says maxOccurs=1 and the one in your
download says maxOccurs=3.
Currently PHP only really cares if maxOccurs>1 or not. If it is then the value being serialized
is actually a list (ie, array) of values, who each are to be serialized individually. If you have
maxOccurs=1 for an object and pass a list then PHP will complain because the list doesn't have
attributes.
> The idea that the value of maxOccurs need not be validated is nonsense.
In the world of specifications there are two words with two different meanings: "need" and
"should".
The data does not *need* to be validated because the developer is supposed to know what they're
doing, and if they get it wrong then it's not like PHP can automatically recover. The data
*should* be validated because that's A Good Thing To Do.
PHP does not validate right now. *Should* it? Yes, so the developer can be presented with nicer
error messages and, as a more egregious example, not attempt to send invalid data to a service that
the client could have known was invalid. But does it *need* to? No, because when used correctly
ext/soap is perfectly capable of sending data in its current state.
Let me repeat that last sentence to emphasize why I'm making this a doc bug: ext/soap is
perfectly capable of sending data in its current state. When you passed a list of objects where the
WSDL specified one object, the mistake was on you. PHP could have given you a better error message
that more directly indicated the source of the problem, absolutely*, but that doesn't change
how PHP was not able to recover and somehow adapt the data to suit. You, the developer, would have
to go in and fix your code.
Now I really don't want this argument to turn into both of us repeating ourselves until the
other person gives up, so here's what you should do: since ext/soap does not currently attempt
to validate the data against the WSDL in any way, or even have the functionality to do so AFAIK, you
should *request* that validation be *added* so that developers like you and me could make use of it
and benefit from the failure messages it may produce. I would suggest that SoapClient gets a
"validate" (or perhaps "__validate") method that takes a function name and
parameters and validates, and/or that __soapCall() gets an option to opt-into validating before
sending.
* In case this is a source of confusion, I'm saying PHP could give a better message *in
principle*. The cause of your problem is PHP being given a list where it needs an object, but it
isn't discovering anything wrong until it reaches the point where it tries to serialize a
"first_name" property when it was working on an array with keys (0,1,2). With my quick
reading through the source, I don't believe that it *currently* can accurately report some sort
of "expecting object, received list" message at that point in the process - all it knows
there is that the array doesn't have the required key.
Previous Comments:
------------------------------------------------------------------------
[2019-11-05 18:45:24] tony at marston-home dot demon dot co dot uk
I disagree completely with your assessment.
In my WSDL the element <contacts> can occur 0 or 1 times. It is a container for any number of
<contact> elements, and each <contact> contains its own group of elements which can
occur 0 or 1 times each.
The idea that the value of maxOccurs need not be validated is nonsense. The official specification
at http://www.w3.org/TR/xmlschema-0/#OccurrenceConstraints
contains the sentence "The maximum number of times an element may appear is determined by the
value of a maxOccurs attribute in its declaration." To any reasonable person this would mean
that if the WSDL provides a value for maxOccurs then the XML document should checked to ensure that
this limit is not violated.
------------------------------------------------------------------------
[2019-11-05 17:52:19] requinix@php.net
Here's what is happening:
If maxOccurs is 1 then the PHP value should not be a list. Because there's only possibly one.
It doesn't make sense to have a list when there can only be a single entity/value in it. Like
having the title be an array("Title") is weird.
If maxOccurs is unbounded or >1, PHP does not validate against the count. It just doesn't.
If the max is 2 and you give 3 then it will put in all 3 (which you can verify through
__getLastRequest).
So there's two issues here:
1. That behavior is undocumented. I think it's the most important aspect of this report, so
I'm repurposing this as a doc bug.
2. The missing maxOccurs validation. I don't see this as high priority as it doesn't seem
that SoapClient has any particular intention to perform validation beyond what is required to
serialize the data to XML; maxOccurs when >1 isn't being validated, minOccurs when >1
isn't being validated, and there are probably other rules not being validated either.
------------------------------------------------------------------------
[2019-11-05 09:45:02] tony at marston-home dot demon dot co dot uk
That structure is perfectly valid according to the WSDL definition, and it validates using third
party tools such as OxygenXML and SOAPUI.
The XML I supplied contains three occurrences of <contact> and the SOAP Server ->handle()
method deals properly with these when the WSDL specifies maxOccurs of 3 or more.
If I set maxOccurs to 1 the error message is entirely wrong.
If I set maxOccurs to 2 there is no error message complaining that I have exceeded maxOccurs.
It is your validation of the structure which is wrong and not the structure itself.
------------------------------------------------------------------------
[2019-11-04 21:31:18] camporter1 at gmail dot com
It's possible that I'm not understanding the issue properly, but it seems like the issue
here is that 'first_name' is trying to be accessed on the array of 'contact',
which won't map to the type.
Replacing ArrayOfContactInfo with:
<xsd:complexType name="ArrayOfContactInfo">
<complexContent>
<restriction base="SOAP-ENC:Array">
<attribute ref="SOAP-ENC:arrayType" wsdl:arrayType="tns:contact[]"/>
</restriction>
</complexContent>
</xsd:complexType>
and removing the extra 'contact' array:
'contacts' => [
'0' => [
'title' => 'Mr',
'first_name' => 'Joe',
'middle_name' => 'Xavier',
'last_name' => 'Soap',
'contact_role' => 'Account Manager',
'telephone' => '075 40008000'
],
'1' => [
'title' => 'Mrs',
'first_name' => 'Jane',
'last_name' => 'Doe',
'contact_role' => 'Assistant Account Manager',
'telephone' => '075 40008001'
],
'2' => [
'title' => 'Miss',
'first_name' => 'Dee',
'last_name' => 'Meanour',
'contact_role' => 'Deputy Assistant Account Manager',
'telephone' => '075 40008003',
],
],
seems like it might be more in line with the expected behavior?
------------------------------------------------------------------------
[2019-10-25 17:11:24] tony at marston-home dot demon dot co dot uk
I have created a zip file containing the two files necessary to reproduce this fault as it simply
cannot be done in 20 lines of code or less. The WSDL file alone requires over 80 lines. This zip
file is available at:
https://www.tonymarston.net/php-mysql/gmx_soap_bug_report.zip
The 'contact' element in the WSDL file has a 'maxOccurs' attribute which I am
testing by sending 3 occurrences. If I set 'maxOccurs' to 1 it fails with
"SOAP-ERROR: Encoding object has no 'first_name' property" even though the array
does contain a value.
If I set 'maxOccurs' to 2 it does not fail (which it should as I have violated the
maximum) and it also sends all 3 occurrences to the server.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=78749
--
Edit this bug report at https://bugs.php.net/bug.php?id=78749&edit=1