Test Failed
Push — master ( d99a5b...94cf84 )
by Dieter
10:01
created

analyzeWithErrCodeAndMsgQueryFixedCat()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 15
cts 15
cp 1
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 12
nc 3
nop 4
crap 4
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
 * The standard response handler for an individual message. Includes some basic functionality to build on.
31
 *
32
 * @package Amadeus\Client\ResponseHandler
33
 * @author Dieter Devlieghere <[email protected]>
34
 */
35
abstract class StandardResponseHandler implements MessageResponseHandler
36
{
37
    /**
38
     * Default namespace prefix we'll be using for xpath queries
39
     *
40
     * Why not "m"? It's as good as any other letter.
41
     */
42
    const XMLNS_PREFIX = "m";
43
44
    /**
45
     * Analyze response by looking for error, category and message with the provided XPATH queries
46
     *
47
     * xpath queries must be prefixed with the namespace self::XMLNS_PREFIX
48
     *
49
     * @param SendResult $response
50
     * @param string $qErr XPATH query for fetching error code (first node is used)
51
     * @param string $qCat XPATH query for fetching error category (first node is used)
52
     * @param string $qMsg XPATH query for fetching error messages (all nodes are used)
53
     * @param string|null $errLevel Optional custom error level string.
54
     * @return Result
55
     */
56 11
    protected function analyzeWithErrCodeCategoryMsgQuery(SendResult $response, $qErr, $qCat, $qMsg, $errLevel = null)
57
    {
58 11
        $analyzeResponse = new Result($response);
59
60 11
        $domXpath = $this->makeDomXpath($response->responseXml);
61
62 10
        $errorCodeNodeList = $domXpath->query($qErr);
63
64 10
        if ($errorCodeNodeList->length > 0) {
65 7
            $analyzeResponse->status = Result::STATUS_ERROR;
66
67 7
            $errorCatNode = $domXpath->query($qCat)->item(0);
68 7
            if ($errorCatNode instanceof \DOMNode) {
69 7
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
70 7
            }
71
72 7
            $analyzeResponse->messages[] = new Result\NotOk(
73 7
                $errorCodeNodeList->item(0)->nodeValue,
74 7
                $this->makeMessageFromMessagesNodeList(
75 7
                    $domXpath->query($qMsg)
76 7
                ),
77
                $errLevel
78 7
            );
79 7
        }
80
81 10
        return $analyzeResponse;
82
    }
83
84
    /**
85
     * Analyze response by looking for error, message and level with the provided XPATH queries
86
     *
87
     * Result status defaults to Result::STATUS_ERROR if any error is found.
88
     *
89
     * xpath queries must be prefixed with the namespace self::XMLNS_PREFIX
90
     *
91
     * @param SendResult $response
92
     * @param string $qErr XPATH query for fetching error code (first node is used)
93
     * @param string $qMsg XPATH query for fetching error messages (all nodes are used)
94
     * @param string $qLvl  XPATH query for fetching error level (first node is used)
95
     * @param array $lvlToText Level-to-text translation
96
     * @return Result
97
     */
98 1
    protected function analyzeWithErrorCodeMsgQueryLevel(SendResult $response, $qErr, $qMsg, $qLvl, $lvlToText)
99
    {
100 1
        $analyzeResponse = new Result($response);
101
102 1
        $domXpath = $this->makeDomXpath($response->responseXml);
103
104 1
        $errorCodeNodeList = $domXpath->query($qErr);
105
106 1
        if ($errorCodeNodeList->length > 0) {
107 1
            $analyzeResponse->status = Result::STATUS_ERROR;
108
109 1
            $lvlNodeList = $domXpath->query($qLvl);
110
111 1
            $level = null;
112 1
            if ($lvlNodeList->length > 0) {
113 1
                if (array_key_exists($lvlNodeList->item(0)->nodeValue, $lvlToText)) {
114 1
                    $level = $lvlToText[$lvlNodeList->item(0)->nodeValue];
115 1
                }
116 1
            }
117
118 1
            $analyzeResponse->messages[] = new Result\NotOk(
119 1
                $errorCodeNodeList->item(0)->nodeValue,
120 1
                $this->makeMessageFromMessagesNodeList(
121 1
                    $domXpath->query($qMsg)
122 1
                ),
123
                $level
124 1
            );
125 1
        }
126
127 1
        return $analyzeResponse;
128
    }
129
130
    /**
131
     * Analyse with XPATH queries for error code and message, provide fixed category
132
     *
133
     * @param SendResult $response
134
     * @param string $qErr XPATH query for fetching error code (first node is used)
135
     * @param string $qMsg XPATH query for fetching error messages (all nodes are used)
136
     * @param string $category Result::STATUS_* The fixed error category (status)
137
     * @return Result
138
     */
139 37
    public function analyzeWithErrCodeAndMsgQueryFixedCat(SendResult $response, $qErr, $qMsg, $category)
140
    {
141 37
        $analyzeResponse = new Result($response);
142
143 37
        $domXpath = $this->makeDomXpath($response->responseXml);
144
145 37
        $errorCodeNodeList = $domXpath->query($qErr);
146
        $errorMsgNodeList = $domXpath->query($qMsg);
147 37
148 30
        if ($errorCodeNodeList->length > 0 || $errorMsgNodeList->length > 0) {
149 30
            $analyzeResponse->status = $category;
150 22
151 22
            $errorCode = ($errorCodeNodeList->length > 0) ? $errorCodeNodeList->item(0)->nodeValue : null;
152 8
153
            $analyzeResponse->messages[] = new Result\NotOk(
154
                $errorCode,
155 30
                $this->makeMessageFromMessagesNodeList($errorMsgNodeList)
156 30
            );
157
        }
158 30
159 30
        return $analyzeResponse;
160 30
    }
161 30
162 30
    /**
163
     * Analyze response by looking for error, category and message in nodes specified by name
164 37
     *
165
     * @param SendResult $response
166
     * @param string $nodeErr Node name of the node containing the error code (first node is used)
167
     * @param string $nodeCat Node name of the node containing the error category (first node is used)
168
     * @param string $nodeMsg Node name of the node containing the error messages (all nodes are used)
169
     * @return Result
170
     */
171
    protected function analyzeWithErrCodeCategoryMsgNodeName(SendResult $response, $nodeErr, $nodeCat, $nodeMsg)
172
    {
173 28
        $analyzeResponse = new Result($response);
174
175 28
        $domDoc = $this->loadDomDocument($response->responseXml);
176 28
177 28
        $errorCodeNode = $domDoc->getElementsByTagName($nodeErr)->item(0);
178 28
179
        if (!is_null($errorCodeNode)) {
180 28
            $errorCatNode = $domDoc->getElementsByTagName($nodeCat)->item(0);
181
            if ($errorCatNode instanceof \DOMNode) {
182
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
183
            } else {
184
                $analyzeResponse->status = Result::STATUS_ERROR;
185
            }
186
187
            $errorCode = $errorCodeNode->nodeValue;
188 5
            $errorTextNodeList = $domDoc->getElementsByTagName($nodeMsg);
189
190 5
            $analyzeResponse->messages[] = new Result\NotOk(
191 5
                $errorCode,
192 5
                $this->makeMessageFromMessagesNodeList($errorTextNodeList)
193 5
            );
194
        }
195 5
196
        return $analyzeResponse;
197
    }
198
199
200
    /**
201
     * @param SendResult $response WebService message Send Result
202
     * @return Result
203
     * @throws Exception
204
     */
205
    protected function analyzeSimpleResponseErrorCodeAndMessage($response)
206
    {
207 51
        return $this->analyzeWithErrCodeCategoryMsgNodeName(
208
            $response,
209 51
            "errorCode",
210 50
            "errorCategory",
211
            "freeText"
212 50
        );
213 50
    }
214 50
215 50
    /**
216
     * @param SendResult $response WebService message Send Result
217 50
     * @return Result
218
     * @throws Exception
219
     */
220
    protected function analyzeSimpleResponseErrorCodeAndMessageStatusCode($response)
221
    {
222
        return $this->analyzeWithErrCodeCategoryMsgNodeName(
223
            $response,
224
            "errorCode",
225 93
            "statusCode",
226
            "freeText"
227 93
        );
228
    }
229 93
230 93
    /**
231 1
     * Make a Xpath-queryable object for an XML string
232
     *
233
     * registers TNS namespace with prefix self::XMLNS_PREFIX
234 92
     *
235
     * @param string $response
236
     * @return \DOMXPath
237
     * @throws Exception when there's a problem loading the message
238
     */
239
    protected function makeDomXpath($response)
240
    {
241
        $domDoc = $this->loadDomDocument($response);
242
        $domXpath = new \DOMXPath($domDoc);
243
244
        $domXpath->registerNamespace(
245
            self::XMLNS_PREFIX,
246 43
            $domDoc->documentElement->lookupNamespaceUri(null)
247
        );
248
249 43
        return $domXpath;
250 43
    }
251 43
252 43
    /**
253 43
     * @param string $response
254 43
     * @return \DOMDocument
255 43
     * @throws Exception when there's a problem loading the message
256 43
     */
257 43
    protected function loadDomDocument($response)
258 43
    {
259 43
        $domDoc = new \DOMDocument('1.0', 'UTF-8');
260
261 43
        $loadResult = $domDoc->loadXML($response);
262
        if ($loadResult === false) {
263 43
            throw new Exception('Could not load response message into DOMDocument');
264 41
        }
265 43
266 1
        return $domDoc;
267 1
    }
268 1
269
    /**
270
     * Converts a status code found in an error message to the appropriate status level
271 43
     *
272
     * if no node found (= $qualifier is a null), $defaultStatus will be used
273
     *
274
     * @param string|null $qualifier
275
     * @param string $defaultStatus the default status to fall back to if no qualifier is present
276
     * @return string Result::STATUS_*
277
     */
278
    protected function makeStatusFromErrorQualifier($qualifier, $defaultStatus = Result::STATUS_ERROR)
279
    {
280 48
        $statusQualMapping = [
281
            'INF' => Result::STATUS_INFO,
282 48
            'WEC' => Result::STATUS_WARN,
283 48
            'WZZ' => Result::STATUS_WARN, //Mutually defined warning
284 48
            'WA' => Result::STATUS_WARN, //Info line Warning - PNR_AddMultiElements
285 48
            'W' => Result::STATUS_WARN,
286 47
            'EC' => Result::STATUS_ERROR,
287 48
            'ERR' => Result::STATUS_ERROR, //DocRefund_UpdateRefund
288 48
            'X' => Result::STATUS_ERROR,
289 48
            '001' => Result::STATUS_ERROR, //Air_MultiAvailability
290 48
            'O' => Result::STATUS_OK,
291
            'STA' => Result::STATUS_OK,
292
            'ZZZ' => Result::STATUS_UNKNOWN
293
        ];
294
295
        if (array_key_exists($qualifier, $statusQualMapping)) {
296
            $status = $statusQualMapping[$qualifier];
297
        } elseif (is_null($qualifier)) {
298
            $status = $defaultStatus;
299
        } else {
300
            $status = Result::STATUS_UNKNOWN;
301
        }
302
303
        return $status;
304
    }
305
306
    /**
307
     * Convert a DomNodeList of nodes containing a (potentially partial) error message into a string.
308
     *
309
     * @param \DOMNodeList $errorTextNodeList
310
     * @return string|null
311
     */
312
    protected function makeMessageFromMessagesNodeList($errorTextNodeList)
313
    {
314
        return implode(
315
            ' - ',
316
            array_map(
317
                function ($item) {
318
                    return trim($item->nodeValue);
319
                },
320
                iterator_to_array($errorTextNodeList)
321
            )
322
        );
323
    }
324
}
325