Base::getActiveVersionFor()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 10
cc 3
nc 2
nop 1
crap 3
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 15
    public function getSessionData()
139
    {
140 15
        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 20
    public function setSessionData(array $sessionData)
150
    {
151 20
        if (isset($sessionData['sessionId'], $sessionData['sequenceNumber'], $sessionData['securityToken'])) {
152 15
            $this->sessionData['sessionId'] = $sessionData['sessionId'];
153 15
            $this->sessionData['sequenceNumber'] = $sessionData['sequenceNumber'];
154 15
            $this->sessionData['securityToken'] = $sessionData['securityToken'];
155 15
            $this->isAuthenticated = true;
156 6
        } else {
157 5
            $this->isAuthenticated = false;
158
        }
159
160 20
        return $this->isAuthenticated;
161
    }
162
163
164
    /**
165
     * @param SessionHandlerParams $params
166
     */
167 305
    public function __construct(SessionHandlerParams $params)
168
    {
169 305
        $this->params = $params;
170 305
        if ($params->logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$params->logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
171 285
            $this->setLogger($params->logger);
172 285
            $this->log(LogLevel::INFO, __METHOD__."(): Logger started.");
173 114
        }
174 305
        if ($params->overrideSoapClient instanceof \SoapClient) {
0 ignored issues
show
introduced by
$params->overrideSoapClient is always a sub-type of SoapClient.
Loading history...
175 50
            $this->soapClients[$params->overrideSoapClientWsdlName] = $params->overrideSoapClient;
176 20
        }
177 305
        $this->setStateful($params->stateful);
178 305
        $this->setTransactionFlowLink($params->enableTransactionFlowLink);
179 305
        $this->setConsumerId($params->consumerId);
180 305
        $this->extractor = new Client\Util\MsgBodyExtractor();
181 305
    }
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 55
    public function sendMessage($messageName, Client\Struct\BaseWsMessage $messageBody, $messageOptions = [])
194
    {
195 55
        $result = new SendResult(
196 55
            $this->getActiveVersionFor($messageName)
197 22
        );
198
199 55
        $this->prepareForNextMessage($messageName, $messageOptions);
200
201
        try {
202 50
            $result->responseObject = $this->getSoapClient($messageName)->$messageName($messageBody);
203
204 40
            $this->logRequestAndResponse($messageName);
205
206 40
            $this->handlePostMessage($messageName, $this->getLastResponse($messageName), $messageOptions, $result);
207 26
        } catch (\SoapFault $ex) {
208 5
            $this->log(
209 5
                LogLevel::ERROR,
210 5
                "SOAPFAULT while sending message ".$messageName.": ".$ex->getMessage().
211 5
                " code: ".$ex->getCode()." at ".$ex->getFile()." line ".$ex->getLine().
212 5
                ": \n".$ex->getTraceAsString()
213 2
            );
214 5
            $this->logRequestAndResponse($messageName);
215 5
            $this->handlePostMessage($messageName, $this->getLastResponse($messageName), $messageOptions, $result);
216 7
            $result->exception = $ex;
217
        } catch (\Exception $ex) {
218
            // We should only come here when the XSL extension is not enabled
219 5
            // or the XSLT transformation file is unreadable
220 5
            $this->log(
221 5
                LogLevel::ERROR,
222 7
                "EXCEPTION while sending message ".$messageName.": ".$ex->getMessage().
223 2
                " at ".$ex->getFile()." line ".$ex->getLine().": \n".$ex->getTraceAsString()
224 5
            );
225 5
            $this->logRequestAndResponse($messageName);
226
            throw new Client\Exception($ex->getMessage(), $ex->getCode(), $ex);
227
        }
228 45
229
        $result->responseXml = $this->extractor->extract($this->getLastResponse($messageName));
230 45
231
        return $result;
232
    }
233
234
    /**
235
     * Prepare to send a next message and checks if authenticated
236
     *
237
     * @param string $messageName
238
     * @param array $messageOptions
239
     */
240
    abstract protected function prepareForNextMessage($messageName, $messageOptions);
241
242
    /**
243
     * Handles post message actions
244
     *
245
     * Handles session state based on received response
246
     *
247
     * @param string $messageName
248
     * @param string $lastResponse
249
     * @param array $messageOptions
250
     * @param mixed $result
251
     */
252
    abstract protected function handlePostMessage($messageName, $lastResponse, $messageOptions, $result);
253
254
    /**
255
     * Get the last raw XML message that was sent out
256
     *
257
     * @param string $msgName
258
     * @return string|null
259 15
     */
260
    public function getLastRequest($msgName)
261 15
    {
262 15
        return $this->executeMethodOnSoapClientForMsg(
263 9
            $msgName,
264 6
            '__getLastRequest'
265
        );
266
    }
267
268
    /**
269
     * Get the last raw XML message that was received
270
     *
271
     * @param string $msgName
272
     * @return string|null
273 50
     */
274
    public function getLastResponse($msgName)
275 50
    {
276 50
        return $this->executeMethodOnSoapClientForMsg(
277 30
            $msgName,
278 20
            '__getLastResponse'
279
        );
280
    }
281
282
    /**
283
     * Get the request headers for the last SOAP message that was sent out
284
     *
285
     * @param string $msgName
286
     * @return string|null
287 10
     */
288
    public function getLastRequestHeaders($msgName)
289 10
    {
290 10
        return $this->executeMethodOnSoapClientForMsg(
291 6
            $msgName,
292 4
            '__getLastRequestHeaders'
293
        );
294
    }
295
296
    /**
297
     * Get the response headers for the last SOAP message that was received
298
     *
299
     * @param string $msgName
300
     * @return string|null
301 10
     */
302
    public function getLastResponseHeaders($msgName)
303 10
    {
304 10
        return $this->executeMethodOnSoapClientForMsg(
305 6
            $msgName,
306 4
            '__getLastResponseHeaders'
307
        );
308
    }
309
310
    /**
311
     * Get the office that we are using to sign in to.
312
     *
313
     * @return string
314 65
     */
315
    public function getOriginatorOffice()
316 65
    {
317
        return $this->params->authParams->officeId;
318
    }
319
320
    /**
321
     * Extract the Messages and versions from the loaded WSDL file.
322
     *
323
     * Result is an associative array: keys are message names, values are versions.
324
     *
325
     * @return array
326 180
     */
327
    public function getMessagesAndVersions()
328 180
    {
329 180
        if (empty($this->messagesAndVersions)) {
330 68
            $this->messagesAndVersions = WsdlAnalyser::loadMessagesAndVersions($this->params->wsdl);
331
        }
332 170
333
        return $this->messagesAndVersions;
334
    }
335
336
    /**
337
     * Get the version number active in the WSDL for the given message
338
     *
339
     * @param $messageName
340
     * @return float|string|null
341 55
     */
342
    protected function getActiveVersionFor($messageName)
343 55
    {
344
        $msgAndVer = $this->getMessagesAndVersions();
345 55
346
        $found = null;
347 55
348 55
        if (isset($msgAndVer[$messageName]) && isset($msgAndVer[$messageName]['version'])) {
349 22
            $found = $msgAndVer[$messageName]['version'];
350
        }
351 55
352
        return $found;
353
    }
354
355
    /**
356
     * Get the WSDL ID for the given message
357
     *
358
     * @param $messageName
359
     * @return string|null
360 105
     */
361
    protected function getWsdlIdFor($messageName)
362 105
    {
363
        $msgAndVer = $this->getMessagesAndVersions();
364 105
365 95
        if (isset($msgAndVer[$messageName]) && isset($msgAndVer[$messageName]['wsdl'])) {
366
            return $msgAndVer[$messageName]['wsdl'];
367
        }
368 10
369
        return null;
370
    }
371
372
373
    /**
374
     * Get the appropriate SoapClient for a given message
375
     *
376
     * (depends on which WSDL the message is defined in)
377
     *
378
     * @param string $msgName
379
     * @return \SoapClient
380 70
     */
381
    protected function getSoapClient($msgName)
382 70
    {
383
        $wsdlId = $this->getWsdlIdFor($msgName);
384 70
385 60
        if (!empty($msgName)) {
386 10
            if (!isset($this->soapClients[$wsdlId]) || !($this->soapClients[$wsdlId] instanceof \SoapClient)) {
387 4
                $this->soapClients[$wsdlId] = $this->initSoapClient($wsdlId);
388
            }
389 60
390
            return $this->soapClients[$wsdlId];
391 10
        } else {
392
            return null;
393
        }
394
    }
395
396
    /**
397
     * Initialize SoapClient for a given WSDL ID
398
     *
399
     * @param string $wsdlId
400
     * @return \SoapClient
401 10
     */
402
    protected function initSoapClient($wsdlId)
403 10
    {
404
//        d($wsdlId);
405 10
        $wsdlPath = WsdlAnalyser::$wsdlIds[$wsdlId];
406 10
407 10
        $client = new Client\SoapClient(
408 10
            $wsdlPath,
409 4
            $this->makeSoapClientOptions(),
410
            $this->params->logger
411 10
        );
412
413
        return $client;
414
    }
415
416
    /**
417
     * Make Soap Header specific SoapClient options
418
     *
419
     * @return array
420
     */
421
    abstract protected function makeSoapClientOptions();
422
423
    /**
424
     * Execute a method on the native SoapClient
425
     *
426
     * @param string $msgName
427
     * @param string $method
428 65
     * @return null|string
429
     */
430 65
    protected function executeMethodOnSoapClientForMsg($msgName, $method)
431 65
    {
432
        $result = null;
433 65
        $soapClient = $this->getSoapClient($msgName);
434 55
435 22
        if ($soapClient instanceof \SoapClient) {
0 ignored issues
show
introduced by
$soapClient is always a sub-type of SoapClient.
Loading history...
436
            $result = $soapClient->$method();
437 65
        }
438
439
        return $result;
440
    }
441
442
    /**
443
     * @param string $messageName
444 50
     * @uses $this->log
445
     */
446 50
    protected function logRequestAndResponse($messageName)
447 50
    {
448 50
        $this->log(
449 20
            LogLevel::INFO,
450 50
            'Called '.$messageName.' with request: '.$this->getSoapClient($messageName)->__getLastRequest()
451 50
        );
452 50
        $this->log(
453 20
            LogLevel::INFO,
454 50
            'Response:  '.$this->getSoapClient($messageName)->__getLastResponse()
455
        );
456
    }
457
458
    /**
459
     * @param mixed $level
460
     * @param string $message
461
     * @param array $context
462 300
     * @return null
463
     */
464 300
    protected function log($level, $message, $context = [])
465 15
    {
466 6
        if (is_null($this->logger)) {
467
            $this->setLogger(new NullLogger());
468 300
        }
469
470
        return $this->logger->log($level, $message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->logger->log($level, $message, $context) targeting Psr\Log\LoggerInterface::log() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
The method log() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

470
        return $this->logger->/** @scrutinizer ignore-call */ log($level, $message, $context);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
471
    }
472
}
473