|
<?php |
|
|
|
namespace JsonRPC; |
|
|
|
use BadFunctionCallException; |
|
use Closure; |
|
use InvalidArgumentException; |
|
use ReflectionFunction; |
|
use ReflectionMethod; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProcedureHandler |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $callbacks = array(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $classes = array(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $instances = array(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $beforeMethodName = ''; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function withCallback($procedure, Closure $callback) |
|
{ |
|
$this->callbacks[$procedure] = $callback; |
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function withClassAndMethod($procedure, $class, $method = '') |
|
{ |
|
if ($method === '') { |
|
$method = $procedure; |
|
} |
|
|
|
$this->classes[$procedure] = array($class, $method); |
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function withObject($instance) |
|
{ |
|
$this->instances[] = $instance; |
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function withBeforeMethod($methodName) |
|
{ |
|
$this->beforeMethodName = $methodName; |
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function withCallbackArray($callbacks) |
|
{ |
|
foreach ($callbacks as $procedure => $callback) { |
|
$this->withCallback($procedure, $callback); |
|
} |
|
|
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function withClassAndMethodArray($callbacks) |
|
{ |
|
foreach ($callbacks as $procedure => $callback) { |
|
$this->withClassAndMethod($procedure, $callback[0], $callback[1]); |
|
} |
|
|
|
return $this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function executeProcedure($procedure, array $params = array()) |
|
{ |
|
if (isset($this->callbacks[$procedure])) { |
|
return $this->executeCallback($this->callbacks[$procedure], $params); |
|
} elseif (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); |
|
} |
|
|
|
foreach ($this->instances as $instance) { |
|
if (method_exists($instance, $procedure)) { |
|
return $this->executeMethod($instance, $procedure, $params); |
|
} |
|
} |
|
|
|
throw new BadFunctionCallException('Unable to find the procedure'); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function executeCallback(Closure $callback, $params) |
|
{ |
|
$reflection = new ReflectionFunction($callback); |
|
|
|
$arguments = $this->getArguments( |
|
$params, |
|
$reflection->getParameters(), |
|
$reflection->getNumberOfRequiredParameters(), |
|
$reflection->getNumberOfParameters() |
|
); |
|
|
|
return $reflection->invokeArgs($arguments); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function executeMethod($class, $method, $params) |
|
{ |
|
$instance = is_string($class) ? new $class : $class; |
|
$reflection = new ReflectionMethod($class, $method); |
|
|
|
$this->executeBeforeMethod($instance, $method); |
|
|
|
$arguments = $this->getArguments( |
|
$params, |
|
$reflection->getParameters(), |
|
$reflection->getNumberOfRequiredParameters(), |
|
$reflection->getNumberOfParameters() |
|
); |
|
|
|
return $reflection->invokeArgs($instance, $arguments); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function executeBeforeMethod($object, $method) |
|
{ |
|
if ($this->beforeMethodName !== '' && method_exists($object, $this->beforeMethodName)) { |
|
call_user_func_array(array($object, $this->beforeMethodName), array($method)); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getArguments(array $requestParams, array $methodParams, $nbRequiredParams, $nbMaxParams) |
|
{ |
|
$nbParams = count($requestParams); |
|
|
|
if ($nbParams < $nbRequiredParams) { |
|
throw new InvalidArgumentException('Wrong number of arguments'); |
|
} |
|
|
|
if ($nbParams > $nbMaxParams) { |
|
throw new InvalidArgumentException('Too many arguments'); |
|
} |
|
|
|
if ($this->isPositionalArguments($requestParams)) { |
|
return $requestParams; |
|
} |
|
|
|
return $this->getNamedArguments($requestParams, $methodParams); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function isPositionalArguments(array $request_params) |
|
{ |
|
return array_keys($request_params) === range(0, count($request_params) - 1); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getNamedArguments(array $requestParams, array $methodParams) |
|
{ |
|
$params = array(); |
|
|
|
foreach ($methodParams as $p) { |
|
$name = $p->getName(); |
|
|
|
if (array_key_exists($name, $requestParams)) { |
|
$params[$name] = $requestParams[$name]; |
|
} elseif ($p->isDefaultValueAvailable()) { |
|
$params[$name] = $p->getDefaultValue(); |
|
} else { |
|
throw new InvalidArgumentException('Missing argument: '.$name); |
|
} |
|
} |
|
|
|
return $params; |
|
} |
|
} |
|
|