Completed
Pull Request — master (#33)
by Robbert van den
03:13 queued 01:49
created

Client::serializeMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 9
cts 9
cp 1
rs 9.8666
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
namespace GoetasWebservices\SoapServices\SoapClient;
4
5
use GoetasWebservices\SoapServices\SoapClient\Arguments\ArgumentsReader;
6
use GoetasWebservices\SoapServices\SoapClient\Arguments\ArgumentsReaderInterface;
7
use GoetasWebservices\SoapServices\SoapClient\Arguments\Headers\Handler\HeaderHandler;
8
use GoetasWebservices\SoapServices\SoapClient\Envelope\SoapEnvelope\Messages\Fault as Fault11;
9
use GoetasWebservices\SoapServices\SoapClient\Envelope\SoapEnvelope12\Messages\Fault as Fault12;
10
use GoetasWebservices\SoapServices\SoapClient\Exception\ClientException;
11
use GoetasWebservices\SoapServices\SoapClient\Exception\ServerException;
12
use GoetasWebservices\SoapServices\SoapClient\Exception\SoapException;
13
use GoetasWebservices\SoapServices\SoapClient\Exception\UnexpectedFormatException;
14
use GoetasWebservices\SoapServices\SoapClient\Result\ResultCreator;
15
use GoetasWebservices\SoapServices\SoapClient\Result\ResultCreatorInterface;
16
use GoetasWebservices\SoapServices\SoapEnvelope;
17
use Http\Client\Exception\HttpException;
18
use Http\Client\HttpClient;
19
use Http\Message\MessageFactory;
20
use JMS\Serializer\SerializationContext;
21
use JMS\Serializer\Serializer;
22
use Psr\Http\Message\RequestInterface;
23
use Psr\Http\Message\ResponseInterface;
24
25
class Client implements ClientInterface
26
{
27
    /**
28
     * @var Serializer
29
     */
30
    protected $serializer;
31
    /**
32
     * @var array
33
     */
34
    protected $serviceDefinition;
35
    /**
36
     * @var HttpClient
37
     */
38
    protected $client;
39
40
    /**
41
     * @var MessageFactory
42
     */
43
    protected $messageFactory;
44
45
    /**
46
     * @var ResultCreatorInterface
47
     */
48
    protected $resultCreator;
49
50
    /**
51
     * @var ArgumentsReaderInterface
52
     */
53
    protected $argumentsReader;
54
55
    /**
56
     * @var RequestInterface
57
     */
58
    private $requestMessage;
59
    /**
60
     * @var ResponseInterface
61
     */
62
    private $responseMessage;
63
64 36
    public function __construct(array $serviceDefinition, Serializer $serializer, MessageFactory $messageFactory, HttpClient $client, HeaderHandler $headerHandler)
65
    {
66 36
        $this->serviceDefinition = $serviceDefinition;
67 36
        $this->serializer = $serializer;
68 36
        $this->client = $client;
69 36
        $this->messageFactory = $messageFactory;
70 36
        $this->argumentsReader = new ArgumentsReader($this->serializer, $headerHandler);
71 36
        $this->resultCreator = new ResultCreator($this->serializer, !empty($serviceDefinition['unwrap']));
72 36
    }
73
74 34
    public function __call($functionName, array $args)
75
    {
76 34
        $soapOperation = $this->findOperation($functionName, $this->serviceDefinition);
77
78 34
        $request = $this->buildRequest($args, $soapOperation);
79
80
        try {
81 34
            $response = $this->sendRequest($request);
82 24
            $response = $this->handleResponse($response, $soapOperation, $request);
83 34
        } catch (HttpException $e) {
84 10
            $response = $e->getResponse();
85 10
            if (strpos($response->getHeaderLine('Content-Type'), 'xml') !== false) {
86 6
                $this->handleFaultIfPresent($response, $e->getRequest(), $e);
87
            } else {
88 4
                throw new ServerException($response, $e->getRequest(), $e);
89
            }
90
        }
91 21
        return $this->resultCreator->prepareResult($response, $soapOperation['output']);
92
    }
93
94
    /**
95
     * @return RequestInterface|null
96
     */
97 2
    public function __getLastRequestMessage()
98
    {
99 2
        return $this->requestMessage;
100
    }
101
    /**
102
     * @return ResponseInterface|null
103
     */
104 2
    public function __getLastResponseMessage()
105
    {
106 2
        return $this->responseMessage;
107
    }
108
109 24
    public function findFaultClass(ResponseInterface $response)
110
    {
111 24
        if (strpos($response->getHeaderLine('Content-Type'), 'application/soap+xml') !== false) {
112 13
            return Fault12::class;
113
        } else {
114 12
            return Fault11::class;
115
        }
116
    }
117
118 34
    protected function buildHeaders(array $operation)
119
    {
120
        return [
121 34
            'Content-Type' => isset($operation['version']) && $operation['version'] === '1.2'
122 34
                ? 'application/soap+xml; charset=utf-8'
123 34
                : 'text/xml; charset=utf-8',
124 34
            'SoapAction' => '"' . $operation['action'] . '"',
125 34
        ];
126
    }
127
128 34
    protected function findOperation($functionName, array $serviceDefinition)
129
    {
130 34
        if (isset($serviceDefinition['operations'][$functionName])) {
131 33
            return $serviceDefinition['operations'][$functionName];
132
        }
133
134 1
        foreach ($serviceDefinition['operations'] as $operation) {
135 1
            if (strtolower($functionName) == strtolower($operation['method'])) {
136 1
                return $operation;
137
            }
138
        }
139
        throw new ClientException("Can not find an operation to run $functionName service call");
140
    }
141
142 24
    protected function handleFaultIfPresent(ResponseInterface $response, RequestInterface $request, HttpException $e = null)
143
    {
144 24
        $faultClass = $this->findFaultClass($response);
145 24
        $body = (string) $response->getBody();
146
147 24
        if ((strpos($body, ':Fault>') !== false) || (null !== $e)) { // some server returns a fault with 200 OK HTTP
148 7
            $fault = $this->serializer->deserialize($body, $faultClass, 'xml');
149 7
            throw $fault->createException($response, $request, $e);
150
        }
151 17
    }
152
153 34
    protected function buildRequest(array $args, $soapOperation)
154
    {
155 34
        $message = $this->argumentsReader->readArguments($args, $soapOperation['input']);
156 34
        $xmlMessage = $this->serializeMessage($soapOperation, $message);
157 34
        $headers = $this->buildHeaders($soapOperation);
158
159 34
        $this->requestMessage = $request = $this->messageFactory->createRequest('POST', $this->serviceDefinition['endpoint'], $headers, $xmlMessage);
160
161 34
        return $request;
162
    }
163
164
    /**
165
     * @param $soapOperation
166
     * @param $message
167
     * @return string
168
     */
169 34
    protected function serializeMessage($soapOperation, $message)
170
    {
171 34
        $xmlMessage = $this->serializer->serialize(
172 34
            $message,
173 34
            'xml',
174 34
            (new SerializationContext())
175 34
                ->setAttribute('soapAction', $soapOperation['action'])
176 34
                ->setAttribute('soapEndpoint', $this->serviceDefinition['endpoint'])
177 34
        );
178
179 34
        return $xmlMessage;
180
    }
181
182
    /**
183
     * @param $body
184
     * @param $soapOperation
185
     * @return array|\JMS\Serializer\scalar|mixed|object
186
     */
187 17
    protected function deserializeResponse($body, $soapOperation)
188
    {
189 17
        $response = $this->serializer->deserialize($body, $soapOperation['output']['message_fqcn'], 'xml');
190
191 17
        return $response;
192
    }
193
194
    /**
195
     * @param $body
196
     * @param $soapOperation
197
     * @return array|\JMS\Serializer\scalar|mixed|object
198
     */
199 24
    protected function handleResponse(ResponseInterface $response, $soapOperation, RequestInterface $request)
200
    {
201 24
        if (strpos($response->getHeaderLine('Content-Type'), 'xml') === false) {
202 2
            throw new UnexpectedFormatException(
203 2
                $response,
204 2
                $request,
205 2
                "Unexpected content type '" . $response->getHeaderLine('Content-Type') . "'"
206 2
            );
207
        }
208
209
        // fast return if no return is expected
210 22
        if (!count($soapOperation['output']['parts'])) {
211 4
            return null;
212
        }
213
214 18
        $body = (string)$response->getBody();
215 18
        $this->handleFaultIfPresent($response, $request);
216 17
        $response = $this->deserializeResponse($body, $soapOperation);
217
218 17
        return $response;
219
    }
220
221
    /**
222
     * @param $request
223
     * @return ResponseInterface
224
     */
225 34
    protected function sendRequest($request)
226
    {
227 34
        $this->responseMessage = $response = $this->client->sendRequest($request);
228
229 24
        return $response;
230
    }
231
}
232