Base::prepareForNextMessage()
last analyzed

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
c 0
b 0
f 0
nc 1
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));
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->extractor->extrac...Response($messageName)) can also be of type boolean. However, the property $responseXml is declared as type string. Maybe add an additional type check?

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 $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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