Completed
Push — master ( 8f168b...4b1795 )
by Dieter
09:49
created

BaseUtils::makeStatusFromErrorQualifier()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 16
cts 16
cp 1
rs 9.0856
c 0
b 0
f 0
cc 2
eloc 17
nc 2
nop 1
crap 2
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
25
use Amadeus\Client\Exception;
26
use Amadeus\Client\Result;
27
use Amadeus\Client\Session\Handler\SendResult;
28
29
/**
30
 * BaseUtils
31
 *
32
 * Provides utility functions for the Base Response Handler.
33
 *
34
 * @package Amadeus\Client\ResponseHandler
35
 * @author Dieter Devlieghere <[email protected]>
36
 */
37
abstract class BaseUtils implements ResponseHandlerInterface
38
{
39
    /**
40
     * Default namespace prefix we'll be using for xpath queries
41
     *
42
     * Why not "m"? It's as good as any other letter.
43
     */
44
    const XMLNS_PREFIX = "m";
45
46
    /**
47
     * Analyze the response from the server and throw an exception when an error has been detected.
48
     *
49
     * @param SendResult $sendResult The Send Result from the Session Handler
50
     * @param string $messageName The message that was called
51
     *
52
     * @throws Exception
53
     * @throws \RuntimeException
54
     * @return Result
55
     */
56
    abstract public function analyzeResponse($sendResult, $messageName);
57
58
    /**
59
     * Analysing a PNR_Reply
60
     *
61
     * @param SendResult $response PNR_Retrieve result
62
     * @return Result
63
     */
64 6
    protected function analyzePnrReply($response)
65
    {
66 6
        $analyzeResponse = new Result($response);
67
68 6
        $domXpath = $this->makeDomXpath($response->responseXml);
69
70
        //General Errors:
71 6
        $queryAllErrorCodes = "//m:generalErrorInfo//m:errorOrWarningCodeDetails/m:errorDetails/m:errorCode";
72 6
        $queryAllErrorMsg = "//m:generalErrorInfo/m:errorWarningDescription/m:freeText";
73
74 6
        $errorCodeNodeList = $domXpath->query($queryAllErrorCodes);
75
76 6 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...
77 2
            $analyzeResponse->status = Result::STATUS_ERROR;
78
79 2
            $code = $errorCodeNodeList->item(0)->nodeValue;
80 2
            $errorTextNodeList = $domXpath->query($queryAllErrorMsg);
81 2
            $message = $this->makeMessageFromMessagesNodeList($errorTextNodeList);
82
83 2
            $analyzeResponse->messages[] = new Result\NotOk($code, trim($message), 'general');
84 2
        }
85
86
        //Segment errors:
87 6
        $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...
88 6
        $querySegmentErrorMsg = "//m:originDestinationDetails//m:errorInfo/m:errorWarningDescription/m:freeText";
89
90 6
        $errorCodeNodeList = $domXpath->query($querySegmentErrorCodes);
91
92 6 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...
93 1
            $analyzeResponse->status = Result::STATUS_ERROR;
94
95 1
            $code = $errorCodeNodeList->item(0)->nodeValue;
96 1
            $errorTextNodeList = $domXpath->query($querySegmentErrorMsg);
97 1
            $message = $this->makeMessageFromMessagesNodeList($errorTextNodeList);
98
99 1
            $analyzeResponse->messages[] = new Result\NotOk($code, trim($message), 'segment');
100 1
        }
101
102
        //Element errors:
103 6
        $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...
104 6
        $queryElementErrorMsg = "//m:dataElementsIndiv//m:elementErrorInformation/m:errorWarningDescription/m:freeText";
105
106 6
        $errorCodeNodeList = $domXpath->query($queryElementErrorCodes);
107
108 6 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...
109 1
            $analyzeResponse->status = Result::STATUS_ERROR;
110
111 1
            $code = $errorCodeNodeList->item(0)->nodeValue;
112
113 1
            $errorTextNodeList = $domXpath->query($queryElementErrorMsg);
114 1
            $message = $this->makeMessageFromMessagesNodeList($errorTextNodeList);
115
116 1
            $analyzeResponse->messages[] = new Result\NotOk($code, trim($message), 'element');
117 1
        }
118
119 6
        return $analyzeResponse;
120
    }
121
122
    /**
123
     * @param SendResult $response WebService message Send Result
124
     * @return Result
125
     * @throws Exception
126
     */
127 20 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...
128
    {
129 20
        $analyzeResponse = new Result($response);
130
131 20
        $domDoc = $this->loadDomDocument($response->responseXml);
132
133 20
        $errorCodeNode = $domDoc->getElementsByTagName("errorCode")->item(0);
134
135 20
        if (!is_null($errorCodeNode)) {
136 15
            $errorCatNode = $domDoc->getElementsByTagName("errorCategory")->item(0);
137 15
            if ($errorCatNode instanceof \DOMNode) {
138 9
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
139 9
            } else {
140 6
                $analyzeResponse->status = Result::STATUS_ERROR;
141
            }
142
143 15
            $errorCode = $errorCodeNode->nodeValue;
144 15
            $errorTextNodeList = $domDoc->getElementsByTagName("freeText");
145
146 15
            $analyzeResponse->messages[] = new Result\NotOk(
147 15
                $errorCode,
148 15
                $this->makeMessageFromMessagesNodeList($errorTextNodeList)
149 15
            );
150 15
        }
151
152 20
        return $analyzeResponse;
153
    }
154
155
    /**
156
     * @param SendResult $response WebService message Send Result
157
     * @return Result
158
     * @throws Exception
159
     */
160 3 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...
161
    {
162 3
        $analyzeResponse = new Result($response);
163
164 3
        $domDoc = $this->loadDomDocument($response->responseXml);
165
166 3
        $errorCodeNode = $domDoc->getElementsByTagName("errorCode")->item(0);
167
168 3
        if (!is_null($errorCodeNode)) {
169 3
            $analyzeResponse->status = Result::STATUS_ERROR;
170
171 3
            $errorCatNode = $domDoc->getElementsByTagName("statusCode")->item(0);
172 3
            if ($errorCatNode instanceof \DOMNode) {
173 3
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
174 3
            }
175
176 3
            $errorCode = $errorCodeNode->nodeValue;
177 3
            $errorTextNodeList = $domDoc->getElementsByTagName("freeText");
178
179 3
            $analyzeResponse->messages[] = new Result\NotOk(
180 3
                $errorCode,
181 3
                $this->makeMessageFromMessagesNodeList($errorTextNodeList)
182 3
            );
183 3
        }
184
185 3
        return $analyzeResponse;
186
    }
187
188
    /**
189
     * @param SendResult $response
190
     * @return Result
191
     */
192 8
    protected function analyzeGenericOfferResponse($response)
193
    {
194 8
        $analyzeResponse = new Result($response);
195
196 8
        $domXpath = $this->makeDomXpath($response->responseXml);
197
198 8
        $msgNode = $domXpath->query('//m:errorsDescription/m:errorWarningDescription/m:freeText')->item(0);
199
200 8
        if ($msgNode instanceof \DOMNode) {
201 7
            if (trim($msgNode->nodeValue) === "OFFER CONFIRMED SUCCESSFULLY" ||
202 5
                trim($msgNode->nodeValue) === "OFFER VERIFIED SUCCESSFULLY"
203 7
            ) {
204 3
                $analyzeResponse->messages[] = new Result\NotOk(
205 3
                    0,
206 3
                    trim($msgNode->nodeValue)
207 3
                );
208 3
                return $analyzeResponse;
209
            }
210
211 4
            $categoryNode = $domXpath->query('//m:errorDetails/m:errorCategory')->item(0);
212 4
            if ($categoryNode instanceof \DOMNode) {
213 4
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($categoryNode->nodeValue);
214 4
            }
215
216 4
            $codeNode = $domXpath->query('//m:errorDetails/m:errorCode')->item(0);
217
218 4
            $analyzeResponse->messages[] = new Result\NotOk(
219 4
                $codeNode->nodeValue,
220 4
                trim($msgNode->nodeValue)
221 4
            );
222 4
        }
223
224 5
        return $analyzeResponse;
225
    }
226
227
    /**
228
     * Returns the errortext from a Queue_*Reply errorcode
229
     *
230
     * This function is necessary because the core only responds
231
     * with errorcode but does not send an errortext.
232
     *
233
     * The errorcodes for all Queue_*Reply messages are the same.
234
     *
235
     * @link https://webservices.amadeus.com/extranet/viewArea.do?id=10
236
     * @param string $errorCode
237
     * @return string the errortext for this errorcode.
238
     */
239 3
    protected function getErrorTextFromQueueErrorCode($errorCode)
240
    {
241
        $recognizedErrors = [
242 3
            '723' => "Invalid category",
243 3
            '911' => "Unable to process - system error",
244 3
            '913' => "Item/data not found or data not existing in processing host",
245 3
            '79D' => "Queue identifier has not been assigned for specified office identification",
246 3
            '91C' => "invalid record locator",
247 3
            '91F' => "Invalid queue number",
248 3
            '921' => "target not specified",
249 3
            '922' => "Targetted queue has wrong queue type",
250 3
            '926' => "Queue category empty",
251 3
            '928' => "Queue category not assigned",
252 3
            '92A' => "Queue category full",
253 3
        ];
254
255 3
        $errorMessage = (array_key_exists($errorCode, $recognizedErrors)) ? $recognizedErrors[$errorCode] : '';
256
257 3
        if ($errorMessage === '') {
258 1
            $errorMessage = "QUEUE ERROR '" . $errorCode . "' (Error message unavailable)";
259 1
        }
260
261 3
        return $errorMessage;
262
    }
263
264
    /**
265
     * @param string $response
266
     * @return \DOMDocument
267
     * @throws Exception when there's a problem loading the message
268
     */
269 72
    protected function loadDomDocument($response)
270
    {
271 72
        $domDoc = new \DOMDocument('1.0', 'UTF-8');
272
273 72
        $loadResult = $domDoc->loadXML($response);
274 72
        if ($loadResult === false) {
275 1
            throw new Exception('Could not load response message into DOMDocument');
276
        }
277
278 71
        return $domDoc;
279
    }
280
281
    /**
282
     * Converts a status code found in an error message to the appropriate status level
283
     *
284
     * @param string $qualifier
285
     * @return string Result::STATUS_*
286
     */
287 31
    protected function makeStatusFromErrorQualifier($qualifier)
288
    {
289
        $statusQualMapping = [
290 31
            'INF' => Result::STATUS_INFO,
291 31
            'WEC' => Result::STATUS_WARN,
292 31
            'WZZ' => Result::STATUS_WARN, //Mutually defined warning
293 31
            'WA' => Result::STATUS_WARN,  //Info line Warning - PNR_AddMultiElements
294 31
            'W' => Result::STATUS_WARN,
295 31
            'EC' => Result::STATUS_ERROR,
296 31
            'X' => Result::STATUS_ERROR,
297 31
            '001' => Result::STATUS_ERROR, //Air_MultiAvailability
298 31
            'O' => Result::STATUS_OK,
299
            'ZZZ' => Result::STATUS_UNKNOWN
300 31
        ];
301
302 31
        if (array_key_exists($qualifier, $statusQualMapping)) {
303 30
            $status = $statusQualMapping[$qualifier];
304 30
        } else {
305 1
            $status = Result::STATUS_UNKNOWN;
306
        }
307
308 31
        return $status;
309
    }
310
311
    /**
312
     * Make a Xpath-queryable object for an XML string
313
     *
314
     * registers TNS namespace with prefix self::XMLNS_PREFIX
315
     *
316
     * @param string $response
317
     * @return \DOMXPath
318
     * @throws Exception when there's a problem loading the message
319
     */
320 40
    protected function makeDomXpath($response)
321
    {
322 40
        $domDoc = $this->loadDomDocument($response);
323 39
        $domXpath = new \DOMXPath($domDoc);
324
325 39
        $domXpath->registerNamespace(
326 39
            self::XMLNS_PREFIX,
327 39
            $domDoc->documentElement->lookupNamespaceUri(null)
328 39
        );
329
330 39
        return $domXpath;
331
    }
332
333
    /**
334
     * Convert a DomNodeList of nodes containing a (potentially partial) error message into a string.
335
     *
336
     * @param \DOMNodeList $errorTextNodeList
337
     * @return string|null
338
     */
339 32
    protected function makeMessageFromMessagesNodeList($errorTextNodeList)
340
    {
341 32
        return implode(
342 32
            ' - ',
343 32
            array_map(
344 32
                function ($item) {
345 32
                    return trim($item->nodeValue);
346 32
                },
347 32
                iterator_to_array($errorTextNodeList)
348 32
            )
349 32
        );
350
    }
351
352
    /**
353
     * @param SendResult $sendResult
354
     * @return Result
355
     */
356 2
    protected function makeResultForException($sendResult)
357
    {
358 2
        $result = new Result($sendResult, Result::STATUS_FATAL);
359
360 2
        $result->messages[] = $this->makeMessageFromException($sendResult->exception);
361
362 2
        return $result;
363
    }
364
365
    /**
366
     * @param \Exception $exception
367
     * @return Result\NotOk
368
     * @throws Exception
369
     */
370 2
    protected function makeMessageFromException(\Exception $exception)
371
    {
372 2
        $message = new Result\NotOk();
373
374 2
        if ($exception instanceof \SoapFault) {
375 2
            $info = explode('|', $exception->getMessage());
376 2
            $message->code = $info[0];
377 2
            if (count($info) === 3) {
378 2
                $message->level = $info[1];
379 2
                $message->text = $info[2];
380 2
            }
381 2
        }
382
383 2
        return $message;
384
    }
385
}
386