Reputation: 89
I'm discovering soap and after hours trying to find any tutorial on how to simply build a soap request, I come here. I have a soap request to make to a wdsl server. I created the soap object like this :
$option=array('trace'=>1);
$client=new SoapClient('https://distribution-service.e-interforum.com/connecteur-standardise/ConnecteurStandardiseGateway?wsdl',$option);
what I have to achieve is to send a request which is documented this way :
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://cns.connecteur-universel.com/webservices">
<soapenv:Header>
<web:deviceOS></web:deviceOS>
<web:deviceType></web:deviceType>
</soapenv:Header>
<soapenv:Body>
<web:UserRessourcesCatalog>
<input>
<Cle> </Cle>
<Pf> </Pf>
<ENTPersonStructRattachUAI> </ENTPersonStructRattachUAI>
<ENTPersonProfils>National_ELV</ENTPersonProfils>
<EnfantId></EnfantId>
<ENTEleveMEF></ENTEleveMEF>
<ENTEleveCodeEnseignements></ENTEleveCodeEnseignements>
<ENTEleveClasses>classe1</ENTEleveClasses>
<ENTAuxEnsClassesMatieres></ENTAuxEnsClassesMatieres>
<user>eleve1</user>
<ENTAuxEnsGroupes></ENTAuxEnsGroupes>
<ENTEleveGroupes></ENTEleveGroupes>
<ENTAuxEnsClasses></ENTAuxEnsClasses>
<ENTAuxEnsMEF></ENTAuxEnsMEF>
<ENTStructureTypeStruct></ENTStructureTypeStruct>
</input>
</web:UserRessourcesCatalog>
</soapenv:Body>
</soapenv:Envelope>
I got the functions Uses by the wsdl service through __getFunctions and what I get is :
array(2) {
[0]=>
string(81) "UserRessourcesCatalogResponse UserRessourcesCatalog(UserRessourcesCatalog $input)"
[1]=>
string(113) "InitUserRessourcesCatalogResponse InitUserRessourcesCatalog(InitUserRessourcesCatalog $InitUserRessourcesCatalog)"
}
which, as far as I understand, correspond to the body of the given example.
So what I want to know is :
How to I see my soap object before sending it (in this "xml-view") ?
How do I modify the headers to web: (I guess this "envelope" thing is already included in the object) ?
Thanx for your answers !
Upvotes: 2
Views: 2078
Reputation: 5119
soap xml with php is more complex than one can see on the first view. I will try to describe the different steps how to realize a good working php soap client with native php.
Step 1: The WSDL and the XSD Definitions
Before you start coding you have to check if the given wsdl address you became from the provider of the webservice is valid. In most cases it is sufficient to call the WSDL address via a browser. If you display the contents of the WSDL file, your web service will also work. Your given WSDL address https://distribution-service.e-interforum.com/connecteur-standardise/ConnecteurStandardiseGateway?wsdl
is valid.
There is a reference to an XSD file in the WSDL file. You can also call these.
<xsd:schema>
<xsd:import namespace="http://cns.connecteur-universel.com/webservices"
schemaLocation="https://distribution-service.e-interforum.com:443/it-dpf-cs/ConnecteurStandardiseGateway?xsd=1"/>
</xsd:schema>
When you call this address in a browser all defined complex and simple types are shown.
Step 2: Functions and types
With the above given data you can init your php soap client and retrieve all functions and types for it.
try {
$client = new SoapClient($wsdl, [
'cache_wsdl' => WSDL_CACHE_NONE,
'encoding' => 'utf-8',
'exceptions' => true,
'send_errors' => true,
'soap_version' => SOAP_1_1,
'trace' => true,
]);
echo "<pre>";
var_dump($client->__getFunctions(), $client->__getTypes());
echo "</pre>";
} catch (SoapFault $fault) {
echo "<pre>";
var_dump($fault);
echo "</pre>";
}
With the above shown code you 'll retrieve all callable functions of the webservice and the used types in this webservice. The php output is very simple and does not include things like inheritation of complex types. I recommend always looking directly in the xsd definitions, which are mentioned under step 1.
As you stated out we need a complex type UserRessourcesCatalog
for your function UserRessourcesCatalog
. This complex type is described in the xsd as follows.
<xs:complexType name="UserRessourcesCatalog">
<xs:sequence>
<xs:element name="input" type="tns:input2"/>
</xs:sequence>
</xs:complexType>
This shows us, that the complex type UserRessourcesCatalog
can contain one child node called input
. The input
child if of the type input2
which is defined as follows.
<xs:complexType name="input2">
<xs:sequence>
<xs:element name="Cle" type="xs:string"/>
<xs:element name="Pf" type="xs:string"/>
<xs:element name="ENTPersonStructRattachUAI" type="xs:string"/>
<xs:element name="ENTPersonProfils" type="xs:string"/>
<xs:element name="EnfantId" type="xs:string"/>
<xs:element name="ENTEleveMEF" type="xs:string"/>
<xs:element name="ENTEleveCodeEnseignements" type="xs:string"/>
<xs:element name="ENTEleveClasses" type="xs:string"/>
<xs:element name="ENTAuxEnsClassesMatieres" type="xs:string"/>
<xs:element name="user" type="xs:string"/>
<xs:element name="ENTAuxEnsGroupes" type="xs:string"/>
<xs:element name="ENTEleveGroupes" type="xs:string"/>
<xs:element name="ENTAuxEnsClasses" type="xs:string"/>
<xs:element name="ENTAuxEnsMEF" type="xs:string"/>
<xs:element name="ENTStructureTypeStruct" type="xs:string"/>
</xs:sequence>
</xs:complexType>
Looks a bit confusing on the first view. But these definitions are elemental for using our soap client.
Step 3: Using PHP classes for the XML content
With the definitions noted in the xsd and shown above, we can write down our php classes, which we use to define our content we want to send via soap. Such a php class is a so called value object. It containts all the values we want to send and it also copies the xsd complex type.
use SoapVar;
class UserRessourcesCatalouge
{
protected $input;
public function getInput() : ?SoapVar
{
return $this->input;
}
public function setInput(SoapVar $input) : self
{
$this->input = $input;
return $this;
}
}
The same goes for the complex type input2
which we 've found in the xsd file.
class Input2
{
protected $Cle;
protected $Pf;
// list all properties of the complex type here
public function getCle() : ?SoapVar
{
return $this->Cle;
}
public function setCle(SoapVar $cle) : self
{
$this->Cle = $cle;
return $this;
}
public function getPf() : ?SoapVar
{
return $this->Pf;
}
public function setPf(SoapVar $pf)
{
$this->Pf = $pf;
return $this;
}
// implement getter and setter functions for all properties
}
It 's pretty simple. Every php class is a exact copy of the complex type mentioned in the xsd definitions.
Step4: Defining the content of the soap request
As we now know how the name of the function is and which parameters and complex types we have to use with this function, we can put up our request. We use the classes we have written in step 3 and our soap client we have initialized in step 2.
$cle = new SoapVar(
'bla',
XSD_STRING,
'',
'',
'Cle',
'http://cns.connecteur-universel.com/webservices'
);
$pf = new SoapVar(
'blubb',
XSD_STRING,
'',
'',
'Pf',
'http://cns.connecteur-universel.com/webservices'
);
$input = (new Input())
->setCle($cle)
->setPf($pf);
$encodedInput = new SoapVar(
$input,
SOAP_ENC_OBJECT,
'',
'',
'input',
'http://cns.connecteur-universel.com/webservices'
);
$userRecourcesCatalogue = (new UserResourcesCatalogue())
->setInput($encocedInput);
$encodedUserResourcesCatalogue = new SoapVar(
$userRecourcesCatalogue,
SOAP_ENC_OBJECT,
'',
'',
'UserResourcesCatalogue',
'http://cns.connecteur-universel.com/webservices'
);
Now we have set a php object structure which will be given as parameter to the webservice function UserRessourcesCatalog
. You can simple call it as follows.
$result = $client->UserRessourcesCatalog($encodedUserResourcesCatalogue);
If you 've done everything correctly you shoul get a valid response. In this case you 'll result in a soap fault because we have not defined the header data for your soap request.
Step 5: Setting a soap header
It 's pretty simple to set a soap header. It 's nearly the same as defining the request body. PHP has its own soap header class.
$deviceOS = new SoapHeader(
'http://cns.connecteur-universel.com/webservices',
'deviceOS',
'bla'
);
$deviceType = new SoapHeader(
'http://cns.connecteur-universel.com/webservices',
'deviceType',
'bla'
);
$client->__setSoapHeaders([ $deviceOS, $deviceType ]);
$result = $client->UserRessourcesCatalog($encodedUserResourcesCatalogue);
This was very simple and results in the xml content you need. The php soap client now translates your class structure automatically into valid xml and sends it. The result will also be an object structure depending on the return type of the webservice methid. To see, how the xml you 've sent looks like follow the next step.
Step 6: How does my XML look like?
To see what you 've sent and recieved from the webservice it is necessary to initialize the soap client with the enabled trace
option. This allows you to use the native soap client funktions __getLastRequest
and __getLastResponse
. So just place them after you called the webservice method.
$xmlRequest = $client->__getLastRequest();
$xmlResponse = $client->__getLastResponse();
When you output these two variables they containt the xml structure. The response can be empty in case of a soap fault.
Hope that helps a bit.
Upvotes: 3