Связка PHP с 1С по SOAP протоколу. Подводные камни.
Небольшие заметки о подводных камнях, которые могут испортить жизнь при написании шлюза по протоколу SOAP между веб-сервисом на PHP и 1С. Здесь отражается только взгляд со стороны php-программиста.
Binding Style
Стиль сообщения может быть как rpc так и document. 1C умеет работать и с тем и с другим. Я остановился на rpc, так как его использование в PHP не требует дополнительного оборачивания ответов методов API в объект. При этом формат сериализации я выбрал literal, т.к. через encode нельзя передать вложенные друг в друга списки.
<binding name="MyAPIClassBinding" type="tns:MyAPIClassPort">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="MyAPIMethod">
<soap:operation
soapAction="http://mydomen.ru/MyAPIClass#MyAPIMethod"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
Zend_Soap_AutoDiscover
Если для генерации wsdl используется Zend_Soap_AutoDiscover, то для создания wsdl, которую потом сможет использовать 1С, необходим следующий код:
$autodiscover = new Zend_Soap_AutoDiscover();
$autodiscover->setOperationBodyStyle(
array(
'use' => 'literal'
)
);
$autodiscover->setBindingStyle(
array(
'style' => 'rpc'
)
);
$autodiscover->setClass('MyAPIClass');
$autodiscover->handle();
Zend_Soap_Wsdl_Strategy_DefaultComplexType
Для того, чтобы с помощью Zend_Soap_AutoDiscover возможно было генерировать wsdl не только с простыми типами данных, но и со сложными, необходима расширенная версия класса Zend_Soap_Wsdl_Strategy_DefaultComplexType. По ссылке есть не только сам класс, но и описание, как его использовать. Но для создания wsdl для 1C надо учесть такой момент, что при использовании комплексного типа данных инструкция советует сделать следующий класс:
/**
* @xsd sequence
*/
class wsGetUserInfosResult
{
/**
* @xsd sequence start
* @var string
*/
public $firstName;
/**
* @var string
*/
public $familyName;
/**
* @var AgeType
*/
public $age;
/**
* @var detailsBrotherList
* @xsd sequence end
*/
public $detailsBrotherList;
/**
* @param string $firstName
* @param string $familyName
* @param integer $age
* @param detailsBrotherList $detailsBrotherList
* @return wsGetUserInfosResult
*/
public function __construct($firstName, $familyName, $age, $detailsBrotherList) {
$this->firstName = $firstName;
$this->familyName = $familyName;
$this->age = $age;
$this->detailsBrotherList = $detailsBrotherList;
return $this;
}
}
Который при автогенерации создат вот такой кусок wsdl:
<xsd:complexType name="wsGetUserInfosResult">
<xsd:sequence>
<xsd:sequence>
<xsd:element name="firstName" type="xsd:string"/>
<xsd:element name="familyName" type="xsd:string"/>
<xsd:element name="age" type="tns:AgeType"/>
<xsd:element ref="tns:detailsBrotherList"/>
</xsd:sequence>
</xsd:sequence>
</xsd:complexType>
И вот 1С не сможет обработать этот wsdl и при работе выдаст ошибку: “Ошибка проверки данных XDTO: Структура объекта не соответствует типу.”
Чтобы избежать этого необходимо убрать
@xsd sequence start
и
@xsd sequence end
из описания класса.
4 месяца назад - обсудить...