PHP SoapClient не обрабатывает абстрактные и substitutionGroup атрибуты в WSDL
Я отправляю вызов в Canada Post, используя их предоставленный wsdl, который содержит раздел вроде этого:
<!-- group-id and transmit-shipment are mutually exclusive -->
<xsd:element name="groupIdOrTransmitShipment" abstract="true" />
<xsd:element name="group-id" type="tns:GroupIDType" substitutionGroup="tns:groupIdOrTransmitShipment"/>
<xsd:element name="transmit-shipment" type="xsd:boolean" fixed="true" substitutionGroup="tns:groupIdOrTransmitShipment"/>
<xsd:complexType name="ShipmentType">
<xsd:all>
<xsd:element ref="tns:groupIdOrTransmitShipment" />
<xsd:element name="quickship-label-requested" type="xsd:boolean" minOccurs="0"/>
<xsd:element name="cpc-pickup-indicator" type="xsd:boolean" fixed="true" minOccurs="0"/>
<xsd:element name="requested-shipping-point" type="tns:PostalCodeType" minOccurs="0"/>
<xsd:element name="shipping-point-id" type="tns:OutletIDType" minOccurs="0" />
<xsd:element name="expected-mailing-date" type="xsd:date" minOccurs="0"/>
<xsd:element name="delivery-spec" type="tns:DeliverySpecType"/>
<xsd:element name="return-spec" type="tns:ReturnSpecType" minOccurs="0"/>
</xsd:all>
</xsd:complexType>
В своем примере кода они расширяют класс Soap и переопределяют метод __doRequest()
Soap следующим образом:
/*
Need to override SoapClient because the abstract element 'groupIdOrTransmitShipment' is expected to be in the request in order for validation to pass.
So, we give it what it expects, but in __doRequest we modify the request by removing the abstract element and add the correct element.
*/
class MySoapClient extends SoapClient {
function __construct($wsdl, $options = null) {
parent::__construct($wsdl, $options);
}
function __doRequest($request, $location, $action, $version, $one_way = NULL) {
$dom = new DOMDocument('1.0');
$dom->loadXML($request);
//get element name and values of group-id or transmit-shipment.
$groupIdOrTransmitShipment = $dom->getElementsByTagName("groupIdOrTransmitShipment")->item(0);
$element = $groupIdOrTransmitShipment->firstChild->firstChild->nodeValue;
$value = $groupIdOrTransmitShipment->firstChild->firstChild->nextSibling->firstChild->nodeValue;
//remove bad element
$newDom = $groupIdOrTransmitShipment->parentNode->removeChild($groupIdOrTransmitShipment);
//append correct element with namespace
$body = $dom->getElementsByTagName("shipment")->item(0);
$newElement = $dom->createElement($element, $value);
$body->appendChild($newElement);
//save $dom to string
$request = $dom->saveXML();
//echo $request;
//doRequest
return parent::__doRequest($request, $location, $action, $version);
}
}
Использование их метода overdes прекрасно работает, поскольку он изменяет запрос xml, но он совершенно запутывает меня , почему они это делают. Есть ли что-то принципиально неправильное в WSDL? Является ли это ошибкой в PHP SoapClient? Я бы хотел, чтобы отправить действительный запрос без переопределения каких-либо методов основного класса.
По моему мнению, автор хочет либо элемент group-id
, либо transmit-shipment
, но не оба или ни один. Поскольку элемент <choice>
внутри элемента <all>
не может иметь значения, в соответствии с это обсуждение по w3c.org, это должно быть чтобы объявить группу замещения для этой цели и включить только один из двух элементов в мой запрос, но если я включаю только transmit-shipment
и опускаю абстрактный элемент groupIdOrTransmitShipment
, php возвращает ошибку:
SOAP-ERROR: Encoding: object has no 'groupIdOrTransmitShipment' property
UPDATE:
Это очень старый, но может ли это быть актуальным? https://bugs.php.net/bug.php?id=48570
Ответы
Ответ 1
Мне пришлось перезаписать и расширить php SoapClass. Это связано с тем, что мыло с php ожидало определенный формат в запросе/ответе, а затем то, что было получено/отправлено. Расширение позволяло мне самостоятельно обрабатывать форматирование.
В wsdl ничего не получается, ошибка является частью класса. Нет пути вокруг переопределения