Update JsonRPC library

This commit is contained in:
Frederic Guillot 2016-08-05 20:27:09 -04:00
parent 0b4ee5d347
commit caa91dbf06
No known key found for this signature in database
GPG Key ID: 92D77191BA7FBC99
15 changed files with 569 additions and 264 deletions

View File

@ -13,7 +13,7 @@
}, },
"require": { "require": {
"fguillot/simple-validator": "v1.0.0", "fguillot/simple-validator": "v1.0.0",
"fguillot/json-rpc": "v1.1.0", "fguillot/json-rpc": "v1.2.1",
"fguillot/picodb": "v1.0.14 ", "fguillot/picodb": "v1.0.14 ",
"fguillot/picofeed": "v0.1.24", "fguillot/picofeed": "v0.1.24",
"pda/pheanstalk": "v3.1.0" "pda/pheanstalk": "v3.1.0"

View File

@ -11,13 +11,15 @@ $server->authentication(array(
Config\get('username') => Config\get('api_token') Config\get('username') => Config\get('api_token')
)); ));
$procedureHandler = $server->getProcedureHandler();
// Get version // Get version
$server->register('app.version', function () { $procedureHandler->withCallback('app.version', function () {
return array('version' => APP_VERSION); return array('version' => APP_VERSION);
}); });
// Get all feeds // Get all feeds
$server->register('feed.list', function () { $procedureHandler->withCallback('feed.list', function () {
$feeds = Model\Feed\get_all(); $feeds = Model\Feed\get_all();
if (empty($feeds)) { if (empty($feeds)) {
return array(); return array();
@ -36,14 +38,14 @@ $server->register('feed.list', function () {
}); });
// Get one feed // Get one feed
$server->register('feed.info', function ($feed_id) { $procedureHandler->withCallback('feed.info', function ($feed_id) {
$result = Model\Feed\get($feed_id); $result = Model\Feed\get($feed_id);
$result['feed_group_ids'] = Model\Group\get_feed_group_ids($feed_id); $result['feed_group_ids'] = Model\Group\get_feed_group_ids($feed_id);
return $result; return $result;
}); });
// Add a new feed // Add a new feed
$server->register('feed.create', function($url) { $procedureHandler->withCallback('feed.create', function($url) {
try { try {
$result = Model\Feed\create($url); $result = Model\Feed\create($url);
} catch (Exception $e) { } catch (Exception $e) {
@ -56,172 +58,172 @@ $server->register('feed.create', function($url) {
}); });
// Delete a feed // Delete a feed
$server->register('feed.delete', function($feed_id) { $procedureHandler->withCallback('feed.delete', function($feed_id) {
return Model\Feed\remove($feed_id); return Model\Feed\remove($feed_id);
}); });
// Delete all feeds // Delete all feeds
$server->register('feed.delete_all', function() { $procedureHandler->withCallback('feed.delete_all', function() {
return Model\Feed\remove_all(); return Model\Feed\remove_all();
}); });
// Enable a feed // Enable a feed
$server->register('feed.enable', function($feed_id) { $procedureHandler->withCallback('feed.enable', function($feed_id) {
return Model\Feed\enable($feed_id); return Model\Feed\enable($feed_id);
}); });
// Disable a feed // Disable a feed
$server->register('feed.disable', function($feed_id) { $procedureHandler->withCallback('feed.disable', function($feed_id) {
return Model\Feed\disable($feed_id); return Model\Feed\disable($feed_id);
}); });
// Update a feed // Update a feed
$server->register('feed.update', function($feed_id) { $procedureHandler->withCallback('feed.update', function($feed_id) {
return Model\Feed\refresh($feed_id); return Model\Feed\refresh($feed_id);
}); });
// Get all groups // Get all groups
$server->register('group.list', function () { $procedureHandler->withCallback('group.list', function () {
return Model\Group\get_all(); return Model\Group\get_all();
}); });
// Add a new group // Add a new group
$server->register('group.create', function($title) { $procedureHandler->withCallback('group.create', function($title) {
return Model\Group\create($title); return Model\Group\create($title);
}); });
// Get assoc array of group ids with assigned feeds ids // Get assoc array of group ids with assigned feeds ids
$server->register('group.map', function() { $procedureHandler->withCallback('group.map', function() {
return Model\Group\get_map(); return Model\Group\get_map();
}); });
// Get the id of a group // Get the id of a group
$server->register('group.id', function($title) { $procedureHandler->withCallback('group.id', function($title) {
return Model\Group\get_group_id($title); return Model\Group\get_group_id($title);
}); });
// Get all feed ids assigned to a group // Get all feed ids assigned to a group
$server->register('group.feeds', function($group_id) { $procedureHandler->withCallback('group.feeds', function($group_id) {
return Model\Group\get_feeds_by_group($group_id); return Model\Group\get_feeds_by_group($group_id);
}); });
// Add groups to feed // Add groups to feed
$server->register('group.add', function($feed_id, $group_ids) { $procedureHandler->withCallback('group.add', function($feed_id, $group_ids) {
return Model\Group\add($feed_id, $group_ids); return Model\Group\add($feed_id, $group_ids);
}); });
// Remove groups from feed // Remove groups from feed
$server->register('group.remove', function($feed_id, $group_ids) { $procedureHandler->withCallback('group.remove', function($feed_id, $group_ids) {
return Model\Group\remove($feed_id, $group_ids); return Model\Group\remove($feed_id, $group_ids);
}); });
// Remove all groups from feed // Remove all groups from feed
$server->register('group.remove_all', function($feed_id) { $procedureHandler->withCallback('group.remove_all', function($feed_id) {
return Model\Group\remove_all($feed_id); return Model\Group\remove_all($feed_id);
}); });
// Update feed group associations // Update feed group associations
$server->register('group.update_feed_groups', function($feed_id, $group_ids, $create_group = '') { $procedureHandler->withCallback('group.update_feed_groups', function($feed_id, $group_ids, $create_group = '') {
return Model\Group\update_feed_groups($feed_id, $group_ids, $create_group); return Model\Group\update_feed_groups($feed_id, $group_ids, $create_group);
}); });
// Get all items for a specific feed // Get all items for a specific feed
$server->register('item.feed.list', function ($feed_id, $offset = null, $limit = null) { $procedureHandler->withCallback('item.feed.list', function ($feed_id, $offset = null, $limit = null) {
return Model\Item\get_all_by_feed($feed_id, $offset, $limit); return Model\Item\get_all_by_feed($feed_id, $offset, $limit);
}); });
// Count all feed items // Count all feed items
$server->register('item.feed.count', function ($feed_id) { $procedureHandler->withCallback('item.feed.count', function ($feed_id) {
return Model\Item\count_by_feed($feed_id); return Model\Item\count_by_feed($feed_id);
}); });
// Get all bookmark items // Get all bookmark items
$server->register('item.bookmark.list', function ($offset = null, $limit = null) { $procedureHandler->withCallback('item.bookmark.list', function ($offset = null, $limit = null) {
return Model\Item\get_bookmarks($offset, $limit); return Model\Item\get_bookmarks($offset, $limit);
}); });
// Count bookmarks // Count bookmarks
$server->register('item.bookmark.count', function () { $procedureHandler->withCallback('item.bookmark.count', function () {
return Model\Item\count_bookmarks(); return Model\Item\count_bookmarks();
}); });
// Add a bookmark // Add a bookmark
$server->register('item.bookmark.create', function ($item_id) { $procedureHandler->withCallback('item.bookmark.create', function ($item_id) {
return Model\Item\set_bookmark_value($item_id, 1); return Model\Item\set_bookmark_value($item_id, 1);
}); });
// Remove a bookmark // Remove a bookmark
$server->register('item.bookmark.delete', function ($item_id) { $procedureHandler->withCallback('item.bookmark.delete', function ($item_id) {
return Model\Item\set_bookmark_value($item_id, 0); return Model\Item\set_bookmark_value($item_id, 0);
}); });
// Get all unread items // Get all unread items
$server->register('item.list_unread', function ($offset = null, $limit = null) { $procedureHandler->withCallback('item.list_unread', function ($offset = null, $limit = null) {
return Model\Item\get_all_by_status('unread', array(), $offset, $limit); return Model\Item\get_all_by_status('unread', array(), $offset, $limit);
}); });
// Count all unread items // Count all unread items
$server->register('item.count_unread', function () { $procedureHandler->withCallback('item.count_unread', function () {
return Model\Item\count_by_status('unread'); return Model\Item\count_by_status('unread');
}); });
// Get all read items // Get all read items
$server->register('item.list_read', function ($offset = null, $limit = null) { $procedureHandler->withCallback('item.list_read', function ($offset = null, $limit = null) {
return Model\Item\get_all_by_status('read', array(), $offset, $limit); return Model\Item\get_all_by_status('read', array(), $offset, $limit);
}); });
// Count all read items // Count all read items
$server->register('item.count_read', function () { $procedureHandler->withCallback('item.count_read', function () {
return Model\Item\count_by_status('read'); return Model\Item\count_by_status('read');
}); });
// Get one item // Get one item
$server->register('item.info', function ($item_id) { $procedureHandler->withCallback('item.info', function ($item_id) {
return Model\Item\get($item_id); return Model\Item\get($item_id);
}); });
// Delete an item // Delete an item
$server->register('item.delete', function($item_id) { $procedureHandler->withCallback('item.delete', function($item_id) {
return Model\Item\set_removed($item_id); return Model\Item\set_removed($item_id);
}); });
// Mark item as read // Mark item as read
$server->register('item.mark_as_read', function($item_id) { $procedureHandler->withCallback('item.mark_as_read', function($item_id) {
return Model\Item\set_read($item_id); return Model\Item\set_read($item_id);
}); });
// Mark item as unread // Mark item as unread
$server->register('item.mark_as_unread', function($item_id) { $procedureHandler->withCallback('item.mark_as_unread', function($item_id) {
return Model\Item\set_unread($item_id); return Model\Item\set_unread($item_id);
}); });
// Change the status of list of items // Change the status of list of items
$server->register('item.set_list_status', function($status, array $items) { $procedureHandler->withCallback('item.set_list_status', function($status, array $items) {
return Model\Item\set_status($status, $items); return Model\Item\set_status($status, $items);
}); });
// Flush all read items // Flush all read items
$server->register('item.flush', function() { $procedureHandler->withCallback('item.flush', function() {
return Model\Item\mark_all_as_removed(); return Model\Item\mark_all_as_removed();
}); });
// Mark all unread items as read // Mark all unread items as read
$server->register('item.mark_all_as_read', function() { $procedureHandler->withCallback('item.mark_all_as_read', function() {
return Model\Item\mark_all_as_read(); return Model\Item\mark_all_as_read();
}); });
// Get all items with the content // Get all items with the content
$server->register('item.get_all', function() { $procedureHandler->withCallback('item.get_all', function() {
return Model\Item\get_all(); return Model\Item\get_all();
}); });
// Get all items since a date // Get all items since a date
$server->register('item.get_all_since', function($timestamp) { $procedureHandler->withCallback('item.get_all_since', function($timestamp) {
return Model\Item\get_all_since($timestamp); return Model\Item\get_all_since($timestamp);
}); });
// Get all items id and status // Get all items id and status
$server->register('item.get_all_status', function() { $procedureHandler->withCallback('item.get_all_status', function() {
return Model\Item\get_all_status(); return Model\Item\get_all_status();
}); });

View File

@ -16,6 +16,8 @@ return array(
'JsonRPC\\Exception\\ResponseException' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Exception/ResponseException.php', 'JsonRPC\\Exception\\ResponseException' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Exception/ResponseException.php',
'JsonRPC\\Exception\\ServerErrorException' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Exception/ServerErrorException.php', 'JsonRPC\\Exception\\ServerErrorException' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Exception/ServerErrorException.php',
'JsonRPC\\HttpClient' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/HttpClient.php', 'JsonRPC\\HttpClient' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/HttpClient.php',
'JsonRPC\\MiddlewareHandler' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/MiddlewareHandler.php',
'JsonRPC\\MiddlewareInterface' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/MiddlewareInterface.php',
'JsonRPC\\ProcedureHandler' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/ProcedureHandler.php', 'JsonRPC\\ProcedureHandler' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/ProcedureHandler.php',
'JsonRPC\\Request\\BatchRequestParser' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Request/BatchRequestParser.php', 'JsonRPC\\Request\\BatchRequestParser' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Request/BatchRequestParser.php',
'JsonRPC\\Request\\RequestBuilder' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Request/RequestBuilder.php', 'JsonRPC\\Request\\RequestBuilder' => $vendorDir . '/fguillot/json-rpc/src/JsonRPC/Request/RequestBuilder.php',

View File

@ -88,6 +88,8 @@ class ComposerStaticInitfd7e8d436e1dc450edc3153ac8bc31b4
'JsonRPC\\Exception\\ResponseException' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Exception/ResponseException.php', 'JsonRPC\\Exception\\ResponseException' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Exception/ResponseException.php',
'JsonRPC\\Exception\\ServerErrorException' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Exception/ServerErrorException.php', 'JsonRPC\\Exception\\ServerErrorException' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Exception/ServerErrorException.php',
'JsonRPC\\HttpClient' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/HttpClient.php', 'JsonRPC\\HttpClient' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/HttpClient.php',
'JsonRPC\\MiddlewareHandler' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/MiddlewareHandler.php',
'JsonRPC\\MiddlewareInterface' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/MiddlewareInterface.php',
'JsonRPC\\ProcedureHandler' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/ProcedureHandler.php', 'JsonRPC\\ProcedureHandler' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/ProcedureHandler.php',
'JsonRPC\\Request\\BatchRequestParser' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Request/BatchRequestParser.php', 'JsonRPC\\Request\\BatchRequestParser' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Request/BatchRequestParser.php',
'JsonRPC\\Request\\RequestBuilder' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Request/RequestBuilder.php', 'JsonRPC\\Request\\RequestBuilder' => __DIR__ . '/..' . '/fguillot/json-rpc/src/JsonRPC/Request/RequestBuilder.php',

View File

@ -136,44 +136,6 @@
"beanstalkd" "beanstalkd"
] ]
}, },
{
"name": "fguillot/json-rpc",
"version": "v1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/fguillot/JsonRPC.git",
"reference": "e915dab71940e7ac251955c785570048f460d332"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/e915dab71940e7ac251955c785570048f460d332",
"reference": "e915dab71940e7ac251955c785570048f460d332",
"shasum": ""
},
"require": {
"php": ">=5.3.4"
},
"time": "2016-04-27 02:48:10",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"JsonRPC": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frédéric Guillot"
}
],
"description": "Simple Json-RPC client/server library that just works",
"homepage": "https://github.com/fguillot/JsonRPC"
},
{ {
"name": "fguillot/picofeed", "name": "fguillot/picofeed",
"version": "v0.1.24", "version": "v0.1.24",
@ -265,5 +227,46 @@
], ],
"description": "Minimalist database query builder", "description": "Minimalist database query builder",
"homepage": "https://github.com/fguillot/picoDb" "homepage": "https://github.com/fguillot/picoDb"
},
{
"name": "fguillot/json-rpc",
"version": "v1.2.1",
"version_normalized": "1.2.1.0",
"source": {
"type": "git",
"url": "https://github.com/fguillot/JsonRPC.git",
"reference": "d491bb549bfa11aff4c37abcea2ffb28c9523f69"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/d491bb549bfa11aff4c37abcea2ffb28c9523f69",
"reference": "d491bb549bfa11aff4c37abcea2ffb28c9523f69",
"shasum": ""
},
"require": {
"php": ">=5.3.4"
},
"require-dev": {
"phpunit/phpunit": "4.8.*"
},
"time": "2016-06-25 23:11:10",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"JsonRPC": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Frédéric Guillot"
}
],
"description": "Simple Json-RPC client/server library that just works",
"homepage": "https://github.com/fguillot/JsonRPC"
} }
] ]

View File

@ -157,13 +157,15 @@ class Client
* @access public * @access public
* @param string $procedure Procedure name * @param string $procedure Procedure name
* @param array $params Procedure arguments * @param array $params Procedure arguments
* @param array $reqattrs
* @return mixed * @return mixed
*/ */
public function execute($procedure, array $params = array()) public function execute($procedure, array $params = array(), array $reqattrs = array())
{ {
$payload = RequestBuilder::create() $payload = RequestBuilder::create()
->withProcedure($procedure) ->withProcedure($procedure)
->withParams($params) ->withParams($params)
->withRequestAttributes($reqattrs)
->build(); ->build();
if ($this->isBatch) { if ($this->isBatch) {
@ -184,18 +186,9 @@ class Client
*/ */
private function sendPayload($payload) private function sendPayload($payload)
{ {
try {
return ResponseParser::create() return ResponseParser::create()
->withReturnException($this->returnException)
->withPayload($this->httpClient->execute($payload)) ->withPayload($this->httpClient->execute($payload))
->parse(); ->parse();
} catch (Exception $e) {
if ($this->returnException) {
return $e;
}
throw $e;
}
} }
} }

View File

@ -257,7 +257,7 @@ class HttpClient
$response = json_decode(stream_get_contents($stream), true); $response = json_decode(stream_get_contents($stream), true);
if ($this->debug) { if ($this->debug) {
error_log('==> Request: '.PHP_EOL.json_encode($payload, JSON_PRETTY_PRINT)); error_log('==> Request: '.PHP_EOL.(is_string($payload) ? $payload : json_encode($payload, JSON_PRETTY_PRINT)));
error_log('==> Headers: '.PHP_EOL.var_export($headers, true)); error_log('==> Headers: '.PHP_EOL.var_export($headers, true));
error_log('==> Response: '.PHP_EOL.json_encode($response, JSON_PRETTY_PRINT)); error_log('==> Response: '.PHP_EOL.json_encode($response, JSON_PRETTY_PRINT));
} }

View File

@ -0,0 +1,114 @@
<?php
namespace JsonRPC;
/**
* Class MiddlewareHandler
*
* @package JsonRPC
* @author Frederic Guillot
*/
class MiddlewareHandler
{
/**
* Procedure Name
*
* @access protected
* @var string
*/
protected $procedureName = '';
/**
* Username
*
* @access protected
* @var string
*/
protected $username = '';
/**
* Password
*
* @access protected
* @var string
*/
protected $password = '';
/**
* List of middleware to execute before to call the method
*
* @access protected
* @var MiddlewareInterface[]
*/
protected $middleware = array();
/**
* Set username
*
* @access public
* @param string $username
* @return $this
*/
public function withUsername($username)
{
if (! empty($username)) {
$this->username = $username;
}
return $this;
}
/**
* Set password
*
* @access public
* @param string $password
* @return $this
*/
public function withPassword($password)
{
if (! empty($password)) {
$this->password = $password;
}
return $this;
}
/**
* Set procedure name
*
* @access public
* @param string $procedureName
* @return $this
*/
public function withProcedure($procedureName)
{
$this->procedureName = $procedureName;
return $this;
}
/**
* Add a new middleware
*
* @access public
* @param MiddlewareInterface $middleware
* @return MiddlewareHandler
*/
public function withMiddleware(MiddlewareInterface $middleware)
{
$this->middleware[] = $middleware;
return $this;
}
/**
* Execute all middleware
*
* @access public
*/
public function execute()
{
foreach ($this->middleware as $middleware) {
$middleware->execute($this->username, $this->password, $this->procedureName);
}
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace JsonRPC;
use JsonRPC\Exception\AccessDeniedException;
use JsonRPC\Exception\AuthenticationFailureException;
/**
* Interface MiddlewareInterface
*
* @package JsonRPC
* @author Frederic Guillot
*/
interface MiddlewareInterface
{
/**
* Execute Middleware
*
* @access public
* @param string $username
* @param string $password
* @param string $procedureName
* @throws AccessDeniedException
* @throws AuthenticationFailureException
*/
public function execute($username, $password, $procedureName);
}

View File

@ -19,76 +19,34 @@ class ProcedureHandler
/** /**
* List of procedures * List of procedures
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $callbacks = array(); protected $callbacks = array();
/** /**
* List of classes * List of classes
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $classes = array(); protected $classes = array();
/** /**
* List of instances * List of instances
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $instances = array(); protected $instances = array();
/** /**
* Method name to execute before the procedure * Before method name to call
* *
* @access private * @access protected
* @var string * @var string
*/ */
private $before = ''; protected $beforeMethodName = '';
/**
* Username
*
* @access private
* @var string
*/
private $username;
/**
* Password
*
* @access private
* @var string
*/
private $password;
/**
* Set username
*
* @access public
* @param string $username
* @return $this
*/
public function withUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Set password
*
* @access public
* @param string $password
* @return $this
*/
public function withPassword($password)
{
$this->password = $password;
return $this;
}
/** /**
* Register a new procedure * Register a new procedure
@ -96,7 +54,7 @@ class ProcedureHandler
* @access public * @access public
* @param string $procedure Procedure name * @param string $procedure Procedure name
* @param closure $callback Callback * @param closure $callback Callback
* @return Server * @return $this
*/ */
public function withCallback($procedure, Closure $callback) public function withCallback($procedure, Closure $callback)
{ {
@ -111,7 +69,7 @@ class ProcedureHandler
* @param string $procedure Procedure name * @param string $procedure Procedure name
* @param mixed $class Class name or instance * @param mixed $class Class name or instance
* @param string $method Procedure name * @param string $method Procedure name
* @return Server * @return $this
*/ */
public function withClassAndMethod($procedure, $class, $method = '') public function withClassAndMethod($procedure, $class, $method = '')
{ {
@ -128,7 +86,7 @@ class ProcedureHandler
* *
* @access public * @access public
* @param mixed $instance * @param mixed $instance
* @return Server * @return $this
*/ */
public function withObject($instance) public function withObject($instance)
{ {
@ -137,15 +95,15 @@ class ProcedureHandler
} }
/** /**
* Attach a method that will be called before the procedure * Set a before method to call
* *
* @access public * @access public
* @param string $before * @param string $methodName
* @return Server * @return $this
*/ */
public function withBeforeMethod($before) public function withBeforeMethod($methodName)
{ {
$this->before = $before; $this->beforeMethodName = $methodName;
return $this; return $this;
} }
@ -161,8 +119,7 @@ class ProcedureHandler
{ {
if (isset($this->callbacks[$procedure])) { if (isset($this->callbacks[$procedure])) {
return $this->executeCallback($this->callbacks[$procedure], $params); return $this->executeCallback($this->callbacks[$procedure], $params);
} } elseif (isset($this->classes[$procedure]) && method_exists($this->classes[$procedure][0], $this->classes[$procedure][1])) {
else if (isset($this->classes[$procedure]) && method_exists($this->classes[$procedure][0], $this->classes[$procedure][1])) {
return $this->executeMethod($this->classes[$procedure][0], $this->classes[$procedure][1], $params); return $this->executeMethod($this->classes[$procedure][0], $this->classes[$procedure][1], $params);
} }
@ -209,19 +166,10 @@ class ProcedureHandler
public function executeMethod($class, $method, $params) public function executeMethod($class, $method, $params)
{ {
$instance = is_string($class) ? new $class : $class; $instance = is_string($class) ? new $class : $class;
// Execute before action
if (! empty($this->before)) {
if (is_callable($this->before)) {
call_user_func_array($this->before, array($this->username, $this->password, get_class($class), $method));
}
else if (method_exists($instance, $this->before)) {
$instance->{$this->before}($this->username, $this->password, get_class($class), $method);
}
}
$reflection = new ReflectionMethod($class, $method); $reflection = new ReflectionMethod($class, $method);
$this->executeBeforeMethod($instance, $method);
$arguments = $this->getArguments( $arguments = $this->getArguments(
$params, $params,
$reflection->getParameters(), $reflection->getParameters(),
@ -232,33 +180,47 @@ class ProcedureHandler
return $reflection->invokeArgs($instance, $arguments); return $reflection->invokeArgs($instance, $arguments);
} }
/**
* Execute before method if defined
*
* @access public
* @param mixed $object
* @param string $method
*/
public function executeBeforeMethod($object, $method)
{
if ($this->beforeMethodName !== '' && method_exists($object, $this->beforeMethodName)) {
call_user_func_array(array($object, $this->beforeMethodName), array($method));
}
}
/** /**
* Get procedure arguments * Get procedure arguments
* *
* @access public * @access public
* @param array $request_params Incoming arguments * @param array $requestParams Incoming arguments
* @param array $method_params Procedure arguments * @param array $methodParams Procedure arguments
* @param integer $nb_required_params Number of required parameters * @param integer $nbRequiredParams Number of required parameters
* @param integer $nb_max_params Maximum number of parameters * @param integer $nbMaxParams Maximum number of parameters
* @return array * @return array
*/ */
public function getArguments(array $request_params, array $method_params, $nb_required_params, $nb_max_params) public function getArguments(array $requestParams, array $methodParams, $nbRequiredParams, $nbMaxParams)
{ {
$nb_params = count($request_params); $nbParams = count($requestParams);
if ($nb_params < $nb_required_params) { if ($nbParams < $nbRequiredParams) {
throw new InvalidArgumentException('Wrong number of arguments'); throw new InvalidArgumentException('Wrong number of arguments');
} }
if ($nb_params > $nb_max_params) { if ($nbParams > $nbMaxParams) {
throw new InvalidArgumentException('Too many arguments'); throw new InvalidArgumentException('Too many arguments');
} }
if ($this->isPositionalArguments($request_params)) { if ($this->isPositionalArguments($requestParams)) {
return $request_params; return $requestParams;
} }
return $this->getNamedArguments($request_params, $method_params); return $this->getNamedArguments($requestParams, $methodParams);
} }
/** /**
@ -277,24 +239,22 @@ class ProcedureHandler
* Get named arguments * Get named arguments
* *
* @access public * @access public
* @param array $request_params Incoming arguments * @param array $requestParams Incoming arguments
* @param array $method_params Procedure arguments * @param array $methodParams Procedure arguments
* @return array * @return array
*/ */
public function getNamedArguments(array $request_params, array $method_params) public function getNamedArguments(array $requestParams, array $methodParams)
{ {
$params = array(); $params = array();
foreach ($method_params as $p) { foreach ($methodParams as $p) {
$name = $p->getName(); $name = $p->getName();
if (isset($request_params[$name])) { if (isset($requestParams[$name])) {
$params[$name] = $request_params[$name]; $params[$name] = $requestParams[$name];
} } elseif ($p->isDefaultValueAvailable()) {
else if ($p->isDefaultValueAvailable()) {
$params[$name] = $p->getDefaultValue(); $params[$name] = $p->getDefaultValue();
} } else {
else {
throw new InvalidArgumentException('Missing argument: '.$name); throw new InvalidArgumentException('Missing argument: '.$name);
} }
} }

View File

@ -24,6 +24,8 @@ class BatchRequestParser extends RequestParser
$responses[] = RequestParser::create() $responses[] = RequestParser::create()
->withPayload($payload) ->withPayload($payload)
->withProcedureHandler($this->procedureHandler) ->withProcedureHandler($this->procedureHandler)
->withMiddlewareHandler($this->middlewareHandler)
->withLocalException($this->localExceptions)
->parse(); ->parse();
} }
@ -34,6 +36,13 @@ class BatchRequestParser extends RequestParser
/** /**
* Return true if we have a batch request * Return true if we have a batch request
* *
* ex : [
* 0 => '...',
* 1 => '...',
* 2 => '...',
* 3 => '...',
* ]
*
* @static * @static
* @access public * @access public
* @param array $payload * @param array $payload
@ -41,6 +50,6 @@ class BatchRequestParser extends RequestParser
*/ */
public static function isBatchRequest(array $payload) public static function isBatchRequest(array $payload)
{ {
return is_array($payload) && array_keys($payload) === range(0, count($payload) - 1); return array_keys($payload) === range(0, count($payload) - 1);
} }
} }

View File

@ -34,6 +34,14 @@ class RequestBuilder
*/ */
private $params = array(); private $params = array();
/**
* Additional request attributes
*
* @access private
* @var array
*/
private $reqattrs = array();
/** /**
* Get new object instance * Get new object instance
* *
@ -85,6 +93,19 @@ class RequestBuilder
return $this; return $this;
} }
/**
* Set additional request attributes
*
* @access public
* @param array $reqattrs
* @return RequestBuilder
*/
public function withRequestAttributes(array $reqattrs)
{
$this->reqattrs = $reqattrs;
return $this;
}
/** /**
* Build the payload * Build the payload
* *
@ -93,11 +114,11 @@ class RequestBuilder
*/ */
public function build() public function build()
{ {
$payload = array( $payload = array_merge_recursive($this->reqattrs, array(
'jsonrpc' => '2.0', 'jsonrpc' => '2.0',
'method' => $this->procedure, 'method' => $this->procedure,
'id' => $this->id ?: mt_rand(), 'id' => $this->id ?: mt_rand(),
); ));
if (! empty($this->params)) { if (! empty($this->params)) {
$payload['params'] = $this->params; $payload['params'] = $this->params;

View File

@ -6,6 +6,7 @@ use Exception;
use JsonRPC\Exception\AccessDeniedException; use JsonRPC\Exception\AccessDeniedException;
use JsonRPC\Exception\AuthenticationFailureException; use JsonRPC\Exception\AuthenticationFailureException;
use JsonRPC\Exception\InvalidJsonRpcFormatException; use JsonRPC\Exception\InvalidJsonRpcFormatException;
use JsonRPC\MiddlewareHandler;
use JsonRPC\ProcedureHandler; use JsonRPC\ProcedureHandler;
use JsonRPC\Response\ResponseBuilder; use JsonRPC\Response\ResponseBuilder;
use JsonRPC\Validator\JsonFormatValidator; use JsonRPC\Validator\JsonFormatValidator;
@ -27,6 +28,17 @@ class RequestParser
*/ */
protected $payload; protected $payload;
/**
* List of exceptions that should not be relayed to the client
*
* @access protected
* @var array()
*/
protected $localExceptions = array(
'JsonRPC\Exception\AuthenticationFailureException',
'JsonRPC\Exception\AccessDeniedException',
);
/** /**
* ProcedureHandler * ProcedureHandler
* *
@ -35,6 +47,14 @@ class RequestParser
*/ */
protected $procedureHandler; protected $procedureHandler;
/**
* MiddlewareHandler
*
* @access protected
* @var MiddlewareHandler
*/
protected $middlewareHandler;
/** /**
* Get new object instance * Get new object instance
* *
@ -60,6 +80,24 @@ class RequestParser
return $this; return $this;
} }
/**
* Exception classes that should not be relayed to the client
*
* @access public
* @param mixed $exception
* @return $this
*/
public function withLocalException($exception)
{
if (is_array($exception)) {
$this->localExceptions = array_merge($this->localExceptions, $exception);
} else {
$this->localExceptions[] = $exception;
}
return $this;
}
/** /**
* Set procedure handler * Set procedure handler
* *
@ -73,6 +111,19 @@ class RequestParser
return $this; return $this;
} }
/**
* Set middleware handler
*
* @access public
* @param MiddlewareHandler $middlewareHandler
* @return $this
*/
public function withMiddlewareHandler(MiddlewareHandler $middlewareHandler)
{
$this->middlewareHandler = $middlewareHandler;
return $this;
}
/** /**
* Parse incoming request * Parse incoming request
* *
@ -88,6 +139,10 @@ class RequestParser
JsonFormatValidator::validate($this->payload); JsonFormatValidator::validate($this->payload);
RpcFormatValidator::validate($this->payload); RpcFormatValidator::validate($this->payload);
$this->middlewareHandler
->withProcedure($this->payload['method'])
->execute();
$result = $this->procedureHandler->executeProcedure( $result = $this->procedureHandler->executeProcedure(
$this->payload['method'], $this->payload['method'],
empty($this->payload['params']) ? array() : $this->payload['params'] empty($this->payload['params']) ? array() : $this->payload['params']
@ -100,10 +155,27 @@ class RequestParser
->build(); ->build();
} }
} catch (Exception $e) { } catch (Exception $e) {
return $this->handleExceptions($e);
}
if ($e instanceof AccessDeniedException || $e instanceof AuthenticationFailureException) { return '';
}
/**
* Handle exceptions
*
* @access protected
* @param Exception $e
* @return string
* @throws Exception
*/
protected function handleExceptions(Exception $e)
{
foreach ($this->localExceptions as $exception) {
if ($e instanceof $exception) {
throw $e; throw $e;
} }
}
if ($e instanceof InvalidJsonRpcFormatException || ! $this->isNotification()) { if ($e instanceof InvalidJsonRpcFormatException || ! $this->isNotification()) {
return ResponseBuilder::create() return ResponseBuilder::create()
@ -111,7 +183,6 @@ class RequestParser
->withException($e) ->withException($e)
->build(); ->build();
} }
}
return ''; return '';
} }
@ -119,10 +190,10 @@ class RequestParser
/** /**
* Return true if the message is a notification * Return true if the message is a notification
* *
* @access private * @access protected
* @return bool * @return bool
*/ */
private function isNotification() protected function isNotification()
{ {
return is_array($this->payload) && !isset($this->payload['id']); return is_array($this->payload) && !isset($this->payload['id']);
} }

View File

@ -4,6 +4,7 @@ namespace JsonRPC\Response;
use BadFunctionCallException; use BadFunctionCallException;
use InvalidArgumentException; use InvalidArgumentException;
use Exception;
use JsonRPC\Exception\InvalidJsonFormatException; use JsonRPC\Exception\InvalidJsonFormatException;
use JsonRPC\Exception\InvalidJsonRpcFormatException; use JsonRPC\Exception\InvalidJsonRpcFormatException;
use JsonRPC\Exception\ResponseException; use JsonRPC\Exception\ResponseException;
@ -25,6 +26,13 @@ class ResponseParser
*/ */
private $payload; private $payload;
/**
* Do not immediately throw an exception on error. Return it instead.
*
* @var bool
*/
private $returnException = false;
/** /**
* Get new object instance * Get new object instance
* *
@ -37,6 +45,18 @@ class ResponseParser
return new static(); return new static();
} }
/**
* Set Return Exception Or Throw It
*
* @param $returnException
* @return ResponseParser
*/
public function withReturnException($returnException)
{
$this->returnException = $returnException;
return $this;
}
/** /**
* Set payload * Set payload
* *
@ -53,11 +73,13 @@ class ResponseParser
/** /**
* Parse response * Parse response
* *
* @access public * @return array|Exception|null
* @throws InvalidJsonFormatException * @throws InvalidJsonFormatException
* @throws BadFunctionCallException
* @throws InvalidJsonRpcFormatException * @throws InvalidJsonRpcFormatException
* @throws InvalidArgumentException
* @throws Exception
* @throws ResponseException * @throws ResponseException
* @return mixed
*/ */
public function parse() public function parse()
{ {
@ -68,6 +90,7 @@ class ResponseParser
foreach ($this->payload as $response) { foreach ($this->payload as $response) {
$results[] = self::create() $results[] = self::create()
->withReturnException($this->returnException)
->withPayload($response) ->withPayload($response)
->parse(); ->parse();
} }
@ -76,7 +99,14 @@ class ResponseParser
} }
if (isset($this->payload['error']['code'])) { if (isset($this->payload['error']['code'])) {
try {
$this->handleExceptions(); $this->handleExceptions();
} catch (Exception $e) {
if ($this->returnException) {
return $e;
}
throw $e;
}
} }
return isset($this->payload['result']) ? $this->payload['result'] : null; return isset($this->payload['result']) ? $this->payload['result'] : null;

View File

@ -22,66 +22,99 @@ class Server
/** /**
* Allowed hosts * Allowed hosts
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $hosts = array(); protected $hosts = array();
/** /**
* Data received from the client * Data received from the client
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $payload = array(); protected $payload = array();
/** /**
* List of exception classes that should be relayed to client * List of exceptions that should not be relayed to the client
* *
* @access private * @access protected
* @var array * @var array()
*/ */
private $exceptions = array(); protected $localExceptions = array();
/** /**
* Username * Username
* *
* @access private * @access protected
* @var string * @var string
*/ */
private $username = ''; protected $username = '';
/** /**
* Password * Password
* *
* @access private * @access protected
* @var string * @var string
*/ */
private $password = ''; protected $password = '';
/** /**
* Allowed users * Allowed users
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $users = array(); protected $users = array();
/** /**
* $_SERVER * $_SERVER
* *
* @access private * @access protected
* @var array * @var array
*/ */
private $serverVariable; protected $serverVariable;
/** /**
* ProcedureHandler object * ProcedureHandler object
* *
* @access private * @access protected
* @var ProcedureHandler * @var ProcedureHandler
*/ */
private $procedureHandler; protected $procedureHandler;
/**
* MiddlewareHandler object
*
* @access protected
* @var MiddlewareHandler
*/
protected $middlewareHandler;
/**
* Response builder
*
* @access protected
* @var ResponseBuilder
*/
protected $responseBuilder;
/**
* Response builder
*
* @access protected
* @var RequestParser
*/
protected $requestParser;
/**
*
* Batch request parser
*
* @access protected
* @var BatchRequestParser
*/
protected $batchRequestParser;
/** /**
* Constructor * Constructor
@ -89,9 +122,21 @@ class Server
* @access public * @access public
* @param string $request * @param string $request
* @param array $server * @param array $server
* @param ResponseBuilder $responseBuilder
* @param RequestParser $requestParser
* @param BatchRequestParser $batchRequestParser
* @param ProcedureHandler $procedureHandler
* @param MiddlewareHandler $middlewareHandler
*/ */
public function __construct($request = '', array $server = array()) public function __construct(
{ $request = '',
array $server = array(),
ResponseBuilder $responseBuilder = null,
RequestParser $requestParser = null,
BatchRequestParser $batchRequestParser = null,
ProcedureHandler $procedureHandler = null,
MiddlewareHandler $middlewareHandler = null
) {
if ($request !== '') { if ($request !== '') {
$this->payload = json_decode($request, true); $this->payload = json_decode($request, true);
} else { } else {
@ -99,7 +144,11 @@ class Server
} }
$this->serverVariable = $server ?: $_SERVER; $this->serverVariable = $server ?: $_SERVER;
$this->procedureHandler = new ProcedureHandler(); $this->responseBuilder = $responseBuilder ?: ResponseBuilder::create();
$this->requestParser = $requestParser ?: RequestParser::create();
$this->batchRequestParser = $batchRequestParser ?: BatchRequestParser::create();
$this->procedureHandler = $procedureHandler ?: new ProcedureHandler();
$this->middlewareHandler = $middlewareHandler ?: new MiddlewareHandler();
} }
/** /**
@ -107,7 +156,7 @@ class Server
* *
* @access public * @access public
* @param string $header Header name * @param string $header Header name
* @return Server * @return $this
*/ */
public function setAuthenticationHeader($header) public function setAuthenticationHeader($header)
{ {
@ -134,6 +183,17 @@ class Server
return $this->procedureHandler; return $this->procedureHandler;
} }
/**
* Get MiddlewareHandler
*
* @access public
* @return MiddlewareHandler
*/
public function getMiddlewareHandler()
{
return $this->middlewareHandler;
}
/** /**
* Get username * Get username
* *
@ -161,7 +221,7 @@ class Server
* *
* @access public * @access public
* @param array $hosts List of hosts * @param array $hosts List of hosts
* @return Server * @return $this
*/ */
public function allowHosts(array $hosts) public function allowHosts(array $hosts)
{ {
@ -174,7 +234,7 @@ class Server
* *
* @access public * @access public
* @param array $users Dictionary of username/password * @param array $users Dictionary of username/password
* @return Server * @return $this
*/ */
public function authentication(array $users) public function authentication(array $users)
{ {
@ -186,9 +246,10 @@ class Server
* Register a new procedure * Register a new procedure
* *
* @access public * @access public
* @deprecated Use $server->getProcedureHandler()->withCallback($procedure, $callback)
* @param string $procedure Procedure name * @param string $procedure Procedure name
* @param closure $callback Callback * @param closure $callback Callback
* @return Server * @return $this
*/ */
public function register($procedure, Closure $callback) public function register($procedure, Closure $callback)
{ {
@ -200,10 +261,11 @@ class Server
* Bind a procedure to a class * Bind a procedure to a class
* *
* @access public * @access public
* @deprecated Use $server->getProcedureHandler()->withClassAndMethod($procedure, $class, $method);
* @param string $procedure Procedure name * @param string $procedure Procedure name
* @param mixed $class Class name or instance * @param mixed $class Class name or instance
* @param string $method Procedure name * @param string $method Procedure name
* @return Server * @return $this
*/ */
public function bind($procedure, $class, $method = '') public function bind($procedure, $class, $method = '')
{ {
@ -215,8 +277,9 @@ class Server
* Bind a class instance * Bind a class instance
* *
* @access public * @access public
* @deprecated Use $server->getProcedureHandler()->withObject($instance);
* @param mixed $instance Instance name * @param mixed $instance Instance name
* @return Server * @return $this
*/ */
public function attach($instance) public function attach($instance)
{ {
@ -225,29 +288,15 @@ class Server
} }
/** /**
* Bind an exception * Exception classes that should not be relayed to the client
* If this exception occurs it is relayed to the client as JSON-RPC error
* *
* @access public * @access public
* @param mixed $exception Exception class. Defaults to all. * @param Exception|string $exception
* @return Server * @return $this
*/ */
public function attachException($exception = 'Exception') public function withLocalException($exception)
{ {
$this->exceptions[] = $exception; $this->localExceptions[] = $exception;
return $this;
}
/**
* Attach a method that will be called before the procedure
*
* @access public
* @param string $before
* @return Server
*/
public function before($before)
{
$this->procedureHandler->withBeforeMethod($before);
return $this; return $this;
} }
@ -259,56 +308,78 @@ class Server
*/ */
public function execute() public function execute()
{ {
$responseBuilder = ResponseBuilder::create();
try { try {
$this->procedureHandler
->withUsername($this->getUsername())
->withPassword($this->getPassword());
JsonFormatValidator::validate($this->payload); JsonFormatValidator::validate($this->payload);
HostValidator::validate($this->hosts, $this->getServerVariable('REMOTE_ADDR')); HostValidator::validate($this->hosts, $this->getServerVariable('REMOTE_ADDR'));
UserValidator::validate($this->users, $this->getUsername(), $this->getPassword()); UserValidator::validate($this->users, $this->getUsername(), $this->getPassword());
$this->middlewareHandler
->withUsername($this->getUsername())
->withPassword($this->getPassword())
;
$response = $this->parseRequest(); $response = $this->parseRequest();
} catch (Exception $e) { } catch (Exception $e) {
$response = $responseBuilder->withException($e)->build(); $response = $this->handleExceptions($e);
} }
$responseBuilder->sendHeaders(); $this->responseBuilder->sendHeaders();
return $response; return $response;
} }
/**
* Handle exceptions
*
* @access protected
* @param Exception $e
* @return string
* @throws Exception
*/
protected function handleExceptions(Exception $e)
{
foreach ($this->localExceptions as $exception) {
if ($e instanceof $exception) {
throw $e;
}
}
return $this->responseBuilder->withException($e)->build();
}
/** /**
* Parse incoming request * Parse incoming request
* *
* @access private * @access protected
* @return string * @return string
*/ */
private function parseRequest() protected function parseRequest()
{ {
if (BatchRequestParser::isBatchRequest($this->payload)) { if (BatchRequestParser::isBatchRequest($this->payload)) {
return BatchRequestParser::create() return $this->batchRequestParser
->withPayload($this->payload) ->withPayload($this->payload)
->withProcedureHandler($this->procedureHandler) ->withProcedureHandler($this->procedureHandler)
->withMiddlewareHandler($this->middlewareHandler)
->withLocalException($this->localExceptions)
->parse(); ->parse();
} }
return RequestParser::create() return $this->requestParser
->withPayload($this->payload) ->withPayload($this->payload)
->withProcedureHandler($this->procedureHandler) ->withProcedureHandler($this->procedureHandler)
->withMiddlewareHandler($this->middlewareHandler)
->withLocalException($this->localExceptions)
->parse(); ->parse();
} }
/** /**
* Check existence and get value of server variable * Check existence and get value of server variable
* *
* @access private * @access protected
* @param string $variable * @param string $variable
* @return string|null * @return string|null
*/ */
private function getServerVariable($variable) protected function getServerVariable($variable)
{ {
return isset($this->serverVariable[$variable]) ? $this->serverVariable[$variable] : null; return isset($this->serverVariable[$variable]) ? $this->serverVariable[$variable] : null;
} }