Completed
Pull Request — master (#43)
by Dieter
13:45
created

StandardResponseHandler   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 210
Duplicated Lines 7.62 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 15
lcom 1
cbo 4
dl 16
loc 210
ccs 90
cts 90
cp 1
rs 10
c 1
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
B analyzeWithErrCodeCategoryMsgQuery() 0 27 3
B analyzeWithErrCodeCategoryMsgNodeName() 16 27 3
A analyzeSimpleResponseErrorCodeAndMessage() 0 9 1
A analyzeSimpleResponseErrorCodeAndMessageStatusCode() 0 9 1
A makeDomXpath() 0 12 1
A loadDomDocument() 0 11 2
B makeStatusFromErrorQualifier() 0 25 3
A makeMessageFromMessagesNodeList() 0 12 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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)) {
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...
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