Completed
Push — master ( 833351...5fbac6 )
by Dieter
07:24
created

makeMessageFromMessagesNodeList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 1
crap 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
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 9
    protected function analyzeWithErrCodeCategoryMsgQuery(SendResult $response, $qErr, $qCat, $qMsg, $errLevel = null)
57
    {
58 9
        $analyzeResponse = new Result($response);
59
60 9
        $domXpath = $this->makeDomXpath($response->responseXml);
61
62 8
        $errorCodeNodeList = $domXpath->query($qErr);
63
64 8
        if ($errorCodeNodeList->length > 0) {
65 5
            $analyzeResponse->status = Result::STATUS_ERROR;
66
67 5
            $errorCatNode = $domXpath->query($qCat)->item(0);
68 5
            if ($errorCatNode instanceof \DOMNode) {
69 5
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
70 5
            }
71
72 5
            $analyzeResponse->messages[] = new Result\NotOk(
73 5
                $errorCodeNodeList->item(0)->nodeValue,
74 5
                $this->makeMessageFromMessagesNodeList(
75 5
                    $domXpath->query($qMsg)
76 5
                ),
77
                $errLevel
78 5
            );
79 5
        }
80
81 8
        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
     * Analyze response by looking for error, category and message in nodes specified by name
132
     *
133
     * @param SendResult $response
134
     * @param string $nodeErr Node name of the node containing the error code (first node is used)
135
     * @param string $nodeCat Node name of the node containing the error category (first node is used)
136
     * @param string $nodeMsg Node name of the node containing the error messages (all nodes are used)
137
     * @return Result
138
     */
139 33
    protected function analyzeWithErrCodeCategoryMsgNodeName(SendResult $response, $nodeErr, $nodeCat, $nodeMsg)
140
    {
141 33
        $analyzeResponse = new Result($response);
142
143 33
        $domDoc = $this->loadDomDocument($response->responseXml);
144
145 33
        $errorCodeNode = $domDoc->getElementsByTagName($nodeErr)->item(0);
146
147 33
        if (!is_null($errorCodeNode)) {
148 27
            $errorCatNode = $domDoc->getElementsByTagName($nodeCat)->item(0);
149 27
            if ($errorCatNode instanceof \DOMNode) {
150 20
                $analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue);
151 20
            } else {
152 7
                $analyzeResponse->status = Result::STATUS_ERROR;
153
            }
154
155 27
            $errorCode = $errorCodeNode->nodeValue;
156 27
            $errorTextNodeList = $domDoc->getElementsByTagName($nodeMsg);
157
158 27
            $analyzeResponse->messages[] = new Result\NotOk(
159 27
                $errorCode,
160 27
                $this->makeMessageFromMessagesNodeList($errorTextNodeList)
161 27
            );
162 27
        }
163
164 33
        return $analyzeResponse;
165
    }
166
167
168
    /**
169
     * @param SendResult $response WebService message Send Result
170
     * @return Result
171
     * @throws Exception
172
     */
173 26
    protected function analyzeSimpleResponseErrorCodeAndMessage($response)
174
    {
175 26
        return $this->analyzeWithErrCodeCategoryMsgNodeName(
176 26
            $response,
177 26
            "errorCode",
178 26
            "errorCategory",
179
            "freeText"
180 26
        );
181
    }
182
183
    /**
184
     * @param SendResult $response WebService message Send Result
185
     * @return Result
186
     * @throws Exception
187
     */
188 4
    protected function analyzeSimpleResponseErrorCodeAndMessageStatusCode($response)
189
    {
190 4
        return $this->analyzeWithErrCodeCategoryMsgNodeName(
191 4
            $response,
192 4
            "errorCode",
193 4
            "statusCode",
194
            "freeText"
195 4
        );
196
    }
197
198
    /**
199
     * Make a Xpath-queryable object for an XML string
200
     *
201
     * registers TNS namespace with prefix self::XMLNS_PREFIX
202
     *
203
     * @param string $response
204
     * @return \DOMXPath
205
     * @throws Exception when there's a problem loading the message
206
     */
207 47
    protected function makeDomXpath($response)
208
    {
209 47
        $domDoc = $this->loadDomDocument($response);
210 46
        $domXpath = new \DOMXPath($domDoc);
211
212 46
        $domXpath->registerNamespace(
213 46
            self::XMLNS_PREFIX,
214 46
            $domDoc->documentElement->lookupNamespaceUri(null)
215 46
        );
216
217 46
        return $domXpath;
218
    }
219
220
    /**
221
     * @param string $response
222
     * @return \DOMDocument
223
     * @throws Exception when there's a problem loading the message
224
     */
225 85
    protected function loadDomDocument($response)
226
    {
227 85
        $domDoc = new \DOMDocument('1.0', 'UTF-8');
228
229 85
        $loadResult = $domDoc->loadXML($response);
230 85
        if ($loadResult === false) {
231 1
            throw new Exception('Could not load response message into DOMDocument');
232
        }
233
234 84
        return $domDoc;
235
    }
236
237
    /**
238
     * Converts a status code found in an error message to the appropriate status level
239
     *
240
     * if no node found (= $qualifier is a null), $defaultStatus will be used
241
     *
242
     * @param string|null $qualifier
243
     * @param string $defaultStatus the default status to fall back to if no qualifier is present
244
     * @return string Result::STATUS_*
245
     */
246 39
    protected function makeStatusFromErrorQualifier($qualifier, $defaultStatus = Result::STATUS_ERROR)
247
    {
248
        $statusQualMapping = [
249 39
            'INF' => Result::STATUS_INFO,
250 39
            'WEC' => Result::STATUS_WARN,
251 39
            'WZZ' => Result::STATUS_WARN, //Mutually defined warning
252 39
            'WA' => Result::STATUS_WARN, //Info line Warning - PNR_AddMultiElements
253 39
            'W' => Result::STATUS_WARN,
254 39
            'EC' => Result::STATUS_ERROR,
255 39
            'X' => Result::STATUS_ERROR,
256 39
            '001' => Result::STATUS_ERROR, //Air_MultiAvailability
257 39
            'O' => Result::STATUS_OK,
258
            'ZZZ' => Result::STATUS_UNKNOWN
259 39
        ];
260
261 39
        if (array_key_exists($qualifier, $statusQualMapping)) {
262 37
            $status = $statusQualMapping[$qualifier];
263 39
        } elseif (is_null($qualifier)) {
264 1
            $status = $defaultStatus;
265 1
        } else {
266 1
            $status = Result::STATUS_UNKNOWN;
267
        }
268
269 39
        return $status;
270
    }
271
272
    /**
273
     * Convert a DomNodeList of nodes containing a (potentially partial) error message into a string.
274
     *
275
     * @param \DOMNodeList $errorTextNodeList
276
     * @return string|null
277
     */
278 42
    protected function makeMessageFromMessagesNodeList($errorTextNodeList)
279
    {
280 42
        return implode(
281 42
            ' - ',
282 42
            array_map(
283 42
                function ($item) {
284 41
                    return trim($item->nodeValue);
285 42
                },
286 42
                iterator_to_array($errorTextNodeList)
287 42
            )
288 42
        );
289
    }
290
}
291