Необходимые изменения в определении вашего веб-сервиса
Прежде всего, определение необходимого комплексного типа 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>
Это означает, что вы можете отправить все дополнительно. Ваш веб-сервис не знает элемент OrderLine
в контексте PlaceOrder
, поскольку он здесь не определен. Вы должны изменить определение элемента 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
. Как вы можете видеть, все элементы, которые определены в вашем определении веб-сервиса, встречаются как свойства этого класса. Этот класс является точной php реализацией сложного типа PlaceOrder
. Можно сказать, что все сложные типы всегда являются PHP классами. Далее принятыми параметрами метода являются в основном SoapVar
экземпляры. Это важно для клиента soap, потому что это гарантирует правильную структуру xml в конце.
Объект значения OrderLine ...
<?php
namespace Webservice\Entity;
class OrderLine
{
protected $AdditionalCustomerReferenceNumber;
protected $LineID;
protected $OrderedArticle;
protected $PortalReference;
// getters and setters here
}
С этими двумя классами можно сделать полный вызов веб-службы с PHP. Следующий пример не является тестом и показывает, как работать с классом PHP SoapClient
. Класс иногда немного обманчив, и для достижения правильного результата в конце требуется немало работы. Но в основном это то, как это работает.
<code><?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 "
";} catch (SoapFault $ fault) {echo"
";
var_dump($fault);
echo "
";}
Заключение
Ваш веб-сервис очень неточно определен. По этой причине вам следует просто переосмыслить определения параметров и более точно определить их в файле WSDL. Затем он также работает с PHP. PHP использует строго веб-стандарты в своем soap расширении.