|
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, category and message in nodes specified by name |
|
86
|
|
|
* |
|
87
|
|
|
* @param SendResult $response |
|
88
|
|
|
* @param string $nodeErr Node name of the node containing the error code (first node is used) |
|
89
|
|
|
* @param string $nodeCat Node name of the node containing the error category (first node is used) |
|
90
|
|
|
* @param string $nodeMsg Node name of the node containing the error messages (all nodes are used) |
|
91
|
|
|
* @return Result |
|
92
|
|
|
*/ |
|
93
|
30 |
|
protected function analyzeWithErrCodeCategoryMsgNodeName(SendResult $response, $nodeErr, $nodeCat, $nodeMsg) |
|
94
|
|
|
{ |
|
95
|
30 |
|
$analyzeResponse = new Result($response); |
|
96
|
|
|
|
|
97
|
30 |
|
$domDoc = $this->loadDomDocument($response->responseXml); |
|
98
|
|
|
|
|
99
|
30 |
|
$errorCodeNode = $domDoc->getElementsByTagName($nodeErr)->item(0); |
|
100
|
|
|
|
|
101
|
30 |
View Code Duplication |
if (!is_null($errorCodeNode)) { |
|
|
|
|
|
|
102
|
24 |
|
$errorCatNode = $domDoc->getElementsByTagName($nodeCat)->item(0); |
|
103
|
24 |
|
if ($errorCatNode instanceof \DOMNode) { |
|
104
|
17 |
|
$analyzeResponse->status = $this->makeStatusFromErrorQualifier($errorCatNode->nodeValue); |
|
105
|
17 |
|
} else { |
|
106
|
7 |
|
$analyzeResponse->status = Result::STATUS_ERROR; |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
24 |
|
$errorCode = $errorCodeNode->nodeValue; |
|
110
|
24 |
|
$errorTextNodeList = $domDoc->getElementsByTagName($nodeMsg); |
|
111
|
|
|
|
|
112
|
24 |
|
$analyzeResponse->messages[] = new Result\NotOk( |
|
113
|
24 |
|
$errorCode, |
|
114
|
24 |
|
$this->makeMessageFromMessagesNodeList($errorTextNodeList) |
|
115
|
24 |
|
); |
|
116
|
24 |
|
} |
|
117
|
|
|
|
|
118
|
30 |
|
return $analyzeResponse; |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* @param SendResult $response WebService message Send Result |
|
124
|
|
|
* @return Result |
|
125
|
|
|
* @throws Exception |
|
126
|
|
|
*/ |
|
127
|
26 |
|
protected function analyzeSimpleResponseErrorCodeAndMessage($response) |
|
128
|
|
|
{ |
|
129
|
26 |
|
return $this->analyzeWithErrCodeCategoryMsgNodeName( |
|
130
|
26 |
|
$response, |
|
131
|
26 |
|
"errorCode", |
|
132
|
26 |
|
"errorCategory", |
|
133
|
|
|
"freeText" |
|
134
|
26 |
|
); |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
/** |
|
138
|
|
|
* @param SendResult $response WebService message Send Result |
|
139
|
|
|
* @return Result |
|
140
|
|
|
* @throws Exception |
|
141
|
|
|
*/ |
|
142
|
4 |
|
protected function analyzeSimpleResponseErrorCodeAndMessageStatusCode($response) |
|
143
|
|
|
{ |
|
144
|
4 |
|
return $this->analyzeWithErrCodeCategoryMsgNodeName( |
|
145
|
4 |
|
$response, |
|
146
|
4 |
|
"errorCode", |
|
147
|
4 |
|
"statusCode", |
|
148
|
|
|
"freeText" |
|
149
|
4 |
|
); |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
|
/** |
|
153
|
|
|
* Make a Xpath-queryable object for an XML string |
|
154
|
|
|
* |
|
155
|
|
|
* registers TNS namespace with prefix self::XMLNS_PREFIX |
|
156
|
|
|
* |
|
157
|
|
|
* @param string $response |
|
158
|
|
|
* @return \DOMXPath |
|
159
|
|
|
* @throws Exception when there's a problem loading the message |
|
160
|
|
|
*/ |
|
161
|
46 |
|
protected function makeDomXpath($response) |
|
162
|
|
|
{ |
|
163
|
46 |
|
$domDoc = $this->loadDomDocument($response); |
|
164
|
45 |
|
$domXpath = new \DOMXPath($domDoc); |
|
165
|
|
|
|
|
166
|
45 |
|
$domXpath->registerNamespace( |
|
167
|
45 |
|
self::XMLNS_PREFIX, |
|
168
|
45 |
|
$domDoc->documentElement->lookupNamespaceUri(null) |
|
169
|
45 |
|
); |
|
170
|
|
|
|
|
171
|
45 |
|
return $domXpath; |
|
172
|
|
|
} |
|
173
|
|
|
|
|
174
|
|
|
/** |
|
175
|
|
|
* @param string $response |
|
176
|
|
|
* @return \DOMDocument |
|
177
|
|
|
* @throws Exception when there's a problem loading the message |
|
178
|
|
|
*/ |
|
179
|
84 |
|
protected function loadDomDocument($response) |
|
180
|
|
|
{ |
|
181
|
84 |
|
$domDoc = new \DOMDocument('1.0', 'UTF-8'); |
|
182
|
|
|
|
|
183
|
84 |
|
$loadResult = $domDoc->loadXML($response); |
|
184
|
84 |
|
if ($loadResult === false) { |
|
185
|
1 |
|
throw new Exception('Could not load response message into DOMDocument'); |
|
186
|
|
|
} |
|
187
|
|
|
|
|
188
|
83 |
|
return $domDoc; |
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
|
|
/** |
|
192
|
|
|
* Converts a status code found in an error message to the appropriate status level |
|
193
|
|
|
* |
|
194
|
|
|
* if no node found (= $qualifier is a null), $defaultStatus will be used |
|
195
|
|
|
* |
|
196
|
|
|
* @param string|null $qualifier |
|
197
|
|
|
* @param string $defaultStatus the default status to fall back to if no qualifier is present |
|
198
|
|
|
* @return string Result::STATUS_* |
|
199
|
|
|
*/ |
|
200
|
39 |
|
protected function makeStatusFromErrorQualifier($qualifier, $defaultStatus = Result::STATUS_ERROR) |
|
201
|
|
|
{ |
|
202
|
|
|
$statusQualMapping = [ |
|
203
|
39 |
|
'INF' => Result::STATUS_INFO, |
|
204
|
39 |
|
'WEC' => Result::STATUS_WARN, |
|
205
|
39 |
|
'WZZ' => Result::STATUS_WARN, //Mutually defined warning |
|
206
|
39 |
|
'WA' => Result::STATUS_WARN, //Info line Warning - PNR_AddMultiElements |
|
207
|
39 |
|
'W' => Result::STATUS_WARN, |
|
208
|
39 |
|
'EC' => Result::STATUS_ERROR, |
|
209
|
39 |
|
'X' => Result::STATUS_ERROR, |
|
210
|
39 |
|
'001' => Result::STATUS_ERROR, //Air_MultiAvailability |
|
211
|
39 |
|
'O' => Result::STATUS_OK, |
|
212
|
|
|
'ZZZ' => Result::STATUS_UNKNOWN |
|
213
|
39 |
|
]; |
|
214
|
|
|
|
|
215
|
39 |
|
if (array_key_exists($qualifier, $statusQualMapping)) { |
|
216
|
37 |
|
$status = $statusQualMapping[$qualifier]; |
|
217
|
39 |
|
} elseif (is_null($qualifier)) { |
|
218
|
1 |
|
$status = $defaultStatus; |
|
219
|
1 |
|
} else { |
|
220
|
1 |
|
$status = Result::STATUS_UNKNOWN; |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
39 |
|
return $status; |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
/** |
|
227
|
|
|
* Convert a DomNodeList of nodes containing a (potentially partial) error message into a string. |
|
228
|
|
|
* |
|
229
|
|
|
* @param \DOMNodeList $errorTextNodeList |
|
230
|
|
|
* @return string|null |
|
231
|
|
|
*/ |
|
232
|
41 |
|
protected function makeMessageFromMessagesNodeList($errorTextNodeList) |
|
233
|
|
|
{ |
|
234
|
41 |
|
return implode( |
|
235
|
41 |
|
' - ', |
|
236
|
41 |
|
array_map( |
|
237
|
41 |
|
function ($item) { |
|
238
|
40 |
|
return trim($item->nodeValue); |
|
239
|
41 |
|
}, |
|
240
|
41 |
|
iterator_to_array($errorTextNodeList) |
|
241
|
41 |
|
) |
|
242
|
41 |
|
); |
|
243
|
|
|
} |
|
244
|
|
|
} |
|
245
|
|
|
|
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.