Completed
Push — master ( 7c1a3d...b733b0 )
by Dieter
07:59
created

BaseUtils::getErrorTextFromQueueErrorCode()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.9713
c 0
b 0
f 0
cc 3
eloc 17
nc 4
nop 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\ResponseHandler;
24
use Amadeus\Client\Exception;
25
use Amadeus\Client\Result;
26
use Amadeus\Client\Session\Handler\SendResult;
27
28
/**
29
 * BaseUtils
30
 *
31
 * Provides utility functions for the Base Response Handler.
32
 *
33
 * @package Amadeus\Client\ResponseHandler
34
 * @author Dieter Devlieghere <[email protected]>
35
 */
36
abstract class BaseUtils implements ResponseHandlerInterface
37
{
38
    /**
39
     * Default namespace prefix we'll be using for xpath queries
40
     *
41
     * Why not "m"? It's as good as any other letter.
42
     */
43
    const XMLNS_PREFIX = "m";
44
45
    /**
46
     * Analyze the response from the server and throw an exception when an error has been detected.
47
     *
48
     * @param SendResult $sendResult The Send Result from the Session Handler
49
     * @param string $messageName The message that was called
50
     *
51
     * @throws Exception
52
     * @throws \RuntimeException
53
     * @return Result
54
     */
55
    public abstract function analyzeResponse($sendResult, $messageName);
0 ignored issues
show
Coding Style introduced by
The abstract declaration must precede the visibility declaration
Loading history...
56
57
    /**
58
     * Analysing a PNR_Reply
59
     *
60
     * @param SendResult $response PNR_Retrieve result
61
     * @return Result
62
     */
63
    protected function analyzePnrReply($response)
64
    {
65
        $analyzeResponse = new Result($response);
66
67
        $domXpath = $this->makeDomXpath($response->responseXml);
68
69
        //General Errors:
70
        $queryAllErrorCodes = "//m:generalErrorInfo//m:errorOrWarningCodeDetails/m:errorDetails/m:errorCode";
71
        $queryAllErrorMsg = "//m:generalErrorInfo/m:errorWarningDescription/m:freeText";
72
73
        $errorCodeNodeList = $domXpath->query($queryAllErrorCodes);
74
75 View Code Duplication
        if ($errorCodeNodeList->length > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
76
            $analyzeResponse->status = Result::STATUS_ERROR;
77
78
            $code = $errorCodeNodeList->item(0)->nodeValue;
79
            $errorTextNodeList = $domXpath->query($queryAllErrorMsg);
80
            $message = $this->makeMessageFromMessagesNodeList($errorTextNodeList);
81
82
            $analyzeResponse->messages[] = new Result\NotOk($code, trim($message), 'general');
83
        }
84
85
        //Segment errors:
86
        $querySegmentErrorCodes = "//m:originDestinationDetails//m:errorInfo/m:errorOrWarningCodeDetails/m:errorDetails/m:errorCode";
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 133 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
87
        $querySegmentErrorMsg = "//m:originDestinationDetails//m:errorInfo/m:errorWarningDescription/m:freeText";
88
89
        $errorCodeNodeList = $domXpath->query($querySegmentErrorCodes);
90
91 View Code Duplication
        if ($errorCodeNodeList->length > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
92
            $analyzeResponse->status = Result::STATUS_ERROR;
93
94
            $code = $errorCodeNodeList->item(0)->nodeValue;
95
            $errorTextNodeList = $domXpath->query($querySegmentErrorMsg);
96
            $message = $this->makeMessageFromMessagesNodeList($errorTextNodeList);
97
98
            $analyzeResponse->messages[] = new Result\NotOk($code, trim($message), 'segment');
99
        }
100
101
        //Element errors:
102
        $queryElementErrorCodes = "//m:dataElementsIndiv/m:elementErrorInformation/m:errorOrWarningCodeDetails/m:errorDetails/m:errorCode";
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 139 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
103
        $queryElementErrorMsg = "//m:dataElementsIndiv//m:elementErrorInformation/m:errorWarningDescription/m:freeText";
104
105
        $errorCodeNodeList = $domXpath->query($queryElementErrorCodes);
106
107 View Code Duplication
        if ($errorCodeNodeList->length > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
            $analyzeResponse->status = Result::STATUS_ERROR;
109
110
            $code = $errorCodeNodeList->item(0)->nodeValue;
111
112
            $errorTextNodeList = $domXpath->query($queryElementErrorMsg);
113
            $message = $this->makeMessageFromMessagesNodeList($errorTextNodeList);
114
115
            $analyzeResponse->messages[] = new Result\NotOk($code, trim($message), 'element');
116
        }
117
118
        return $analyzeResponse;
119
    }
120
121
    /**
122
     * @param SendResult $response WebService message Send Result
123
     * @return Result
124
     * @throws Exception
125
     */
126 View Code Duplication
    protected function analyzeSimpleResponseErrorCodeAndMessage($response)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
127
    {
128
        $analyzeResponse = new Result($response);
129
130
        $domDoc = $this->loadDomDocument($response->responseXml);
131
132
        $errorCodeNode = $domDoc->getElementsByTagName("errorCode")->item(0);
133
134
        if (!is_null($errorCodeNode)) {
135
            $errorCatNode = $domDoc->getElementsByTagName("errorCategory")->item(0);
136
            if ($errorCatNode instanceof \DOMNode) {
137
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
138
            } else {
139
                $analyzeResponse->status = Result::STATUS_ERROR;
140
            }
141
142
            $errorCode = $errorCodeNode->nodeValue;
143
            $errorTextNodeList = $domDoc->getElementsByTagName("freeText");
144
145
            $analyzeResponse->messages[] = new Result\NotOk(
146
                $errorCode,
147
                $this->makeMessageFromMessagesNodeList($errorTextNodeList)
148
            );
149
        }
150
151
        return $analyzeResponse;
152
    }
153
154
    /**
155
     * @param SendResult $response WebService message Send Result
156
     * @return Result
157
     * @throws Exception
158
     */
159 View Code Duplication
    protected function analyzeSimpleResponseErrorCodeAndMessageStatusCode($response)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
160
    {
161
        $analyzeResponse = new Result($response);
162
163
        $domDoc = $this->loadDomDocument($response->responseXml);
164
165
        $errorCodeNode = $domDoc->getElementsByTagName("errorCode")->item(0);
166
167
        if (!is_null($errorCodeNode)) {
168
            $analyzeResponse->status = Result::STATUS_ERROR;
169
170
            $errorCatNode = $domDoc->getElementsByTagName("statusCode")->item(0);
171
            if ($errorCatNode instanceof \DOMNode) {
172
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
173
            }
174
175
            $errorCode = $errorCodeNode->nodeValue;
176
            $errorTextNodeList = $domDoc->getElementsByTagName("freeText");
177
178
            $analyzeResponse->messages[] = new Result\NotOk(
179
                $errorCode,
180
                $this->makeMessageFromMessagesNodeList($errorTextNodeList)
181
            );
182
        }
183
184
        return $analyzeResponse;
185
    }
186
187
    /**
188
     * @param SendResult $response
189
     * @return Result
190
     */
191
    protected function analyzeGenericOfferResponse($response)
192
    {
193
        $analyzeResponse = new Result($response);
194
195
        $domXpath = $this->makeDomXpath($response->responseXml);
196
197
        $msgNode = $domXpath->query('//m:errorsDescription/m:errorWarningDescription/m:freeText')->item(0);
198
199
        if ($msgNode instanceof \DOMNode) {
200
            if (trim($msgNode->nodeValue) === "OFFER CONFIRMED SUCCESSFULLY" ||
201
                trim($msgNode->nodeValue) === "OFFER VERIFIED SUCCESSFULLY"
202
            ) {
203
                $analyzeResponse->messages[] = new Result\NotOk(
204
                    0,
205
                    trim($msgNode->nodeValue)
206
                );
207
                return $analyzeResponse;
208
            }
209
210
            $categoryNode = $domXpath->query('//m:errorDetails/m:errorCategory')->item(0);
211
            if ($categoryNode instanceof \DOMNode) {
212
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($categoryNode->nodeValue);
213
            }
214
215
            $codeNode = $domXpath->query('//m:errorDetails/m:errorCode')->item(0);
216
217
            $analyzeResponse->messages[] = new Result\NotOk(
218
                $codeNode->nodeValue,
219
                trim($msgNode->nodeValue)
220
            );
221
        }
222
223
        return $analyzeResponse;
224
    }
225
226
    /**
227
     * Returns the errortext from a Queue_*Reply errorcode
228
     *
229
     * This function is necessary because the core only responds
230
     * with errorcode but does not send an errortext.
231
     *
232
     * The errorcodes for all Queue_*Reply messages are the same.
233
     *
234
     * @link https://webservices.amadeus.com/extranet/viewArea.do?id=10
235
     * @param string $errorCode
236
     * @return string the errortext for this errorcode.
237
     */
238
    protected function getErrorTextFromQueueErrorCode($errorCode)
239
    {
240
        $recognizedErrors = [
241
            '723' => "Invalid category",
242
            '911' => "Unable to process - system error",
243
            '913' => "Item/data not found or data not existing in processing host",
244
            '79D' => "Queue identifier has not been assigned for specified office identification",
245
            '91C' => "invalid record locator",
246
            '91F' => "Invalid queue number",
247
            '921' => "target not specified",
248
            '922' => "Targetted queue has wrong queue type",
249
            '926' => "Queue category empty",
250
            '928' => "Queue category not assigned",
251
            '92A' => "Queue category full",
252
        ];
253
254
        $errorMessage = (array_key_exists($errorCode, $recognizedErrors)) ? $recognizedErrors[$errorCode] : '';
255
256
        if ($errorMessage === '') {
257
            $errorMessage = "QUEUE ERROR '" . $errorCode . "' (Error message unavailable)";
258
        }
259
260
        return $errorMessage;
261
    }
262
263
    /**
264
     * @param string $response
265
     * @return \DOMDocument
266
     * @throws Exception when there's a problem loading the message
267
     */
268
    protected function loadDomDocument($response)
269
    {
270
        $domDoc = new \DOMDocument('1.0', 'UTF-8');
271
272
        $loadResult = $domDoc->loadXML($response);
273
        if ($loadResult === false) {
274
            throw new Exception('Could not load response message into DOMDocument');
275
        }
276
277
        return $domDoc;
278
    }
279
280
    /**
281
     * @param string $qualifier
282
     * @return string Result::STATUS_*
283
     */
284
    protected function makeStatusFromErrorQualifier($qualifier)
285
    {
286
        $status = null;
0 ignored issues
show
Unused Code introduced by
$status is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
287
288
        switch ($qualifier) {
289
            case 'INF':
290
                $status = Result::STATUS_INFO;
291
                break;
292
            case 'WEC':
293
            case 'WZZ': //Mutually defined warning
294
            case 'WA': //Info line Warning - PNR_AddMultiElements
295
            case 'W':
296
                $status = Result::STATUS_WARN;
297
                break;
298
            case 'EC':
299
            case 'X':
300
            case '001': //Air_MultiAvailability
301
                $status = Result::STATUS_ERROR;
302
                break;
303
            case 'O':
304
                $status = Result::STATUS_OK;
305
                break;
306
            case 'ZZZ': //Mutually defined
307
            default:
308
                $status = Result::STATUS_UNKNOWN;
309
                break;
310
        }
311
312
        return $status;
313
    }
314
315
316
    /**
317
     * Make a Xpath-queryable object for an XML string
318
     *
319
     * registers TNS namespace with prefix self::XMLNS_PREFIX
320
     *
321
     * @param string $response
322
     * @return \DOMXPath
323
     * @throws Exception when there's a problem loading the message
324
     */
325
    protected function makeDomXpath($response)
326
    {
327
        $domDoc = $this->loadDomDocument($response);
328
        $domXpath = new \DOMXPath($domDoc);
329
330
        $domXpath->registerNamespace(
331
            self::XMLNS_PREFIX,
332
            $domDoc->documentElement->lookupNamespaceUri(null)
333
        );
334
335
        return $domXpath;
336
    }
337
338
    /**
339
     * Convert a DomNodeList of nodes containing a (potentially partial) error message into a string.
340
     *
341
     * @param \DOMNodeList $errorTextNodeList
342
     * @return string|null
343
     */
344
    protected function makeMessageFromMessagesNodeList($errorTextNodeList)
345
    {
346
        return implode(
347
            ' - ',
348
            array_map(
349
                function ($item) {
350
                    return trim($item->nodeValue);
351
                },
352
                iterator_to_array($errorTextNodeList)
353
            )
354
        );
355
    }
356
357
    /**
358
     * @param SendResult $sendResult
359
     * @return Result
360
     */
361
    protected function makeResultForException($sendResult)
362
    {
363
        $result = new Result($sendResult, Result::STATUS_FATAL);
364
365
        $result->messages[] = $this->makeMessageFromException($sendResult->exception);
366
367
        return $result;
368
    }
369
370
    /**
371
     * @param \Exception $exception
372
     * @return Result\NotOk
373
     * @throws Exception
374
     */
375
    protected function makeMessageFromException(\Exception $exception)
376
    {
377
        $message = new Result\NotOk();
378
379
        if ($exception instanceof \SoapFault) {
380
            $info = explode('|', $exception->getMessage());
381
            $message->code = $info[0];
382
            if (count($info) === 3) {
383
                $message->level = $info[1];
384
                $message->text = $info[2];
385
            }
386
        }
387
388
        return $message;
389
    }
390
}
391