|
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\Session\Handler; |
|
24
|
|
|
|
|
25
|
|
|
use Amadeus\Client\InvalidWsdlFileException; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* Wsdl Analyser |
|
29
|
|
|
* |
|
30
|
|
|
* Analyses the given WSDL or WSDL's for the WSAP |
|
31
|
|
|
* Extracts available messages & versions from it |
|
32
|
|
|
* |
|
33
|
|
|
* @package Amadeus\Client\Session\Handler |
|
34
|
|
|
* @author Dieter Devlieghere <[email protected]> |
|
35
|
|
|
*/ |
|
36
|
|
|
class WsdlAnalyser |
|
37
|
|
|
{ |
|
38
|
|
|
/** |
|
39
|
|
|
* XPATH query to retrieve all operations from a WSDL |
|
40
|
|
|
* |
|
41
|
|
|
* @var string |
|
42
|
|
|
*/ |
|
43
|
|
|
const XPATH_ALL_OPERATIONS = '/wsdl:definitions/wsdl:portType/wsdl:operation/@name'; |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* XPATH query to retrieve WSDL imports from a WSDL. |
|
47
|
|
|
*/ |
|
48
|
|
|
const XPATH_IMPORTS = '/wsdl:definitions/wsdl:import/@location'; |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* XPATH query to retrieve the full operation name + version from a WSDL for a given operation. |
|
52
|
|
|
* |
|
53
|
|
|
* @var string |
|
54
|
|
|
*/ |
|
55
|
|
|
const XPATH_VERSION_FOR_OPERATION = "string(/wsdl:definitions/wsdl:message[contains(./@name, '%s_')]/@name)"; |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* Alternate XPATH query to retrieve the full operation name + version from a WSDL for a given operation |
|
59
|
|
|
* |
|
60
|
|
|
* Necessary for "interface" wsdls |
|
61
|
|
|
* |
|
62
|
|
|
* @var string |
|
63
|
|
|
*/ |
|
64
|
|
|
const XPATH_ALT_VERSION_FOR_OPERATION = "string(//wsdl:operation[contains(./@name, '%s')]/wsdl:input/@message)"; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* List of WSDL ID's and their path |
|
68
|
|
|
* |
|
69
|
|
|
* format: |
|
70
|
|
|
* [ |
|
71
|
|
|
* '7d36c7b8' => '/path/to/wsdl.wsdl' |
|
72
|
|
|
* ] |
|
73
|
|
|
* |
|
74
|
|
|
* @var array |
|
75
|
|
|
*/ |
|
76
|
|
|
public static $wsdlIds = []; |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* Dom Document array where the WSDL's contents will be loaded |
|
80
|
|
|
* |
|
81
|
|
|
* format: |
|
82
|
|
|
* [ |
|
83
|
|
|
* '7d36c7b8' => \DOMDocument, |
|
84
|
|
|
* '7e84f2537' => \DOMDocument |
|
85
|
|
|
* ] |
|
86
|
|
|
* |
|
87
|
|
|
* @var array |
|
88
|
|
|
*/ |
|
89
|
|
|
protected static $wsdlDomDoc; |
|
90
|
|
|
|
|
91
|
|
|
/** |
|
92
|
|
|
* To query the WSDL contents |
|
93
|
|
|
* |
|
94
|
|
|
* format: |
|
95
|
|
|
* [ |
|
96
|
|
|
* '7d36c7b8' => \DOMXpath, |
|
97
|
|
|
* '7e84f2537' => \DOMXpath |
|
98
|
|
|
* ] |
|
99
|
|
|
* |
|
100
|
|
|
* @var array |
|
101
|
|
|
*/ |
|
102
|
|
|
protected static $wsdlDomXpath; |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Loads messages & versions from WSDL. |
|
106
|
|
|
* |
|
107
|
|
|
* @return array |
|
108
|
|
|
*/ |
|
109
|
31 |
|
public static function loadMessagesAndVersions($wsdls) |
|
110
|
|
|
{ |
|
111
|
31 |
|
$msgAndVer = []; |
|
112
|
|
|
|
|
113
|
31 |
|
foreach ($wsdls as $wsdl) { |
|
114
|
31 |
|
$wsdlIdentifier = self::makeWsdlIdentifier($wsdl); |
|
115
|
|
|
|
|
116
|
31 |
|
self::$wsdlIds[$wsdlIdentifier] = $wsdl; |
|
117
|
|
|
|
|
118
|
31 |
|
self::loadWsdlXpath($wsdl, $wsdlIdentifier); |
|
119
|
|
|
|
|
120
|
31 |
|
$operations = self::$wsdlDomXpath[$wsdlIdentifier]->query(self::XPATH_ALL_OPERATIONS); |
|
121
|
31 |
|
if ($operations->length === 0) { |
|
122
|
|
|
//No operations found - are there any external WSDLs being imported? |
|
123
|
2 |
|
$imports = self::$wsdlDomXpath[$wsdlIdentifier]->query(self::XPATH_IMPORTS); |
|
124
|
2 |
|
$operations = []; |
|
125
|
|
|
|
|
126
|
2 |
|
foreach ($imports as $import) { |
|
127
|
2 |
|
if (!empty($import->value)) { |
|
128
|
2 |
|
$tmpMsg = self::getMessagesAndVersionsFromImportedWsdl( |
|
129
|
2 |
|
$import->value, |
|
130
|
2 |
|
$wsdl, |
|
131
|
|
|
$wsdlIdentifier |
|
132
|
2 |
|
); |
|
133
|
1 |
|
foreach ($tmpMsg as $msgName => $msgInfo) { |
|
134
|
1 |
|
$msgAndVer[$msgName] = $msgInfo; |
|
135
|
1 |
|
} |
|
136
|
1 |
|
} |
|
137
|
1 |
|
} |
|
138
|
1 |
|
} |
|
139
|
|
|
|
|
140
|
31 |
View Code Duplication |
foreach ($operations as $operation) { |
|
|
|
|
|
|
141
|
31 |
|
if (!empty($operation->value)) { |
|
142
|
31 |
|
$fullVersion = self::$wsdlDomXpath[$wsdlIdentifier]->evaluate( |
|
143
|
31 |
|
sprintf(self::XPATH_VERSION_FOR_OPERATION, $operation->value) |
|
144
|
31 |
|
); |
|
145
|
|
|
|
|
146
|
31 |
|
if (!empty($fullVersion)) { |
|
147
|
31 |
|
$extractedVersion = self::extractMessageVersion($fullVersion); |
|
148
|
31 |
|
$msgAndVer[$operation->value] = [ |
|
149
|
31 |
|
'version' => $extractedVersion, |
|
150
|
|
|
'wsdl' => $wsdlIdentifier |
|
151
|
31 |
|
]; |
|
152
|
31 |
|
} |
|
153
|
31 |
|
} |
|
154
|
31 |
|
} |
|
155
|
31 |
|
} |
|
156
|
|
|
|
|
157
|
29 |
|
return $msgAndVer; |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
/** |
|
161
|
|
|
* Get Messages & Versions from an imported WSDL file |
|
162
|
|
|
* |
|
163
|
|
|
* Imported wsdl's are a little different, they require a different query |
|
164
|
|
|
* to extract the version nrs. |
|
165
|
|
|
* |
|
166
|
|
|
* @param string $import |
|
167
|
|
|
* @param string $wsdlPath |
|
168
|
|
|
* @param string $wsdlIdentifier |
|
169
|
|
|
* @return array |
|
170
|
|
|
* @throws InvalidWsdlFileException when the WSDL import could not be loaded. |
|
171
|
|
|
*/ |
|
172
|
2 |
|
protected static function getMessagesAndVersionsFromImportedWsdl($import, $wsdlPath, $wsdlIdentifier) |
|
173
|
|
|
{ |
|
174
|
2 |
|
$msgAndVer = []; |
|
175
|
2 |
|
$domXpath = null; |
|
176
|
|
|
|
|
177
|
2 |
|
$importPath = realpath(dirname($wsdlPath)).DIRECTORY_SEPARATOR.$import; |
|
178
|
2 |
|
$wsdlContent = file_get_contents($importPath); |
|
179
|
|
|
|
|
180
|
2 |
|
if ($wsdlContent !== false) { |
|
181
|
1 |
|
$domDoc = new \DOMDocument('1.0', 'UTF-8'); |
|
182
|
1 |
|
$ok = $domDoc->loadXML($wsdlContent); |
|
183
|
|
|
|
|
184
|
1 |
|
if ($ok === true) { |
|
185
|
1 |
|
$domXpath = new \DOMXPath($domDoc); |
|
186
|
1 |
|
$domXpath->registerNamespace( |
|
187
|
1 |
|
'wsdl', |
|
188
|
|
|
'http://schemas.xmlsoap.org/wsdl/' |
|
189
|
1 |
|
); |
|
190
|
1 |
|
$domXpath->registerNamespace( |
|
191
|
1 |
|
'soap', |
|
192
|
|
|
'http://schemas.xmlsoap.org/wsdl/soap/' |
|
193
|
1 |
|
); |
|
194
|
1 |
|
} |
|
195
|
1 |
|
} else { |
|
196
|
1 |
|
throw new InvalidWsdlFileException('WSDL '.$importPath.' import could not be loaded'); |
|
197
|
|
|
} |
|
198
|
|
|
|
|
199
|
1 |
|
if ($domXpath instanceof \DOMXPath) { |
|
200
|
1 |
|
$nodeList = $domXpath->query(self::XPATH_ALL_OPERATIONS); |
|
201
|
|
|
|
|
202
|
1 |
View Code Duplication |
foreach ($nodeList as $operation) { |
|
|
|
|
|
|
203
|
1 |
|
if (!empty($operation->value)) { |
|
204
|
1 |
|
$fullVersion = $domXpath->evaluate( |
|
205
|
1 |
|
sprintf(self::XPATH_ALT_VERSION_FOR_OPERATION, $operation->value) |
|
206
|
1 |
|
); |
|
207
|
|
|
|
|
208
|
1 |
|
if (!empty($fullVersion)) { |
|
209
|
1 |
|
$extractedVersion = self::extractMessageVersion($fullVersion); |
|
210
|
1 |
|
$msgAndVer[$operation->value] = [ |
|
211
|
1 |
|
'version' => $extractedVersion, |
|
212
|
|
|
'wsdl' => $wsdlIdentifier |
|
213
|
1 |
|
]; |
|
214
|
1 |
|
} |
|
215
|
1 |
|
} |
|
216
|
1 |
|
} |
|
217
|
1 |
|
} |
|
218
|
|
|
|
|
219
|
1 |
|
return $msgAndVer; |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
/** |
|
223
|
|
|
* Load the WSDL contents to a queryable DOMXpath. |
|
224
|
|
|
* |
|
225
|
|
|
* @param string $wsdlFilePath |
|
226
|
|
|
* @param string $wsdlId |
|
227
|
|
|
* @uses $this->wsdlDomDoc |
|
228
|
|
|
* @uses $this->wsdlDomXpath |
|
229
|
|
|
* @throws InvalidWsdlFileException when WSDL cannot be found. |
|
230
|
|
|
*/ |
|
231
|
31 |
|
public static function loadWsdlXpath($wsdlFilePath, $wsdlId) |
|
232
|
|
|
{ |
|
233
|
31 |
|
if (!isset(self::$wsdlDomXpath[$wsdlId]) || is_null(self::$wsdlDomXpath[$wsdlId])) { |
|
234
|
6 |
|
$wsdlContent = file_get_contents($wsdlFilePath); |
|
235
|
|
|
|
|
236
|
6 |
|
if ($wsdlContent !== false) { |
|
237
|
5 |
|
self::$wsdlDomDoc[$wsdlId] = new \DOMDocument('1.0', 'UTF-8'); |
|
238
|
5 |
|
self::$wsdlDomDoc[$wsdlId]->loadXML($wsdlContent); |
|
239
|
5 |
|
self::$wsdlDomXpath[$wsdlId] = new \DOMXPath(self::$wsdlDomDoc[$wsdlId]); |
|
240
|
5 |
|
self::$wsdlDomXpath[$wsdlId]->registerNamespace( |
|
241
|
5 |
|
'wsdl', |
|
242
|
|
|
'http://schemas.xmlsoap.org/wsdl/' |
|
243
|
5 |
|
); |
|
244
|
5 |
|
self::$wsdlDomXpath[$wsdlId]->registerNamespace( |
|
245
|
5 |
|
'soap', |
|
246
|
|
|
'http://schemas.xmlsoap.org/wsdl/soap/' |
|
247
|
5 |
|
); |
|
248
|
5 |
|
} else { |
|
249
|
1 |
|
throw new InvalidWsdlFileException('WSDL '.$wsdlFilePath.' could not be loaded'); |
|
250
|
|
|
} |
|
251
|
5 |
|
} |
|
252
|
31 |
|
} |
|
253
|
|
|
|
|
254
|
|
|
/** |
|
255
|
|
|
* extractMessageVersion |
|
256
|
|
|
* |
|
257
|
|
|
* extracts "4.1" from a string like "Security_SignOut_4_1" |
|
258
|
|
|
* or "1.00" from a string like "tns:AMA_MediaGetMediaRQ_1.000" |
|
259
|
|
|
* |
|
260
|
|
|
* @param string $fullVersionString |
|
261
|
|
|
* @return string |
|
262
|
|
|
*/ |
|
263
|
31 |
|
protected static function extractMessageVersion($fullVersionString) |
|
264
|
|
|
{ |
|
265
|
31 |
|
$marker = strpos($fullVersionString, '_', strpos($fullVersionString, '_') + 1); |
|
266
|
|
|
|
|
267
|
31 |
|
$num = substr($fullVersionString, $marker + 1); |
|
268
|
|
|
|
|
269
|
31 |
|
return str_replace('_', '.', $num); |
|
270
|
|
|
} |
|
271
|
|
|
|
|
272
|
|
|
/** |
|
273
|
|
|
* Generates a unique identifier for a wsdl based on its path. |
|
274
|
|
|
* |
|
275
|
|
|
* @param string $wsdlPath |
|
276
|
|
|
* |
|
277
|
|
|
* @return string |
|
278
|
|
|
*/ |
|
279
|
31 |
|
protected static function makeWsdlIdentifier($wsdlPath) |
|
280
|
|
|
{ |
|
281
|
31 |
|
return sprintf('%x', crc32($wsdlPath)); |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
/** |
|
285
|
|
|
* Evaluate an XPATH query on a given WSDL |
|
286
|
|
|
* |
|
287
|
|
|
* @param string $wsdlId |
|
288
|
|
|
* @param string $wsdlFilePath |
|
289
|
|
|
* @param string $xpath XPATH query |
|
290
|
|
|
* @return string|null |
|
291
|
|
|
*/ |
|
292
|
11 |
|
public static function exaluateXpathQueryOnWsdl($wsdlId, $wsdlFilePath, $xpath) |
|
293
|
|
|
{ |
|
294
|
11 |
|
WsdlAnalyser::loadWsdlXpath($wsdlFilePath, $wsdlId); |
|
295
|
|
|
|
|
296
|
11 |
|
return self::$wsdlDomXpath[$wsdlId]->evaluate($xpath); |
|
297
|
|
|
} |
|
298
|
|
|
} |
|
299
|
|
|
|
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.