您的网络服务定义中的必要更改
首先,必要的复杂类型PlaceOrder 的定义没有提到tns:OrderLine 类型的元素。我想你必须改变元素的定义。因为您的网络服务定义非常松散,所以它的工作方式就像您在问题中显示的那样。
这是PlaceOrder 请求的当前定义。这表示,PlaceOrder 元素作为请求参数是必需的。
<wsdl:message name="IService_PlaceOrder_InputMessage">
<wsdl:part name="parameters" element="tns:PlaceOrder"/>
</wsdl:message>
PlaceOrder 复杂类型的当前定义表明,没有 OrderLine 元素。
<xs:element name="PlaceOrder">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="userToken" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="ediOrder" nillable="true" type="q1:order"/>
</xs:sequence>
</xs:complexType>
</xs:element>
这意味着您可以另外发送所有内容。您的 web 服务不知道 PlaceOrder 上下文中的 OrderLine 元素,因为它没有在此处定义。您必须将PlaceOrder 元素的定义更改为以下符号。
<xs:element name="PlaceOrder">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="userToken" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="ediOrder" nillable="true" type="q1:order"/>
<xs:element minOccurs="0" name="OrderLine" nillable="true" type="q1:ArrayOfOrderLine"/>
</xs:sequence>
</xs:complexType>
</xs:element>
ArrayOfOrderLine的定义如下:
<xs:complexType name="ArrayOfOrderLine">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="OrderLine" nillable="true" type="tns:OrderLine"/>
</xs:sequence>
</xs:complexType>
这个定义说,你想要有一个父节点OrderLine 的OrderLine 复杂类型。所以父节点完全按照您的 wsdl 文件中的定义出现。要省略父节点,您必须重新定义 PlaceOrder 复杂类型,如下所示:
<xs:element name="PlaceOrder">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="userToken" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="ediOrder" nillable="true" type="q1:order"/>
<xs:element minOccurs="0" maxOccurs="unbounded" name="OrderLine" nillable="true" type="tns:OrderLine"/>
</xs:sequence>
</xs:complexType>
</xs:element>
这个新定义表明“OrderLine”元素不能命名或可以多次命名。本例中的父节点为PlaceOrder。
一个可能的 PHP 示例
Soap 遵循严格的面向对象的方法。基于这种理解,您还必须使用 PHP 中的对象。首先,您需要基于 xsd/wsdl 定义的值对象(有时称为实体)。请记住,此示例使用重新定义的 PlaceOrder 定义。
<?php
namespace Webservice\Entity;
use ArrayObject;
use SoapVar;
class PlaceOrder
{
protected $userToken;
protected $ediOrder;
protected $OrderLine;
public function __construct()
{
$this->OrderLine = new ArrayObject();
}
public function getUserToken(): ?SoapVar
{
return $this->userToken;
}
public function setUserToken(SoapVar $userToken): self
{
$this->userToken = $userToken;
return $this;
}
public function getEdiOrder() : ?SoapVar
{
return $this->ediOrder;
}
public function setEdiOrder(SoapVar $ediOrder): self
{
$this->ediOrder = $ediOrder;
return $this;
}
public function getOrderLine(): ArrayObject
{
return $this->OrderLine;
}
public function attachOrderLine(SoapVar $orderLine): self
{
$this->orderLine->append($orderLine);
return $this;
}
public function setOrderLine(ArrayObject $orderLine): self
{
$this->OrderLine = $orderLine;
return $this;
}
}
上面显示的 PHP 代码显示了 PlaceOrder 值对象。如您所见,在您的 Web 服务定义中定义的所有元素都作为此类的属性出现。此类是PlaceOrder 复杂类型的精确php 实现。您可以说所有复杂类型始终是 PHP 类。此外,接受的方法参数主要是SoapVar 实例。这对于soap客户端很重要,因为这保证了最后正确的xml结构。
OrderLine 值对象 ...
<?php
namespace Webservice\Entity;
class OrderLine
{
protected $AdditionalCustomerReferenceNumber;
protected $LineID;
protected $OrderedArticle;
protected $PortalReference;
// getters and setters here
}
通过这两个类,可以使用 PHP 进行完整的 Web 服务调用。以下示例不是 testet,它显示了如何使用 PHP SoapClient 类。这门课有时有点欺骗性,最后需要一些工作才能得到正确的结果。但主要是这就是它的工作方式。
<?php
namespace Wesbervice;
use Webservice\Entity\Order;
use Webservice\Entity\OrderLine;
use Webservice\Entity\PlaceOrder;
use SoapFault;
use SoapVar;
try {
// this url contains the wrong defined PlaceOrder complex type
$wsdl = 'https://uat-salesapi.ndias.com/service.svc?singlewsdl&version=27';
$client = new SoapClient($wsdl, [
'cache_wsdl' => WSDL_CACHE_NONE, // as long as you work on your wsdl
'encoding' => 'utf-8',
'exceptions' => true,
'soap_version' => SOAP_1_1,
'trace' => true, // enables tracing and __getLastRequest() / __getLastResponse()
'classmap' => [
'order' => Order::class,
'OrderLine' => OrderLine::class,
'PlaceOrder' => PlaceOrder::class,
],
]);
// user token
$usertoken = new SoapVar('bla', XSD_STRING, '', '', 'userToken', 'http://tempuri.org/');
// edi order
$order = (new Order())
->setBlanketOrderReference(new SoapVar(...))
->setBuyerParty(new SoapVar(...);
$order = new SoapVar($order, SOAP_ENC_OBJECT, '', '', 'ediOrder', 'http://tempuri.org/');
// compile our request parameter
$parameter = (new PlaceOrder())
->setUserToken($usertoken)
->setEdiOrder($order);
// order list objects
$orderLine1 = (new OrderLine())
->setAdditionalCustomerReferenceNumber(new SoapVar(...))
->setLineID(new SoapVar(...));
$orderLine1 = new SoapVar($orderLine1, SOAP_ENC_OBJECT, '', '', 'OrderLine', 'http://tempuri.org/');
$parameter->attachOrderLine($orderLine1);
$orderLine2 = (new OrderLine())
->setAdditionalCustomerReferenceNumber(new SoapVar(...))
->setLineID(new SoapVar(...));
$orderLine2 = new SoapVar($orderLine2, SOAP_ENC_OBJECT, '', '', 'OrderLine', 'http://tempuri.org/');
$parameter->attachOrderLine($orderLine2);
$parameter = new SoapVar($parameter, SOAP_ENC_OBJECT, '', '', 'PlaceOrder', 'http://tempuri.org/');
// the client knows the PlaceOrder method from the wsdl
$result = $client->PlaceOrder($parameter);
// the result is a stdClass structure, als long as the classmap parameter does not contain definitions of type to php entity classes
echo "<pre>";
var_dump($result);
echo "</pre>";
} catch (SoapFault $fault) {
echo "<pre>";
var_dump($fault);
echo "</pre>";
}
结论
您的网络服务定义非常不精确。出于这个原因,您应该简单地重新考虑参数的定义,并在 WSDL 文件中更准确地定义它们。然后它也适用于 PHP。 PHP 在其 soap 扩展中使用严格的 Web 标准。