Passed
Push — php8 ( 7ef3e2...94505a )
by Fabio
07:04 queued 01:51
created

TJsonRpcProtocol::checkJsonError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 5
rs 10
1
<?php
2
/**
3
 * @author Robin J. Rogge <[email protected]>
4
 * @link https://github.com/pradosoft/prado
5
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
6
 * @since 3.2
7
 */
8
9
namespace Prado\Web\Services;
10
11
use Prado\Exceptions\THttpException;
12
use Prado\Web\THttpResponse;
13
use Prado\Web\Javascripts\TJavaScript;
14
15
/**
16
 * TJsonRpcProtocol class
17
 *
18
 * TJsonRpcProtocol is a class that implements JSON-Rpc protocol in {@link TRpcService}.
19
 * Both version 1.0 and 2.0 of the specification are implemented, and the server will try
20
 * to answer using the same version of the protocol used by the requesting client.
21
 *
22
 * @author Robin J. Rogge <[email protected]>
23
 * @author Fabio Bas <[email protected]>
24
 * @since 3.2
25
 */
26
class TJsonRpcProtocol extends TRpcProtocol
27
{
28
	protected $_id;
29
	protected $_specificationVersion = 1.0;
30
31
	/**
32
	 * Handles the RPC request
33
	 * @param string $requestPayload $requestPayload
34
	 * @throws TRpcException
35
	 * @return string JSON RPC response
36
	 */
37
	public function callMethod($requestPayload)
38
	{
39
		try {
40
			$_request = $this->decode($requestPayload);
41
42
			if (isset($_request['jsonrpc'])) {
43
				$this->_specificationVersion = $_request['jsonrpc'];
44
				if ($this->_specificationVersion > 2.0) {
45
					throw new TRpcException('Unsupported specification version', '-32600');
46
				}
47
			}
48
49
			if (isset($_request['id'])) {
50
				$this->_id = $_request['id'];
51
			}
52
53
			if (!isset($_request['method'])) {
54
				throw new TRpcException('Missing request method', '-32600');
55
			}
56
57
			if (!isset($_request['params'])) {
58
				$parameters = [];
59
			} else {
60
				$parameters = $_request['params'];
61
			}
62
63
			if (!is_array($parameters)) {
64
				$parameters = [$parameters];
65
			}
66
67
			// a request without an id is a notification that doesn't need a response
68
			if ($this->_id !== null) {
69
				if ($this->_specificationVersion == 2.0) {
70
					return $this->encode([
71
						'jsonrpc' => '2.0',
72
						'id' => $this->_id,
73
						'result' => $this->callApiMethod($_request['method'], $parameters),
74
					]);
75
				} else {
76
					return $this->encode([
77
						'id' => $this->_id,
78
						'result' => $this->callApiMethod($_request['method'], $_request['params']),
79
						'error' => null,
80
					]);
81
				}
82
			}
83
		} catch (TRpcException $e) {
84
			return $this->createErrorResponse($e);
85
		} catch (THttpException $e) {
86
			throw $e;
87
		} catch (\Exception $e) {
88
			return $this->createErrorResponse(new TRpcException('An internal error occured', '-32603'));
89
		}
90
		return '';
91
	}
92
93
	/**
94
	 * Turns the given exception into an JSON RPC fault
95
	 * @param TRpcException $exception
96
	 * @return string JSON RPC fault
97
	 */
98
	public function createErrorResponse(TRpcException $exception)
99
	{
100
		if ($this->_specificationVersion == 2.0) {
101
			return $this->encode([
102
				'id' => $this->_id,
103
				'result' => null,
104
				'error' => [
105
					'code' => $exception->getCode(),
106
					'message' => $exception->getMessage(),
107
					'data' => null,
108
					],
109
			]);
110
		} else {
111
			return $this->encode([
112
				'id' => $this->_id,
113
				'error' => [
114
					'code' => $exception->getCode(),
115
					'message' => $exception->getMessage(),
116
					'data' => null,
117
					],
118
			]);
119
		}
120
	}
121
122
	/**
123
	 * Sets the correct response headers
124
	 * @param THttpResponse $response
125
	 */
126
	public function createResponseHeaders($response)
127
	{
128
		$response->setContentType('application/json');
129
		$response->setCharset('UTF-8');
130
	}
131
132
	/**
133
	 * Decodes JSON encoded data into PHP data
134
	 * @param string $data $data in JSON format
135
	 * @return array PHP data
136
	 */
137
	public function decode($data)
138
	{
139
		return TJavaScript::jsonDecode($data, true);
140
	}
141
142
	/**
143
	 * Encodes PHP data into JSON data
144
	 * @param mixed $data PHP data
145
	 * @return string JSON encoded PHP data
146
	 */
147
	public function encode($data)
148
	{
149
		return TJavaScript::jsonEncode($data);
150
	}
151
152
	/**
153
	 * Calls the callback handler for the given method
154
	 * Overrides parent implementation to correctly handle error codes
155
	 * @param string $methodName of the RPC
156
	 * @param array $parameters for the callback handler as provided by the client
157
	 * @return mixed whatever the callback handler returns
158
	 */
159
	public function callApiMethod($methodName, $parameters)
160
	{
161
		if (!isset($this->rpcMethods[$methodName])) {
162
			throw new TRpcException('Method "' . $methodName . '" not found', '-32601');
163
		}
164
165
		return call_user_func_array($this->rpcMethods[$methodName]['method'], $parameters);
166
	}
167
}
168