Как использовать сложный тип, производный от абстрактного сложного типа с использованием php и Soap - PullRequest
0 голосов
/ 29 мая 2020

Недавно я начал работать с SOAP, но мне трудно понять использование абстрактных сложных типов.

Я пытаюсь отправить запрос к wsdl, но все равно получаю сообщение об ошибке. 'Указанный тип является абстрактным: name = "HomeAffairsIDVRequestedBase".

My php выглядит следующим образом:

$result = $this->soap->__soapCall('PlaceRequest',array('PlaceRequest'=>
                                               array('request' =>
                                                   array(
                                                            'type'=> 'tns:HomeAffairsIDVStandardRequest',
                                                            "IsBatchSearch"=>false,
                                                            "ParentRequestId"=>0,
                                                            "Reference"=>'test',
                                                            "Requester"=>'axxess',
                                                            "SessionId"=>'true',
                                                            "IdNumber"=>$this->idNumber
                                                            ))));

, а целевой раздел wsdl выглядит следующим образом

<s:element name="PlaceRequest">
    <s:complexType>
        <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="request" type="tns:HomeAffairsIDVRequestBase"/>
        </s:sequence>
    </s:complexType>
</s:element>
<s:complexType name="HomeAffairsIDVRequestBase" abstract="true">
    <s:sequence>
        <s:element minOccurs="1" maxOccurs="1" name="IsBatchSearch" type="s:boolean"/>
        <s:element minOccurs="1" maxOccurs="1" name="ParentRequestId" nillable="true" type="s:int"/>
        <s:element minOccurs="0" maxOccurs="1" name="Reference" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="Requester" type="s:string"/>
        <s:element minOccurs="1" maxOccurs="1" name="SessionId" nillable="true" type="s1:guid"/>
    </s:sequence>
</s:complexType>
<s:complexType name="HomeAffairsIDVRequest" abstract="true">
    <s:complexContent mixed="false">
        <s:extension base="tns:HomeAffairsIDVRequestBase">
            <s:sequence>
                <s:element minOccurs="0" maxOccurs="1" name="IdNumber" type="s:string"/>
            </s:sequence>
        </s:extension>
    </s:complexContent>
</s:complexType>
<s:complexType name="HomeAffairsIDVStandardRequest">
    <s:complexContent mixed="false">
        <s:extension base="tns:HomeAffairsIDVRequest"/>
    </s:complexContent>
</s:complexType>
<s:complexType name="HomeAffairsIDVAdvancedRequest">
    <s:complexContent mixed="false">
        <s:extension base="tns:HomeAffairsIDVRequest"/>
    </s:complexContent>
</s:complexType>

Примечание: я не могу редактировать wsdl.

1 Ответ

0 голосов
/ 29 мая 2020

Вы можете читать определения сложных типов из wsdl как php определения классов. Каждый сложный тип - это объект значения php. Абстрактные сложные типы - это объект абстрактного значения, от которого можно наследовать.

Поскольку у нас определены сложные типы, мы можем создавать наши php классы.

abstract class HomeAffairsIDVRequestBase 
{
    protected bool $IsBatchSearch;
    protected int $ParentRequestId;
    protected ?string $Reference;
    protected ?string $Requester;
    protected string $SessionId;

    public function getIsBatchSearch(): bool
    {
        return $this->IsBatchSearch;
    }

    public function setIsBatchSearch(bool $isBatchSearch): self
    {
        $this->isBatchSearch = $isBatchSearch;
        return $this;
    }

    public function getParentRequestId(): int
    {
        return $this->ParentRequestId;
    }

    public function setParentRequestId(int $parentRequestId): self
    {
        $this->ParentRequestId = $parentRequestId;
        return $this;
    }

    public function getReference(): ?string
    {
        return $this->Reference;
    }

    public function setReference(string $reference): self
    {
        $this->Reference = $reference;
        return $this;
    }

    public function getRequester(): ?string
    {
        return $this->Requester;
    }

    public function setRequester(string $requester): self
    {
        $this->Requester = $requester;
        return $this;
    }

    public function getSessionId(): string
    {
        return $this->SessionId;
    }

    public function setSessionId(string $sessionId): self
    {
        $this->SessionId = $sessionId;
        return $this;
    }
}

Это наш первый определение абстрактного сложного типа HomeAffairsIDVRequestBase как абстрактного php класса. Как видите, абстрактный класс имеет все свойства, которые определены в файле wsdl для этого сложного типа. Кроме того, у нас есть методы получения и установки для лучшей обработки свойств класса.

Когда мы смотрим на определение для HomeAffairsIDVStandardRequest, мы видим, что оно наследуется от HomeAffairsIDVRequest. Имея это в виду, мы должны написать больше php классов.

abstract class HomeAffairsIDVRequest extends HomeAffairsIDVRequestBase 
{
    protected ?string $IdNumber;

    public function getIdNumber(): ?string
    {
        return $this->IdNumber;
    }

    public function setIdNumber(?string $idNumber): self
    {
        $this->IdNumber = $idNumber;
        return $this;
    }
}

class HomeAffairsIDVStandardRequest extends HomeAffairsIDVRequest
{

}

Поскольку один из сложных типов HomeAffairsIDVStandardRequest и HomeAffairsIDVAdvancedRequest не является абстрактным, w ie может использовать эти классы для запроса. Имейте в виду, что абстрактные классы php не могут быть инициализированы напрямую. То же самое и с абстрактными сложными типами в wsdl.

Теперь нам нужен элемент запроса как класс. Это наш родительский элемент в нашем запросе soap. Элемент PlaceRequest имеет только одно свойство, называемое request. Поскольку этот элемент является наследованием HomeAffairsIDVRequestBase, и это определение является абстрактным, w ie должен использовать атрибут типа позже в запросе.

class PlaceRequest 
{
    protected HomeAffairsIDVRequestBase $request;

    public function getRequest(): HomeAffairsIDVRequestBase
    {
        return $this->request;
    }

    public function setRequest(HomeAffairsIDVRequestBase $request): self
    {
        $this->request = $request;
        return $this;
    }
}

До сих пор наша структура данных PHP ценные объекты. На данный момент это все, что нам нужно. Теперь давайте посмотрим на возможный запрос.

try {
    $wsdl = 'https://path.to.your.wsdl.file.com?wsdl';
    $client = new SoapClient($wsdl, [
        'exceptions' => true,
        'trace' => true,
    ]);

    // initialize our value object
    $standard = (new HomeAffairsIDVStandardRequest())
        ->setIsBatchSearch(false)
        ->setParentRequestId(0)
        ->setReference('test')
        ->setRequester('requester')
        ->setSessionId('true')
        ->setIdNumber($idNumber);

    // initialize our request element
    $request = (new PlaceRequest())
        ->setRequest($standard);

    $response = $client->placeRequest($request);
} catch (SoapFault $fault) {
    // error handling like var_dump($fault)
}

Поскольку я не вижу всего содержимого wsdl, я не могу сказать, как должен выглядеть запрос XML. Может случиться так, что показанное выше приведет к ошибке soap. В этом случае попробуйте следующий пример.

Измените подсказку типа в классе PlaceRequest.

class PlaceRequest 
{
    protected SoapVar $request;

    public function getRequest(): SoapVar
    {
        return $this->request;
    }

    public function setRequest(SoapVar $request): self
    {
        $this->request = $request;
        return $this;
    }
}

После этого создайте новый экземпляр SoapVar с экземпляром $standard.

// we 've already defined the $standard object above (sets an type attribute for the request node)
$standard = new SoapVar($standard, SOAP_ENC_OBJECT, 'HomeAffairsIDVStandardRequest', 'http://your.namespace.tld/namespace', 'request', 'http://your.namespace.tld/namespace');

// initialise the request element and set the soap var parameter
$request = (new PlaceRequest())
    ->setRequest($standard);

// send it via soap client
$client->PlaceRequest($request);

В качестве дополнительной информации вы всегда должны смотреть на отправленное xml и полученное xml, чтобы иметь лучший обзор обработки ошибок. Мы установили параметр trace при инициализации клиента soap. Это позволяет нам увидеть, каковы были последний запрос и последний ответ.

...
} catch (SoapFault $fault) {
    if ($client) {
        // get last request
        var_dump($client->__getLastRequest());

        // get last response
        var_dump($client->__getLastResponse());
    }
}
...