From 77edbb6fde5424665c12f8b3a91b778b2b4c9ea7 Mon Sep 17 00:00:00 2001 From: Spencer Mortensen Date: Fri, 26 Jul 2019 16:20:13 -0400 Subject: [PATCH] 6.0.0 --- CHANGELOG.md | 7 + README.md | 10 +- composer.json | 4 +- examples/client.php | 110 ++++----- examples/server.php | 9 +- src/Client.php | 211 +++++++++--------- src/Exceptions/ApplicationException.php | 3 - src/Exceptions/ArgumentException.php | 7 +- src/Exceptions/Exception.php | 7 +- src/Exceptions/ImplementationException.php | 3 - src/Exceptions/MethodException.php | 7 +- src/Response.php | 104 --------- .../ErrorResponse.php} | 44 ++-- src/Responses/Response.php | 40 ++++ src/Responses/ResultResponse.php | 56 +++++ src/Server.php | 10 +- tests/ClientTest.php | 15 +- tests/ServerTest.php | 4 +- 18 files changed, 330 insertions(+), 321 deletions(-) delete mode 100644 src/Response.php rename src/{Error.php => Responses/ErrorResponse.php} (60%) create mode 100644 src/Responses/Response.php create mode 100644 src/Responses/ResultResponse.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 912ac24..6f7d411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [6.0.0] - 2019-07-25 +### Changed + - There are now two types of responses--an "ErrorResponse" and a "ResultResponse"-- + which both derive from a base "Response" class. The "Client::decode" method + returns a list of these "Response" objects. You can use the "instanceof" + type operator to see which type of response you have received. + ## [5.0.0] - 2018-05-16 ### Added - The "Client::decode" method now throws an "ErrorException" when the input is not a valid JSON-RPC 2.0 reply string diff --git a/README.md b/README.md index faedf68..1ff9e9e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,9 @@ $client = new Client(); $client->query(1, 'add', array(1, 2)); -$message = $client->encode(); // {"jsonrpc":"2.0","id":1,"method":"add","params":[1,2]} +$message = $client->encode(); + +// message: {"jsonrpc":"2.0","method":"add","params":[1,2],"id":1} ``` ### Server @@ -47,7 +49,9 @@ $api = new Api(); $server = new Server($api); -$reply = $server->reply($message); // {"jsonrpc":"2.0","id":1,"result":3} +$reply = $server->reply($message); + +// reply: {"jsonrpc":"2.0","result":3,"id":1} ``` *See the [examples](https://github.com/datto/php-json-rpc/tree/master/examples) folder for full working examples.* @@ -55,7 +59,7 @@ $reply = $server->reply($message); // {"jsonrpc":"2.0","id":1,"result":3} ## Requirements -* PHP >= 5.3 +* PHP >= 7.0 ## License diff --git a/composer.json b/composer.json index 527d0eb..27ec6a8 100644 --- a/composer.json +++ b/composer.json @@ -14,10 +14,10 @@ } ], "require": { - "php": ">=5.3.0" + "php": ">=7.0.0" }, "require-dev": { - "phpunit/phpunit": "~3.7" + "phpunit/phpunit": "^6.5" }, "autoload": { "psr-4": { diff --git a/examples/client.php b/examples/client.php index ae98910..fe55f17 100644 --- a/examples/client.php +++ b/examples/client.php @@ -1,84 +1,88 @@ query(1, 'add', array(1, 2)); - $message = $client->encode(); -echo "Example 1. Single query:\n{$message}\n\n"; -// {"jsonrpc":"2.0","id":1,"method":"add","params":[1,2]} - +echo "Example 1. Send a single query:\n", + " \$client = new Client();\n", + " \$client->query(1, 'add', array(1, 2));\n", + " \$message = \$client->encode();\n", + " // message: {$message}\n\n"; + // message: {"jsonrpc":"2.0","method":"add","params":[1,2],"id":1} -// Example 2. Batch queries +// Example 2. Send multiple queries together in a batch: $client = new Client(); - $client->query(1, 'add', array(1, 2)); $client->query(2, 'add', array('a', 'b')); - $message = $client->encode(); -echo "Example 2. Batch queries:\n{$message}\n\n"; -// [{"jsonrpc":"2.0","id":1,"method":"add","params":[1,2]},{"jsonrpc":"2.0","id":2,"method":"add","params":["a","b"]}] - +echo "Example 2. Send multiple queries together in a batch:\n", + " \$client = new Client();\n", + " \$client->query(1, 'add', array(1, 2));\n", + " \$client->query(2, 'add', array('a', 'b'));\n", + " \$message = \$client->encode();\n", + " // message: {$message}\n\n"; + // message: [{"jsonrpc":"2.0","id":1,"method":"add","params":[1,2]},{"jsonrpc":"2.0","id":2,"method":"add","params":["a","b"]}] -// Example 3. Valid server response +// Example 3. Send a notification (where no response is required): $client = new Client(); +$client->notify('add', array(1, 2)); +$message = $client->encode(); -$reply = '[{"jsonrpc":"2.0","id":1,"result":3},{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"Invalid params"}}]'; - -$responses = $client->decode($reply); - -echo "Example 3. Valid server response:\n"; -foreach ($responses as $response) { - $id = $response->getId(); - $isError = $response->isError(); - - if ($isError) { - $error = $response->getError(); - - $errorProperties = array( - 'code' => $error->getCode(), - 'message' => $error->getMessage(), - 'data' => $error->getData() - ); - - echo " * id: {$id}, error: ", json_encode($errorProperties), "\n"; - } else { - $result = $response->getResult(); +echo "Example 3. Send a notification (where no response is required):\n", + " \$client = new Client();\n", + " \$client->notify('add', array(1, 2));\n", + " \$message = \$client->encode();\n", + " // message: {$message}\n\n"; + // message: {"jsonrpc":"2.0","method":"add","params":[1,2]} - echo " * id: {$id}, result: ", json_encode($result), "\n"; - } -} -echo "\n"; -// * id: 1, result: 3 -// * id: 2, error: {"code":-32602,"message":"Invalid params","data":null} +// Example 4. Receive a single response: +$client = new Client(); +$reply = '{"jsonrpc":"2.0","id":1,"result":3}'; +$responses = $client->decode($reply); +echo "Example 4. Receive a single response:\n", + " \$client = new Client();\n", + " \$reply = '{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":3}';\n", + " \$responses = \$client->decode(\$reply);\n", + " // responses: [new ResultResponse(1, 3)]\n\n"; -// Example 4. Invalid server response +// Example 5. Receive a batch of responses: $client = new Client(); +$reply = '[{"jsonrpc":"2.0","id":1,"result":3},{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"Invalid params"}}]'; +$responses = $client->decode($reply); -$reply = '{"jsonrpc":"2.0","id":'; - -try { - $responses = $client->decode($reply); -} catch (ErrorException $exception) { - echo "Example 3. Invalid server response:\n"; - $exceptionProperties = array( - 'code' => $exception->getCode(), - 'message' => $exception->getMessage() - ); +echo "Example 5. Receive a batch of responses:\n", + " \$client = new Client();\n", + " \$reply = '[{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":3},{\"jsonrpc\":\"2.0\",\"id\":2,\"error\":{\"code\":-32602,\"message\":\"Invalid params\"}}]';\n", + " \$responses = \$client->decode(\$reply);\n", + " // responses: [new ResultResponse(1, 3), new ErrorResponse(2, 'Invalid params', -32602)]\n"; - echo "ErrorException: ", json_encode($exceptionProperties), "\n"; +foreach ($responses as $response) { + if ($response instanceof ResultResponse) { + $result = [ + 'id' => $response->getId(), + 'value' => $response->getValue() + ]; + } elseif ($response instanceof ErrorResponse) { + $error = [ + 'id' => $response->getId(), + 'message' => $response->getMessage(), + 'code' => $response->getCode(), + 'data' => $response->getData() + ]; + } } diff --git a/examples/server.php b/examples/server.php index d0921b1..1433759 100644 --- a/examples/server.php +++ b/examples/server.php @@ -5,9 +5,12 @@ require_once __DIR__ . '/../vendor/autoload.php'; - +// Example 1. Send a reply: $server = new Server(new Api()); - $reply = $server->reply('{"jsonrpc":"2.0","id":1,"method":"add","params":[1,2]}'); -echo $reply, "\n"; // {"jsonrpc":"2.0","id":1,"result":3} +echo "Example 1. Send a reply:\n", + " \$server = new Server(new Api());\n", + " \$reply = \$server->reply('{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"add\",\"params\":[1,2]}');\n", + " // reply: {$reply}\n"; + // reply: {"jsonrpc":"2.0","id":1,"result":3} diff --git a/src/Client.php b/src/Client.php index 1cf84d1..7ef6072 100644 --- a/src/Client.php +++ b/src/Client.php @@ -24,11 +24,12 @@ namespace Datto\JsonRpc; +use Datto\JsonRpc\Responses\ErrorResponse; +use Datto\JsonRpc\Responses\Response; +use Datto\JsonRpc\Responses\ResultResponse; use ErrorException; /** - * Class Client - * * @link http://www.jsonrpc.org/specification JSON-RPC 2.0 Specifications * * @package Datto\JsonRpc @@ -39,34 +40,36 @@ class Client const VERSION = '2.0'; /** @var array */ - private $messages; + private $requests; public function __construct() { - $this->messages = array(); + $this->reset(); + } + + /** + * Forget any unsent queries or notifications + */ + public function reset() + { + $this->requests = []; } /** * @param mixed $id * @param string $method - * @param array $arguments + * @param array $arguments|null * * @return self - * Returns the object handle, so you can chain method calls if you like + * Returns the object handle (so you can chain method calls, if you like) */ - public function query($id, $method, array $arguments) + public function query($id, string $method, array $arguments = null): self { - $message = array( - 'jsonrpc' => self::VERSION, - 'id' => $id, - 'method' => $method - ); + $request = self::getRequest($method, $arguments); + $request['id'] = $id; - if ($arguments !== null) { - $message['params'] = $arguments; - } + $this->requests[] = $request; - $this->messages[] = $message; return $this; } @@ -75,20 +78,14 @@ public function query($id, $method, array $arguments) * @param array $arguments * * @return self - * Returns the object handle, so you can chain method calls if you like + * Returns the object handle (so you can chain method calls, if you like) */ - public function notify($method, array $arguments) + public function notify($method, array $arguments = null): self { - $message = array( - 'jsonrpc' => self::VERSION, - 'method' => $method - ); + $request = self::getRequest($method, $arguments); - if ($arguments !== null) { - $message['params'] = $arguments; - } + $this->requests[] = $request; - $this->messages[] = $message; return $this; } @@ -104,28 +101,28 @@ public function notify($method, array $arguments) */ public function encode() { - $count = count($this->messages); + $count = count($this->requests); if ($count === 0) { return null; } if ($count === 1) { - $output = array_shift($this->messages); + $input = array_shift($this->requests); } else { - $output = $this->messages; + $input = $this->requests; } - $this->messages = array(); + $this->reset(); - return json_encode($output); + return json_encode($input); } /** * Translates a JSON-RPC 2.0 server reply into an array of "Response" * objects * - * @param string $input + * @param string $json * String reply from a JSON-RPC 2.0 server * * @return Response[] @@ -134,58 +131,84 @@ public function encode() * @throws ErrorException * Throws an "ErrorException" if the reply was not well-formed */ - public function decode($input) + public function decode(string $json) { set_error_handler(__CLASS__ . '::onError'); - $value = json_decode($input, true); - restore_error_handler(); - if (($value === null) && (strtolower(trim($input)) !== 'null')) { - $valuePhp = self::getValuePhp($input); - throw new ErrorException("Invalid JSON: {$valuePhp}"); + try { + $input = json_decode($json, true); + } finally { + restore_error_handler(); } - if (!$this->getReply($value, $output)) { - $valuePhp = self::getValuePhp($input); - throw new ErrorException("Invalid JSON-RPC 2.0 response: {$valuePhp}"); + if (($input === null) && (strtolower(trim($json)) !== 'null')) { + $valueText = self::getValueText($json); + throw new ErrorException("Invalid JSON: {$valueText}"); } - return $output; + if (!$this->getResponses($input, $responses)) { + $valueText = self::getValueText($json); + throw new ErrorException("Invalid JSON-RPC 2.0 response: {$valueText}"); + } + + return $responses; + } + + private static function getRequest(string $method, array $arguments = null): array + { + $request = [ + 'jsonrpc' => self::VERSION, + 'method' => $method + ]; + + if ($arguments !== null) { + $request['params'] = $arguments; + } + + return $request; } - private static function getValuePhp($value) + private static function getValueText($value): string { if (is_null($value)) { return 'null'; } if (is_resource($value)) { + $type = get_resource_type($value); $id = (int)$value; - return "resource({$id})"; + return "{$type}#{$id}"; } return var_export($value, true); } - private function getReply($input, &$output) + private function getResponses($input, array &$responses = null): bool { if ($this->getResponse($input, $response)) { - $output = array($response); + $responses = [$response]; return true; } - return $this->getBatchResponses($input, $output); + return $this->getBatchResponses($input, $responses); + } + + private function getResponse($input, &$response) + { + return $this->getResultResponse($input, $response) || + $this->getErrorResponse($input, $response); } - private function getResponse($input, &$output) + private function getResultResponse($input, &$response) { if ( is_array($input) && + !array_key_exists('error', $input) && $this->getVersion($input) && $this->getId($input, $id) && - $this->getValue($input, $value, $isError) + $this->getResult($input, $value) ) { - $output = new Response($id, $value, $isError); + $response = new ResultResponse($id, $value); return true; } @@ -194,100 +217,83 @@ private function getResponse($input, &$output) private function getVersion(array $input) { - return isset($input['jsonrpc']) && ($input['jsonrpc'] === '2.0'); + return isset($input['jsonrpc']) && ($input['jsonrpc'] === self::VERSION); } private function getId(array $input, &$id) { - if (!array_key_exists('id', $input)) { - return false; + if (array_key_exists('id', $input)) { + $id = $input['id']; + return is_null($id) || is_int($id) || is_float($id) || is_string($id); } - $id = $input['id']; - - return is_null($id) || is_int($id) || is_float($id) || is_string($id); - } - - private function getValue($input, &$value, &$isError) - { - return $this->getResult($input, $value, $isError) || - $this->getError($input, $value, $isError); + return false; } - private function getResult(array $input, &$value, &$isError) + private function getResult(array $input, &$value) { - if (!array_key_exists('result', $input)) { - return false; + if (array_key_exists('result', $input)) { + $value = $input['result']; + return true; } - $value = $input['result']; - $isError = false; - - return true; + return false; } - private function getError(array $input, &$value, &$isError) + private function getErrorResponse(array &$input, &$response) { - if (!isset($input['error'])) { - return false; - } - - $error = $input['error']; - if ( - is_array($error) && - $this->getMessage($error, $message) && - $this->getCode($error, $code) && - $this->getData($error, $data) + is_array($input) && + !array_key_exists('result', $input) && + $this->getVersion($input) && + $this->getId($input, $id) && + $this->getError($input, $code, $message, $data) ) { - $value = new Error($message, $code, $data); - $isError = true; + $response = new ErrorResponse($id, $message, $code, $data); return true; } return false; } - private function getCode(array $input, &$code) + private function getError(array $input, &$code, &$message, &$data) { - if (!isset($input['code'])) { - return false; - } + $error = $input['error'] ?? null; + + return is_array($error) && + $this->getErrorCode($error, $code) && + $this->getErrorMessage($error, $message) && + $this->getErrorData($error, $data); + } - $code = $input['code']; + private function getErrorCode(array $input, &$code) + { + $code = $input['code'] ?? null; return is_int($code); } - private function getMessage(array $input, &$message) + private function getErrorMessage(array $input, &$message) { - if (!isset($input['message'])) { - return false; - } - - $message = $input['message']; + $message = $input['message'] ?? null; return is_string($message); } - private function getData(array $input, &$data) + private function getErrorData(array $input, &$data) { - if (array_key_exists('data', $input)) { - $data = $input['data']; - } else { - $data = null; - } + $data = $input['data'] ?? null; return true; } - private function getBatchResponses($input, &$output) + private function getBatchResponses($input, &$responses) { if (!is_array($input)) { return false; } - $results = array(); + $responses = []; $i = 0; foreach ($input as $key => $value) { @@ -295,12 +301,11 @@ private function getBatchResponses($input, &$output) return false; } - if (!$this->getResponse($value, $results[])) { + if (!$this->getResponse($value, $responses[])) { return false; } } - $output = $results; return true; } diff --git a/src/Exceptions/ApplicationException.php b/src/Exceptions/ApplicationException.php index 520b2cd..f5ad8b5 100644 --- a/src/Exceptions/ApplicationException.php +++ b/src/Exceptions/ApplicationException.php @@ -25,9 +25,6 @@ namespace Datto\JsonRpc\Exceptions; /** - * Class ApplicationException - * @package Datto\JsonRpc\Exceptions - * * If a method cannot be called (e.g. if the method doesn't exist, or is a * private method), then you should throw a "MethodException". * diff --git a/src/Exceptions/ArgumentException.php b/src/Exceptions/ArgumentException.php index 0345b3a..e01cdb8 100644 --- a/src/Exceptions/ArgumentException.php +++ b/src/Exceptions/ArgumentException.php @@ -24,10 +24,9 @@ namespace Datto\JsonRpc\Exceptions; +use Datto\JsonRpc\Responses\ErrorResponse; + /** - * Class ArgumentException - * @package Datto\JsonRpc\Exceptions - * * If a method cannot be called (e.g. if the method doesn't exist, or is a * private method), then you should throw a "MethodException". * @@ -49,6 +48,6 @@ class ArgumentException extends Exception { public function __construct() { - parent::__construct('Invalid params', -32602); + parent::__construct('Invalid params', ErrorResponse::INVALID_ARGUMENTS); } } diff --git a/src/Exceptions/Exception.php b/src/Exceptions/Exception.php index 1f94da1..f9d7776 100644 --- a/src/Exceptions/Exception.php +++ b/src/Exceptions/Exception.php @@ -27,9 +27,6 @@ use Exception as BaseException; /** - * Class Exception - * @package Datto\JsonRpc\Exceptions - * * If a method cannot be called (e.g. if the method doesn't exist, or is a * private method), then you should throw a "MethodException". * @@ -60,13 +57,15 @@ abstract class Exception extends BaseException * @param int $code * Integer identifying the type of error that occurred. This code MUST * follow the JSON-RPC 2.0 requirements for error codes: - * @link http://www.jsonrpc.org/specification#error_object * * @param null|boolean|integer|float|string|array $data * An optional primitive value that contains additional information about * the error.You're free to define the format of this data (e.g. you could * supply an array with detailed error information). Alternatively, you may * omit this field by supplying a null value. + * + * @link http://www.jsonrpc.org/specification#error_object + * */ public function __construct($message, $code, $data = null) { diff --git a/src/Exceptions/ImplementationException.php b/src/Exceptions/ImplementationException.php index 8a2b2da..57dfe99 100644 --- a/src/Exceptions/ImplementationException.php +++ b/src/Exceptions/ImplementationException.php @@ -25,9 +25,6 @@ namespace Datto\JsonRpc\Exceptions; /** - * Class ImplementationException - * @package Datto\JsonRpc\Exceptions - * * If a method cannot be called (e.g. if the method doesn't exist, or is a * private method), then you should throw a "MethodException". * diff --git a/src/Exceptions/MethodException.php b/src/Exceptions/MethodException.php index 4617f61..2b5f692 100644 --- a/src/Exceptions/MethodException.php +++ b/src/Exceptions/MethodException.php @@ -24,10 +24,9 @@ namespace Datto\JsonRpc\Exceptions; +use Datto\JsonRpc\Responses\ErrorResponse; + /** - * Class MethodException - * @package Datto\JsonRpc\Exceptions - * * If a method cannot be called (e.g. if the method doesn't exist, or is a * private method), then you should throw a "MethodException". * @@ -49,6 +48,6 @@ class MethodException extends Exception { public function __construct() { - parent::__construct('Method not found', -32601); + parent::__construct('Method not found', ErrorResponse::INVALID_METHOD); } } diff --git a/src/Response.php b/src/Response.php deleted file mode 100644 index 5efff65..0000000 --- a/src/Response.php +++ /dev/null @@ -1,104 +0,0 @@ -. - * - * @author Spencer Mortensen - * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 - * @copyright 2015 Datto, Inc. - */ - -namespace Datto\JsonRpc; - -/** - * Class Response - * @package Datto\JsonRpc - * - * A response from the server - * - * @link http://www.jsonrpc.org/specification#response_object - */ -class Response -{ - /** @var null|int|float|string */ - private $id; - - /** @var bool */ - private $isError; - - /** @var null|int|float|string|array */ - private $result; - - /** @var Error|null */ - private $error; - - public function __construct($id, $value, $isError) - { - if ($isError) { - $result = null; - $error = $value; - } else { - $result = $value; - $error = null; - } - - $this->id = $id; - $this->result = $result; - $this->error = $error; - $this->isError = $isError; - } - - /** - * @return null|int|float|string - * A unique identifier, used to match this server response with an earlier - * user request - */ - public function getId() - { - return $this->id; - } - - /** - * A response will contain either an error object, or a result, but not both. - * - * @return bool - * True iff the response contains an error object - * False iff the response contains a result - */ - public function isError() - { - return $this->isError; - } - - /** - * @return null|int|float|string|array - * The result returned by the server (if applicable) - */ - public function getResult() - { - return $this->result; - } - - /** - * @return Error|null - * An error object describing the server issue (if applicable) - */ - public function getError() - { - return $this->error; - } -} diff --git a/src/Error.php b/src/Responses/ErrorResponse.php similarity index 60% rename from src/Error.php rename to src/Responses/ErrorResponse.php index ded21bc..42e1268 100644 --- a/src/Error.php +++ b/src/Responses/ErrorResponse.php @@ -22,54 +22,62 @@ * @copyright 2015 Datto, Inc. */ -namespace Datto\JsonRpc; +namespace Datto\JsonRpc\Responses; /** - * Class Error - * @package Datto\JsonRpc - * * A description of an error that occurred on the server * - * @link http://www.jsonrpc.org/specification#error_object + * @link https://www.jsonrpc.org/specification#error_object */ -class Error +class ErrorResponse extends Response { + const PARSE_ERROR = -32700; + const INVALID_ARGUMENTS = -32602; + const INVALID_METHOD = -32601; + const INVALID_REQUEST = -32600; + + /** @var string */ private $message; + /** @var int */ private $code; + /** @var mixed */ private $data; /** - * @param $message - * Short description of the error that occurred. This message SHOULD - * be limited to a single, concise sentence. + * @param mixed $id + * A unique identifier. This MUST be the same as the original request id. + * If there was an error while processing the request, then this MUST be null. + * + * @param string $message + * Short description of the error that occurred. This message SHOULD + * be limited to a single, concise sentence. * * @param int $code * Integer identifying the type of error that occurred. * * @param null|boolean|integer|float|string|array $data - * An optional primitive value that contains additional information about + * An optional primitive value that contains additional information about * the error. */ - public function __construct($message, $code, $data) + public function __construct($id, string $message, int $code, $data = null) { + parent::__construct($id); + $this->message = $message; $this->code = $code; $this->data = $data; } - /** - * @return mixed - */ - public function getCode() + public function getMessage(): string { - return $this->code; + return $this->message; } - public function getMessage() + public function getCode(): int { - return $this->message; + return $this->code; } public function getData() diff --git a/src/Responses/Response.php b/src/Responses/Response.php new file mode 100644 index 0000000..c563c6f --- /dev/null +++ b/src/Responses/Response.php @@ -0,0 +1,40 @@ +. + * + * @author Spencer Mortensen + * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 + * @copyright 2015 Datto, Inc. + */ + +namespace Datto\JsonRpc\Responses; + +abstract class Response +{ + private $id; + + public function __construct($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } +} diff --git a/src/Responses/ResultResponse.php b/src/Responses/ResultResponse.php new file mode 100644 index 0000000..951f3cf --- /dev/null +++ b/src/Responses/ResultResponse.php @@ -0,0 +1,56 @@ +. + * + * @author Spencer Mortensen + * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 + * @copyright 2015 Datto, Inc. + */ + +namespace Datto\JsonRpc\Responses; + +/** + * The result returned by the server + * + * @link https://www.jsonrpc.org/specification#response_object + */ +class ResultResponse extends Response +{ + /** @var mixed */ + private $value; + + /** + * @param mixed $id + * A unique identifier. This MUST be the same as the original request id. + * If there was an error while processing the request, then this MUST be null. + * + * @param mixed $value + * The value returned by the server. + */ + public function __construct($id, $value) + { + parent::__construct($id); + + $this->value = $value; + } + + public function getValue() + { + return $this->value; + } +} diff --git a/src/Server.php b/src/Server.php index 538fe19..d64b663 100644 --- a/src/Server.php +++ b/src/Server.php @@ -25,16 +25,14 @@ namespace Datto\JsonRpc; use Datto\JsonRpc\Exceptions\Exception; +use Datto\JsonRpc\Responses\ErrorResponse; /** - * Class Server - * * @link http://www.jsonrpc.org/specification JSON-RPC 2.0 Specifications - * - * @package Datto\JsonRpc */ class Server { + /** @var string */ const VERSION = '2.0'; /** @var Evaluator */ @@ -251,7 +249,7 @@ private function processNotification($method, $arguments) */ private function parseError() { - return $this->error(null, -32700, 'Parse error'); + return $this->error(null, ErrorResponse::PARSE_ERROR, 'Parse error'); } /** @@ -267,7 +265,7 @@ private function parseError() */ private function requestError($id = null) { - return $this->error($id, -32600, 'Invalid Request'); + return $this->error($id, ErrorResponse::INVALID_REQUEST, 'Invalid Request'); } /** diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 0510d0f..ce6481c 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -24,12 +24,12 @@ namespace Datto\JsonRpc\Tests; -use PHPUnit_Framework_TestCase; +use PHPUnit\Framework\TestCase; use Datto\JsonRpc\Client; -use Datto\JsonRpc\Response; -use Datto\JsonRpc\Error; +use Datto\JsonRpc\Responses\ResultResponse; +use Datto\JsonRpc\Responses\ErrorResponse; -class ClientTest extends PHPUnit_Framework_TestCase +class ClientTest extends TestCase { public function testNotification() { @@ -78,8 +78,7 @@ public function testDecodeResult() $client = new Client(); $actualOutput = $client->decode($reply); - $response = new Response(1, 2, false); - $expectedOutput = array($response); + $expectedOutput = [new ResultResponse(1, 2)]; $this->assertSameValues($expectedOutput, $actualOutput); } @@ -90,9 +89,7 @@ public function testDecodeError() $client = new Client(); $actualOutput = $client->decode($reply); - $error = new Error('Method not found', -32601, null); - $response = new Response(1, $error, true); - $expectedOutput = array($response); + $expectedOutput = [new ErrorResponse(1, 'Method not found', -32601)]; $this->assertSameValues($expectedOutput, $actualOutput); } diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 1cc5b65..181456c 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -24,10 +24,10 @@ namespace Datto\JsonRpc\Tests; -use PHPUnit_Framework_TestCase; +use PHPUnit\Framework\TestCase; use Datto\JsonRpc\Server; -class ServerTest extends PHPUnit_Framework_TestCase +class ServerTest extends TestCase { public function testArgumentsPositionalA() {