WsdlToPhp / PackageGenerator

Generates a PHP SDK based on a WSDL, simple and powerful, WSDL to PHP
https://providr.io
MIT License
422 stars 73 forks source link

Different Response objects for one xml string if prod request and mock __doRequest of SoapClient #218

Closed 4n70w4 closed 4 years ago

4n70w4 commented 4 years ago

Hi! Help me understand why this magic happens. Perhaps I somehow did the test wrong. But it's confusing that the difference is just wrapping in an array.

php ./wsdltophp-php7.phar --version
WsdlToPhp PackageGenerator 3.2.7

Also i tried 3.2.1 and the same result.

I have response from production:

https://gist.github.com/4n70w4/2acd951e312264b414e721319ee32625

$result = $service->CreateNonActiveSubscriber($request);

json_encode($result):

https://gist.github.com/4n70w4/1d432a52f626d96779d6755936b66e8a

Also i make unit test and mock __doRequest of \SoapClient. But in this case json_encode($result) have differents:

https://gist.github.com/4n70w4/8ace5f896ef557d8e312e56ad1a2082d

In production case $.CreateNonActiveSubscriberResult.ValidationResult.Fields.ModelValidationResult is array of object, but in mock case it is object.

image

My test method:

    public function testCreateNonActiveSubscriber2() {
       $this->expectException(\Exception::class);
       $this->expectExceptionMessage('Данный email example@localhost уже зарегистрирован, укажите другой.');

        // https://gist.github.com/4n70w4/2acd951e312264b414e721319ee32625
        $xml = file_get_contents(__DIR__ . '/CreateNonActiveSubscriber-error2.xml');
        $str = 'app/Integrations/Synerdocs/ExchangeService.xml';

        $soapClient = \Mockery::mock(SoapClient::class, [$str, ['classmap' => ClassMap::get()]])->makePartial();
        $soapClient->shouldReceive('__doRequest')->andReturn($xml);

        $service = \Mockery::mock(Create::class)->makePartial();
        $service->shouldReceive('getSoapClient')->andReturn($soapClient);

        $client = \Mockery::mock(SynerdocsClient::class)->makePartial();
        $client->shouldReceive('getCreateService')->andReturn($service);

        $request = \Mockery::mock(NonActiveSubscriberCreationRequest::class);

        $client->createNonActiveSubscriber('test-token', $request);
    }

I try native \WsdlToPhp\PackageBase\AbstractSoapClientBase and \SoapClient and my own SoapClientBase extends AbstractSoapClientBase and SoapClient extends \SoapClient but the same results. I have no idea what else to try tuning.

https://service.synerdocs.ru/ExchangeService.svc?wsdl

mikaelcom commented 4 years ago

Good question!

Did you try using the second argument of json_encode, JSON_FORCE_OBJECT, to see the output?

Maybe it will help having more clues...

Moreover, I currrently can't tell how the Mockery works and if it affects the results or not...

mikaelcom commented 4 years ago

I just had a flash! You must ensure that the value SOAP_SINGLE_ELEMENT_ARRAYS is defined for the features SoapClient option which is set when using the PackageBase classes, as you can see at https://github.com/WsdlToPhp/PackageBase/blob/develop/src/AbstractSoapClientBase.php#L165. By default with the PackageBase, arrays elements are always returned as an array even if there is only one element in the array in order to preserve consistency.

Be sure it is the case when mocking the SoapClient.

4n70w4 commented 4 years ago

@mikaelcom thanks!

Just need add features option.

$soapClient = \Mockery::mock(SoapClient::class, [$str, ['features' => SOAP_SINGLE_ELEMENT_ARRAYS | SOAP_USE_XSI_ARRAY_TYPE, 'classmap' => ClassMap::get()]])->makePartial();
mikaelcom commented 4 years ago

Great! I let you close the issue then if applicable.