Completed
Push — master ( 52f4ed...808c26 )
by Marco
02:51
created

src/Request/XmlProcessor.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
233
234
            // $requested_parameters_count = count($requested_parameters);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
235
236 33
            $requested_parameters_count = count($signature["PARAMETERS"]);
237
238 33
            if ( $provided_parameters_count != $requested_parameters_count ) {
239
240 3
                continue;
241
242
            }
243
244 33
            $index = 0;
245
246 33
            foreach ($signature["PARAMETERS"] as $parameter => $type) {
247
248 21
                if ( !DataValidator::validate($type, $provided_parameters[$index]) ) continue 2;
249
250 21
                $index += 1;
251
252 33
            }
253
254 33
            return $num;
255
256
        }
257
258
        throw new RpcException("Invalid params", -32602);
259
260
    }
261
262
    /**
263
     * Create an associative array of $name => $parameter from current signature
264
     *
265
     * @param array                         $provided
266
     * @param \Comodojo\RpcServer\RpcMethod $method
267
     * @param integer                       $selected_signature
268
     *
269
     * @return array
270
     */
271 33 View Code Duplication
    private static function matchParameters($provided, $method, $selected_signature) {
272
273 33
        $parameters = array();
274
275 33
        $requested_parameters = $method->selectSignature($selected_signature)->getParameters();
276
277 33
        $requested_parameters_keys = array_keys($requested_parameters);
278
279 33
        foreach ( $provided as $index => $parameter ) {
280
281 21
            $parameters[$requested_parameters_keys[$index]] = $parameter;
282
283 33
        }
284
285 33
        return $parameters;
286
287
    }
288
289
    /**
290
     * Preprocess a single xml request
291
     *
292
     * @param array $payload
293
     *
294
     * @return array
295
     */
296 36
    private static function preprocessRequest($payload) {
297
298 36
        return (is_array($payload[0])) ? array('system.multicall', array($payload)) : array($payload[0], $payload[1]);
299
300
    }
301
302
}
303