|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* amadeus-ws-client |
|
4
|
|
|
* |
|
5
|
|
|
* Copyright 2015 Amadeus Benelux NV |
|
6
|
|
|
* |
|
7
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
8
|
|
|
* you may not use this file except in compliance with the License. |
|
9
|
|
|
* You may obtain a copy of the License at |
|
10
|
|
|
* |
|
11
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
12
|
|
|
* |
|
13
|
|
|
* Unless required by applicable law or agreed to in writing, software |
|
14
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
15
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
16
|
|
|
* See the License for the specific language governing permissions and |
|
17
|
|
|
* limitations under the License. |
|
18
|
|
|
* |
|
19
|
|
|
* @package Amadeus |
|
20
|
|
|
* @license https://opensource.org/licenses/Apache-2.0 Apache 2.0 |
|
21
|
|
|
*/ |
|
22
|
|
|
|
|
23
|
|
|
namespace Amadeus\Client\Session\Handler; |
|
24
|
|
|
|
|
25
|
|
|
use Amadeus\Client; |
|
26
|
|
|
use Amadeus\Client\Struct\BaseWsMessage; |
|
27
|
|
|
use Amadeus\Client\Params\SessionHandlerParams; |
|
28
|
|
|
use Psr\Log\LoggerAwareInterface; |
|
29
|
|
|
use Psr\Log\LoggerAwareTrait; |
|
30
|
|
|
use Psr\Log\LoggerInterface; |
|
31
|
|
|
use Psr\Log\LogLevel; |
|
32
|
|
|
use Psr\Log\NullLogger; |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Base Session Handler |
|
36
|
|
|
* |
|
37
|
|
|
* Session handler will manage everything related to the session with the Amadeus Web Services server: |
|
38
|
|
|
* - be configurable to handle different versions of authentication mechanisms depending on the WSDL received |
|
39
|
|
|
* - decide if a separate authentication message is needed and if so, send it |
|
40
|
|
|
* |
|
41
|
|
|
* @package Amadeus\Client\Session\Handler |
|
42
|
|
|
* @author Dieter Devlieghere <[email protected]> |
|
43
|
|
|
*/ |
|
44
|
|
|
abstract class Base implements HandlerInterface, LoggerAwareInterface |
|
45
|
|
|
{ |
|
46
|
|
|
use LoggerAwareTrait; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* Status variable to know wether the given session is in a certain context. |
|
50
|
|
|
* |
|
51
|
|
|
* @todo implement this feature - currently the application using the client must know the context itself. |
|
52
|
|
|
* @var bool |
|
53
|
|
|
*/ |
|
54
|
|
|
protected $hasContext = false; |
|
55
|
|
|
|
|
56
|
|
|
/** |
|
57
|
|
|
* The context of the currently active session |
|
58
|
|
|
* |
|
59
|
|
|
* @todo implement this feature - currently the application using the client must know the context itself. |
|
60
|
|
|
* @var mixed |
|
61
|
|
|
*/ |
|
62
|
|
|
protected $context; |
|
63
|
|
|
|
|
64
|
|
|
/** |
|
65
|
|
|
* Session information: |
|
66
|
|
|
* - session ID |
|
67
|
|
|
* - sequence number |
|
68
|
|
|
* - security Token |
|
69
|
|
|
* |
|
70
|
|
|
* @var array |
|
71
|
|
|
*/ |
|
72
|
|
|
protected $sessionData = [ |
|
73
|
|
|
'sessionId' => null, |
|
74
|
|
|
'sequenceNumber' => null, |
|
75
|
|
|
'securityToken' => null |
|
76
|
|
|
]; |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* Status variable to know if the session is currently logged in |
|
80
|
|
|
* |
|
81
|
|
|
* @var bool |
|
82
|
|
|
*/ |
|
83
|
|
|
protected $isAuthenticated = false; |
|
84
|
|
|
|
|
85
|
|
|
/** |
|
86
|
|
|
* @var array[string]\SoapClient |
|
87
|
|
|
*/ |
|
88
|
|
|
protected $soapClients = []; |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Default SoapClient options used during initialisation |
|
92
|
|
|
* |
|
93
|
|
|
* Can be overridden by providing custom options in |
|
94
|
|
|
* Amadeus\Client\Params\SessionHandlerParams::$soapClientOptions |
|
95
|
|
|
* |
|
96
|
|
|
* @var array |
|
97
|
|
|
*/ |
|
98
|
|
|
protected $soapClientOptions = [ |
|
99
|
|
|
'trace' => 1, |
|
100
|
|
|
'exceptions' => 1, |
|
101
|
|
|
'soap_version' => SOAP_1_1 |
|
102
|
|
|
]; |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* @var SessionHandlerParams |
|
106
|
|
|
*/ |
|
107
|
|
|
protected $params; |
|
108
|
|
|
|
|
109
|
|
|
/** |
|
110
|
|
|
* A map of which messages are available in the provided WSDL's |
|
111
|
|
|
* |
|
112
|
|
|
* format: |
|
113
|
|
|
* [ |
|
114
|
|
|
* 'PNR_Retrieve' => [ |
|
115
|
|
|
* 'version' => '14.1', |
|
116
|
|
|
* 'wsdl' => '7d36c7b8' |
|
117
|
|
|
* ], |
|
118
|
|
|
* 'Media_GetMedia' => [ |
|
119
|
|
|
* 'version' => '14.1', |
|
120
|
|
|
* 'wsdl' => '7e84f2537' |
|
121
|
|
|
* ] |
|
122
|
|
|
* ] |
|
123
|
|
|
* |
|
124
|
|
|
* @var array |
|
125
|
|
|
*/ |
|
126
|
|
|
protected $messagesAndVersions = []; |
|
127
|
|
|
|
|
128
|
|
|
/** |
|
129
|
|
|
* @var Client\Util\MsgBodyExtractor |
|
130
|
|
|
*/ |
|
131
|
|
|
protected $extractor; |
|
132
|
|
|
|
|
133
|
|
|
/** |
|
134
|
|
|
* Get the session parameters of the active session |
|
135
|
|
|
* |
|
136
|
|
|
* @return array|null |
|
137
|
|
|
*/ |
|
138
|
|
|
public function getSessionData() |
|
139
|
|
|
{ |
|
140
|
|
|
return $this->sessionData; |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
/** |
|
144
|
|
|
* Set the session data to continue a previously started session. |
|
145
|
|
|
* |
|
146
|
|
|
* @param array $sessionData |
|
147
|
|
|
* @return bool |
|
148
|
|
|
*/ |
|
149
|
|
|
public function setSessionData(array $sessionData) |
|
150
|
|
|
{ |
|
151
|
|
|
if (isset($sessionData['sessionId'], $sessionData['sequenceNumber'], $sessionData['securityToken'])) { |
|
152
|
|
|
$this->sessionData['sessionId'] = $sessionData['sessionId']; |
|
153
|
|
|
$this->sessionData['sequenceNumber'] = $sessionData['sequenceNumber']; |
|
154
|
|
|
$this->sessionData['securityToken'] = $sessionData['securityToken']; |
|
155
|
|
|
$this->isAuthenticated = true; |
|
156
|
|
|
} else { |
|
157
|
|
|
$this->isAuthenticated = false; |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
return $this->isAuthenticated; |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* @param SessionHandlerParams $params |
|
166
|
|
|
*/ |
|
167
|
|
|
public function __construct(SessionHandlerParams $params) |
|
168
|
|
|
{ |
|
169
|
|
|
$this->params = $params; |
|
170
|
|
|
if ($params->logger instanceof LoggerInterface) { |
|
171
|
|
|
$this->setLogger($params->logger); |
|
172
|
|
|
$this->log(LogLevel::INFO, __METHOD__."(): Logger started."); |
|
173
|
|
|
} |
|
174
|
|
|
if ($params->overrideSoapClient instanceof \SoapClient) { |
|
175
|
|
|
$this->soapClients[$params->overrideSoapClientWsdlName] = $params->overrideSoapClient; |
|
176
|
|
|
} |
|
177
|
|
|
$this->setStateful($params->stateful); |
|
178
|
|
|
$this->setTransactionFlowLink($params->enableTransactionFlowLink); |
|
179
|
|
|
$this->setConsumerId($params->consumerId); |
|
180
|
|
|
$this->extractor = new Client\Util\MsgBodyExtractor(); |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* @param string $messageName Method Operation name as defined in the WSDL. |
|
186
|
|
|
* @param BaseWsMessage $messageBody |
|
187
|
|
|
* @param array $messageOptions options: bool 'asString', bool 'endSession' |
|
188
|
|
|
* @return SendResult |
|
189
|
|
|
* @throws \InvalidArgumentException |
|
190
|
|
|
* @throws Client\Exception |
|
191
|
|
|
* @throws \SoapFault |
|
192
|
|
|
*/ |
|
193
|
|
|
public function sendMessage($messageName, Client\Struct\BaseWsMessage $messageBody, $messageOptions = []) |
|
194
|
|
|
{ |
|
195
|
|
|
$result = new SendResult( |
|
196
|
|
|
$this->getActiveVersionFor($messageName) |
|
197
|
|
|
); |
|
198
|
|
|
|
|
199
|
|
|
$this->prepareForNextMessage($messageName, $messageOptions); |
|
200
|
|
|
|
|
201
|
|
|
try { |
|
202
|
|
|
$result->responseObject = $this->getSoapClient($messageName)->$messageName($messageBody); |
|
203
|
|
|
|
|
204
|
|
|
$this->logRequestAndResponse($messageName); |
|
205
|
|
|
|
|
206
|
|
|
$this->handlePostMessage($messageName, $this->getLastResponse($messageName), $messageOptions, $result); |
|
207
|
|
|
} catch (\SoapFault $ex) { |
|
208
|
|
|
$this->log( |
|
209
|
|
|
LogLevel::ERROR, |
|
210
|
|
|
"SOAPFAULT while sending message ".$messageName.": ".$ex->getMessage(). |
|
211
|
|
|
" code: ".$ex->getCode()." at ".$ex->getFile()." line ".$ex->getLine(). |
|
212
|
|
|
": \n".$ex->getTraceAsString() |
|
213
|
|
|
); |
|
214
|
|
|
$this->logRequestAndResponse($messageName); |
|
215
|
|
|
$result->exception = $ex; |
|
216
|
|
|
} catch (\Exception $ex) { |
|
217
|
|
|
// We should only come here when the XSL extension is not enabled |
|
218
|
|
|
// or the XSLT transformation file is unreadable |
|
219
|
|
|
$this->log( |
|
220
|
|
|
LogLevel::ERROR, |
|
221
|
|
|
"EXCEPTION while sending message ".$messageName.": ".$ex->getMessage(). |
|
222
|
|
|
" at ".$ex->getFile()." line ".$ex->getLine().": \n".$ex->getTraceAsString() |
|
223
|
|
|
); |
|
224
|
|
|
$this->logRequestAndResponse($messageName); |
|
225
|
|
|
throw new Client\Exception($ex->getMessage(), $ex->getCode(), $ex); |
|
226
|
|
|
} |
|
227
|
|
|
|
|
228
|
|
|
$result->responseXml = $this->extractor->extract($this->getLastResponse($messageName)); |
|
|
|
|
|
|
229
|
|
|
|
|
230
|
|
|
return $result; |
|
231
|
|
|
} |
|
232
|
|
|
|
|
233
|
|
|
/** |
|
234
|
|
|
* Prepare to send a next message and checks if authenticated |
|
235
|
|
|
* |
|
236
|
|
|
* @param string $messageName |
|
237
|
|
|
* @param array $messageOptions |
|
238
|
|
|
*/ |
|
239
|
|
|
abstract protected function prepareForNextMessage($messageName, $messageOptions); |
|
240
|
|
|
|
|
241
|
|
|
/** |
|
242
|
|
|
* Handles post message actions |
|
243
|
|
|
* |
|
244
|
|
|
* Handles session state based on received response |
|
245
|
|
|
* |
|
246
|
|
|
* @param string $messageName |
|
247
|
|
|
* @param string $lastResponse |
|
248
|
|
|
* @param array $messageOptions |
|
249
|
|
|
* @param mixed $result |
|
250
|
|
|
*/ |
|
251
|
|
|
abstract protected function handlePostMessage($messageName, $lastResponse, $messageOptions, $result); |
|
252
|
|
|
|
|
253
|
|
|
/** |
|
254
|
|
|
* Get the last raw XML message that was sent out |
|
255
|
|
|
* |
|
256
|
|
|
* @param string $msgName |
|
257
|
|
|
* @return string|null |
|
258
|
|
|
*/ |
|
259
|
|
|
public function getLastRequest($msgName) |
|
260
|
|
|
{ |
|
261
|
|
|
return $this->executeMethodOnSoapClientForMsg( |
|
262
|
|
|
$msgName, |
|
263
|
|
|
'__getLastRequest' |
|
264
|
|
|
); |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
/** |
|
268
|
|
|
* Get the last raw XML message that was received |
|
269
|
|
|
* |
|
270
|
|
|
* @param string $msgName |
|
271
|
|
|
* @return string|null |
|
272
|
|
|
*/ |
|
273
|
|
|
public function getLastResponse($msgName) |
|
274
|
|
|
{ |
|
275
|
|
|
return $this->executeMethodOnSoapClientForMsg( |
|
276
|
|
|
$msgName, |
|
277
|
|
|
'__getLastResponse' |
|
278
|
|
|
); |
|
279
|
|
|
} |
|
280
|
|
|
|
|
281
|
|
|
/** |
|
282
|
|
|
* Get the request headers for the last SOAP message that was sent out |
|
283
|
|
|
* |
|
284
|
|
|
* @param string $msgName |
|
285
|
|
|
* @return string|null |
|
286
|
|
|
*/ |
|
287
|
|
|
public function getLastRequestHeaders($msgName) |
|
288
|
|
|
{ |
|
289
|
|
|
return $this->executeMethodOnSoapClientForMsg( |
|
290
|
|
|
$msgName, |
|
291
|
|
|
'__getLastRequestHeaders' |
|
292
|
|
|
); |
|
293
|
|
|
} |
|
294
|
|
|
|
|
295
|
|
|
/** |
|
296
|
|
|
* Get the response headers for the last SOAP message that was received |
|
297
|
|
|
* |
|
298
|
|
|
* @param string $msgName |
|
299
|
|
|
* @return string|null |
|
300
|
|
|
*/ |
|
301
|
|
|
public function getLastResponseHeaders($msgName) |
|
302
|
|
|
{ |
|
303
|
|
|
return $this->executeMethodOnSoapClientForMsg( |
|
304
|
|
|
$msgName, |
|
305
|
|
|
'__getLastResponseHeaders' |
|
306
|
|
|
); |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
/** |
|
310
|
|
|
* Get the office that we are using to sign in to. |
|
311
|
|
|
* |
|
312
|
|
|
* @return string |
|
313
|
|
|
*/ |
|
314
|
|
|
public function getOriginatorOffice() |
|
315
|
|
|
{ |
|
316
|
|
|
return $this->params->authParams->officeId; |
|
317
|
|
|
} |
|
318
|
|
|
|
|
319
|
|
|
/** |
|
320
|
|
|
* Extract the Messages and versions from the loaded WSDL file. |
|
321
|
|
|
* |
|
322
|
|
|
* Result is an associative array: keys are message names, values are versions. |
|
323
|
|
|
* |
|
324
|
|
|
* @return array |
|
325
|
|
|
*/ |
|
326
|
|
|
public function getMessagesAndVersions() |
|
327
|
|
|
{ |
|
328
|
|
|
if (empty($this->messagesAndVersions)) { |
|
329
|
|
|
$this->messagesAndVersions = WsdlAnalyser::loadMessagesAndVersions($this->params->wsdl); |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
return $this->messagesAndVersions; |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* Get the version number active in the WSDL for the given message |
|
337
|
|
|
* |
|
338
|
|
|
* @param $messageName |
|
339
|
|
|
* @return float|string|null |
|
340
|
|
|
*/ |
|
341
|
|
|
protected function getActiveVersionFor($messageName) |
|
342
|
|
|
{ |
|
343
|
|
|
$msgAndVer = $this->getMessagesAndVersions(); |
|
344
|
|
|
|
|
345
|
|
|
$found = null; |
|
346
|
|
|
|
|
347
|
|
|
if (isset($msgAndVer[$messageName]) && isset($msgAndVer[$messageName]['version'])) { |
|
348
|
|
|
$found = $msgAndVer[$messageName]['version']; |
|
349
|
|
|
} |
|
350
|
|
|
|
|
351
|
|
|
return $found; |
|
352
|
|
|
} |
|
353
|
|
|
|
|
354
|
|
|
/** |
|
355
|
|
|
* Get the WSDL ID for the given message |
|
356
|
|
|
* |
|
357
|
|
|
* @param $messageName |
|
358
|
|
|
* @return string|null |
|
359
|
|
|
*/ |
|
360
|
|
|
protected function getWsdlIdFor($messageName) |
|
361
|
|
|
{ |
|
362
|
|
|
$msgAndVer = $this->getMessagesAndVersions(); |
|
363
|
|
|
|
|
364
|
|
|
if (isset($msgAndVer[$messageName]) && isset($msgAndVer[$messageName]['wsdl'])) { |
|
365
|
|
|
return $msgAndVer[$messageName]['wsdl']; |
|
366
|
|
|
} |
|
367
|
|
|
|
|
368
|
|
|
return null; |
|
369
|
|
|
} |
|
370
|
|
|
|
|
371
|
|
|
|
|
372
|
|
|
/** |
|
373
|
|
|
* Get the appropriate SoapClient for a given message |
|
374
|
|
|
* |
|
375
|
|
|
* (depends on which WSDL the message is defined in) |
|
376
|
|
|
* |
|
377
|
|
|
* @param string $msgName |
|
378
|
|
|
* @return \SoapClient |
|
379
|
|
|
*/ |
|
380
|
|
|
protected function getSoapClient($msgName) |
|
381
|
|
|
{ |
|
382
|
|
|
$wsdlId = $this->getWsdlIdFor($msgName); |
|
383
|
|
|
|
|
384
|
|
|
if (!empty($msgName)) { |
|
385
|
|
|
if (!isset($this->soapClients[$wsdlId]) || !($this->soapClients[$wsdlId] instanceof \SoapClient)) { |
|
386
|
|
|
$this->soapClients[$wsdlId] = $this->initSoapClient($wsdlId); |
|
387
|
|
|
} |
|
388
|
|
|
|
|
389
|
|
|
return $this->soapClients[$wsdlId]; |
|
390
|
|
|
} else { |
|
391
|
|
|
return null; |
|
392
|
|
|
} |
|
393
|
|
|
} |
|
394
|
|
|
|
|
395
|
|
|
/** |
|
396
|
|
|
* Initialize SoapClient for a given WSDL ID |
|
397
|
|
|
* |
|
398
|
|
|
* @param string $wsdlId |
|
399
|
|
|
* @return \SoapClient |
|
400
|
|
|
*/ |
|
401
|
|
|
protected function initSoapClient($wsdlId) |
|
402
|
|
|
{ |
|
403
|
|
|
$wsdlPath = WsdlAnalyser::$wsdlIds[$wsdlId]; |
|
404
|
|
|
|
|
405
|
|
|
$client = new Client\SoapClient( |
|
406
|
|
|
$wsdlPath, |
|
407
|
|
|
$this->makeSoapClientOptions(), |
|
408
|
|
|
$this->params->logger |
|
409
|
|
|
); |
|
410
|
|
|
|
|
411
|
|
|
return $client; |
|
412
|
|
|
} |
|
413
|
|
|
|
|
414
|
|
|
/** |
|
415
|
|
|
* Make Soap Header specific SoapClient options |
|
416
|
|
|
* |
|
417
|
|
|
* @return array |
|
418
|
|
|
*/ |
|
419
|
|
|
abstract protected function makeSoapClientOptions(); |
|
420
|
|
|
|
|
421
|
|
|
/** |
|
422
|
|
|
* Execute a method on the native SoapClient |
|
423
|
|
|
* |
|
424
|
|
|
* @param string $msgName |
|
425
|
|
|
* @param string $method |
|
426
|
|
|
* @return null|string |
|
427
|
|
|
*/ |
|
428
|
|
|
protected function executeMethodOnSoapClientForMsg($msgName, $method) |
|
429
|
|
|
{ |
|
430
|
|
|
$result = null; |
|
431
|
|
|
$soapClient = $this->getSoapClient($msgName); |
|
432
|
|
|
|
|
433
|
|
|
if ($soapClient instanceof \SoapClient) { |
|
434
|
|
|
$result = $soapClient->$method(); |
|
435
|
|
|
} |
|
436
|
|
|
|
|
437
|
|
|
return $result; |
|
438
|
|
|
} |
|
439
|
|
|
|
|
440
|
|
|
/** |
|
441
|
|
|
* @param string $messageName |
|
442
|
|
|
* @uses $this->log |
|
443
|
|
|
*/ |
|
444
|
|
|
protected function logRequestAndResponse($messageName) |
|
445
|
|
|
{ |
|
446
|
|
|
$this->log( |
|
447
|
|
|
LogLevel::INFO, |
|
448
|
|
|
'Called '.$messageName.' with request: '.$this->getSoapClient($messageName)->__getLastRequest() |
|
449
|
|
|
); |
|
450
|
|
|
$this->log( |
|
451
|
|
|
LogLevel::INFO, |
|
452
|
|
|
'Response: '.$this->getSoapClient($messageName)->__getLastResponse() |
|
453
|
|
|
); |
|
454
|
|
|
} |
|
455
|
|
|
|
|
456
|
|
|
/** |
|
457
|
|
|
* @param mixed $level |
|
458
|
|
|
* @param string $message |
|
459
|
|
|
* @param array $context |
|
460
|
|
|
* @return null |
|
461
|
|
|
*/ |
|
462
|
|
|
protected function log($level, $message, $context = []) |
|
463
|
|
|
{ |
|
464
|
|
|
if (is_null($this->logger)) { |
|
465
|
|
|
$this->setLogger(new NullLogger()); |
|
466
|
|
|
} |
|
467
|
|
|
|
|
468
|
|
|
return $this->logger->log($level, $message, $context); |
|
469
|
|
|
} |
|
470
|
|
|
} |
|
471
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountIdthat can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theidproperty of an instance of theAccountclass. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.