XmlProcessor   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Test Coverage

Coverage 78.95%

Importance

Changes 0
Metric Value
wmc 20
dl 0
loc 270
ccs 60
cts 76
cp 0.7895
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkRequestConsistence() 0 31 5
A matchParameters() 0 15 2
A checkRequestSustainability() 0 7 2
A __construct() 0 36 3
A process() 0 19 3
A run() 0 48 3
A preprocessRequest() 0 3 2
1
<?php namespace Comodojo\RpcServer\Request;
2
3
use \Comodojo\RpcServer\Request\Parameters;
4
use \Comodojo\RpcServer\RpcMethod;
5
use \Comodojo\Foundation\Validation\DataValidation as Validator;
6
use \Psr\Log\LoggerInterface;
7
use \Comodojo\Exception\RpcException;
8
use \Exception;
9
10
/**
11
 * The XMLRPC processor
12
 *
13
 * @package     Comodojo Spare Parts
14
 * @author      Marco Giovinazzi <[email protected]>
15
 * @license     MIT
16
 *
17
 * LICENSE:
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 * THE SOFTWARE.
26
 */
27
28
class XmlProcessor {
29
30
    /**
31
     * Requested RPC method
32
     *
33
     * @var string
34
     */
35
    private $method;
36
37
    /**
38
     * A parameters object
39
     *
40
     * @var Parameters
41
     */
42
    private $parameters;
43
44
    /**
45
     * Selected method
46
     *
47
     * @var RpcMethod
48
     */
49
    private $registered_method;
50
51
    /**
52
     * Selected signature
53
     *
54
     * @var int
55
     */
56
    private $selected_signature;
57
58
    /**
59
     * Current logger
60
     *
61
     * @var LoggerInterface
62
     */
63
    private $logger;
64
65
    /**
66
     * Class constructor
67
     *
68
     * @param array $payload
69
     * @param Parameters $parameters
70
     * @param LoggerInterface $logger
71
     */
72 39
    public function __construct(array $payload, Parameters $parameters, LoggerInterface $logger) {
73
74 39
        $this->logger = $logger;
75
76 39
        $this->logger->debug("Starting XML processor");
77
78
        try {
79
80 39
            $this->parameters = $parameters;
81
82 39
            list($this->method, $request_parameters) = self::preprocessRequest($payload);
83
84 39
            $this->logger->debug("Current request", array(
85 39
                'METHOD' => $this->method,
86 39
                'PARAMS' => $request_parameters
87
            ));
88
89 39
            $this->registered_method = $this->checkRequestSustainability();
90
91 36
            $this->selected_signature = $this->checkRequestConsistence($request_parameters);
92
93 36
            $parameters = self::matchParameters($request_parameters, $this->registered_method, $this->selected_signature);
94
95 36
            $this->parameters->setParameters($parameters);
96
97 6
        } catch (RpcException $re) {
98
99 6
            $this->logger->warning($re->getMessage());
100
101 6
            throw $re;
102
103
        } catch (Exception $e) {
104
105
            $this->logger->error($e->getMessage());
106
107
            throw $e;
108
109
        }
110
111 36
    }
112
113
    /**
114
     * Run the processor and exec callback(s)
115
     *
116
     * @return mixed
117
     * @throws Exception
118
     */
119 36
    public function run() {
120
121 36
        $callback = $this->registered_method->getCallback();
122 36
        $attributes = $this->registered_method->getArguments();
123 36
        array_unshift($attributes, $this->parameters);
124
125 36
        set_error_handler(
126
127 36
            function($severity, $message, $file, $line) {
128
129
                $this->logger->error($message, array(
130
                    "FILE" => $file,
131
                    "LINE" => $line
132
                ));
133
134
                throw new RpcException('Internal error', -32603);
135
136 36
            }
137
138
        );
139
140
        try {
141
142
            // $return = call_user_func($callback, $this->parameters);
143 36
            $return = call_user_func_array($callback, $attributes);
144
145 3
        } catch (RpcException $re) {
146
147 3
            restore_error_handler();
148
149 3
            throw $re;
150
151
        } catch (Exception $e) {
152
153
            restore_error_handler();
154
155
            $this->logger->error($e->getMessage(), array(
156
                "FILE" => $e->getFile(),
157
                "LINE" => $e->getLine()
158
            ));
159
160
            throw new RpcException('Internal error', -32603);
161
162
        }
163
164 33
        restore_error_handler();
165
166 33
        return $return;
167
168
    }
169
170
    /**
171
     * Static constructor - start processor
172
     *
173
     * @param array $payload
174
     * @param Parameters $parameters
175
     * @param LoggerInterface $logger
176
     *
177
     * @return mixed
178
     * @throws RpcException
179
     * @throws Exception
180
     */
181 39
    public static function process(array $payload, Parameters $parameters, LoggerInterface $logger) {
182
183
        try {
184
185 39
            $processor = new self($payload, $parameters, $logger);
186
187 36
            $return = $processor->run();
188
189 9
        } catch (RpcException $re) {
190
191 9
            throw $re;
192
193
        } catch (Exception $e) {
194
195
            throw $e;
196
197
        }
198
199 33
        return $return;
200
201
    }
202
203
    /**
204
     * Check if a request is sustainable (i.e. if method is registered)
205
     *
206
     * @return RpcMethod
207
     * @throws RpcException
208
     */
209 39
    private function checkRequestSustainability() {
210
211 39
        $method = $this->parameters->methods()->get($this->method);
0 ignored issues
show
Deprecated Code introduced by
The function Comodojo\RpcServer\Request\Parameters::methods() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

211
        $method = /** @scrutinizer ignore-deprecated */ $this->parameters->methods()->get($this->method);
Loading history...
212
213 39
        if ( is_null($method) ) throw new RpcException("Method not found", -32601);
214
215 36
        return $method;
216
217
    }
218
219
    /**
220
     * Check if a request is consistent (i.e. if it matches one of method's signatures)
221
     *
222
     * @param array  $provided_parameters
223
     *
224
     * @return int
225
     * @throws RpcException
226
     */
227 36
    private function checkRequestConsistence(array $provided_parameters) {
228
229 36
        $signatures = $this->registered_method->getSignatures(false);
230
231 36
        $provided_parameters_count = count($provided_parameters);
232
233 36
        foreach ( $signatures as $num=>$signature ) {
234
235 36
            $requested_parameters_count = count($signature["PARAMETERS"]);
236
237 36
            if ( $provided_parameters_count != $requested_parameters_count ) {
238
239 3
                continue;
240
241
            }
242
243 36
            $index = 0;
244
245 36
            foreach ( $signature["PARAMETERS"] as $parameter => $type ) {
246
247 24
                if ( !Validator::validate($provided_parameters[$index], $type) ) continue 2;
248
249 24
                $index += 1;
250
251
            }
252
253 36
            return $num;
254
255
        }
256
257
        throw new RpcException("Invalid params", -32602);
258
259
    }
260
261
    /**
262
     * Create an associative array of $name => $parameter from current signature
263
     *
264
     * @param array $provided
265
     * @param RpcMethod $method
266
     * @param integer $selected_signature
267
     *
268
     * @return array
269
     */
270 36
    private static function matchParameters(array $provided, RpcMethod $method, $selected_signature) {
271
272 36
        $parameters = [];
273
274 36
        $requested_parameters = $method->selectSignature($selected_signature)->getParameters();
275
276 36
        $requested_parameters_keys = array_keys($requested_parameters);
277
278 36
        foreach ( $provided as $index => $parameter ) {
279
280 24
            $parameters[$requested_parameters_keys[$index]] = $parameter;
281
282
        }
283
284 36
        return $parameters;
285
286
    }
287
288
    /**
289
     * Preprocess a single xml request
290
     *
291
     * @param array $payload
292
     *
293
     * @return array
294
     */
295 39
    private static function preprocessRequest(array $payload) {
296
297 39
        return (is_array($payload[0])) ? array('system.multicall', array($payload)) : array($payload[0], $payload[1]);
298
299
    }
300
301
}
302