15.01.2012

Связка 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

из описания класса.


По теме: #php #soap #1c .