rds/jrf

1.1.1 2015-03-06 16:26 UTC

This package is not auto-updated.

Last update: 2024-09-09 19:41:15 UTC


README

Build Status

JRF 是一个 基于 HTTP 的 JSON-RPC 数据提供框架。简单的组件化架构允许您快速、轻松地开发 Web 服务。直接使用 JRF 支持控制器/动作工厂、输入接口(默认为 PhpInput)和中间件请求检查。

SchemaChecker 接口允许您为您的应用程序服务提供的任何方法提示并检查传入的参数。

智能错误接口非常易于使用。您不需要关心任何低级生命周期捕获器和响应结果构建器。只需提出并查看 =)

除了直接使用之外,您还可以使用控制器工厂创建一个强大的基于控制器的应用程序服务。

使用示例

use \jrf\JRF;
$service = new JRF();

$service->controller()->handleMethod('method',
    function($param_1, $param_2, JRF $app, $request_id) {
        return $param_1 + $param_2
    });

$service->listen();

只需在它上面发布 JSON

{
    "jsonrpc": "2.0",
    "id": 100,
    "method": "method",
    "params": [1, 3]
}

覆盖输入接口

如果 php://input 对您来说不是好方法,您可以创建自己的输入

use jrf\http\Input;

class MyInput extends Input
{
    private $input;

    public function __construct($input)
    {
        $this->input = $input;
    }

    public function read()
    {
        return $this->input;
    }
}

并且像这样覆盖默认设置

// ..... service init
use MyInput;
$input = new MyInput($_POST['json']);
$service->request()->setInputProvider($input);

全部完成 =) 您的提供商将在 JRF 生态系统中正常工作。

创建访问中间件

在 "captain obvious" 看来,所有可用的私有服务都必须有访问配置模块。让我们将其编码进去

use \jrf\middleware\Base;
use \jrf\fault\ServerError;

class AccessMiddleware extends Base
{
	private $ip_list=[];
	public function __construct(array $ip_list) {
		$this->ip_list = $ip_list;
	}

	public function call()
	{
		$info = $this->app->request()->info();
		$ip   = $info['ip_address'];

		if (!in_array($ip, $this->ip_list)) {
		    ServerError::raise('access error');
		}

		$this->next->call();
	}
}

让我们将我们的中间件添加到服务中

// ... service init
use AccessMiddleware;

$list_allowed_ip = ['127.0.0.1'];

$service->add(new AccessMiddleware($list_allowed_ip));

创建自定义控制器工厂

创建工厂的简单且易于的方式是使用基于命名空间的动作提供者。

use jrf\controller\Base;
use jrf\fault\MethodNotFound;

class MyControllerFactory extends Base
{
    public function runMethodWithArgs($method, array $args =[], $request_id=0)
    {
        // fall-back if want to use closure-based methods
        if ($this->isHandledMethod($method)) {
            return parent::runMethodWithArgs($method, $args, $request_id);
        }

        // now try to create action class
        if (strpos('.', $method)===false) {
            MethodNotFound::raise();
        }

        list($group, $action) = explode('.', $method);

        $class_name = sprint_f("\my\action\namespace\%s\%s", strtolower($group), ucfirst($action));

        if (!class_exists($class_name)) {
            MethodNotFound::raise();
        }

        $action = new $class_name($this->app());

        if (!is_callable([$action, 'run'])) {
            MethodNotFound::raise();
        }

        return $action->run();
    }
}

实现

// .... service init
use MyControllerFactory;
$factory = new MyControllerFactory;
$service->controller($factory);

传入参数提示/检查

例如,发布的 json 是

{
    "jsonrpc":"2.0",
    "id":120,
    "method":"test",
    "params":{
        "a":11,
        "b":10
    }
}

规则

  • a > 0
  • b > 0
  • a 是 INT
  • b 是 INT
  • a 是必需的
  • b 是必需的

实现

use jrf\json\Schema;

$params_definition = [
    'a' => [
        'type' => Schema::TYPE_INT,
        'definition' => Schema::DEFINITION_REQUIRED,
        'expression' => function ($v) { return intval($v) > 0; }
    ],
    'b' => [
        'type' => Schema::TYPE_INT,
        'definition' => Schema::DEFINITION_REQUIRED,
        'expression' => function ($v) { return intval($v) > 0; }
    ],
];

$schema = new Schema($params_definition);
$service->controller()->setSchemaForMethod('test', $schema);

配置容器

配置容器在 JRF 构造函数方法中实例化,其中包含传递给它的选项。要访问容器,JRF 提供名为 "config" 的方法,以下是 config 访问示例

use jrf\JRF;

$options = [
    'app.debug' => true,
    'app.secret' => 'secret'
];

$service = new JRF($options);

// return: null
$val = $service->config('unknown-option');

// return default defined value: 123
$val = $service->config('unknown-option', 123);

// return true
$val = $service->config('app.debug');
$val = $service->config('app.debug', false);
$val = $service->config()->get('app.debug');
$val = $service->config()->{'app.debug'};
$val = $service->config()['app.debug'];

客户端使用

$client = new Client("http://json-rpc.server/");

$pipe = $client->createPipe();

$batch = $client->createBatch();
$m1_id = $batch->append($client->method('m1', [1,2,3]));
$m2_id = $batch->append($client->method('m2'));
$m3_id = $batch->append($client->method('m3'));

$pipe->add('batch', $batch);
$pipe->add('news', $client->method('news.search', ['limit'=>50]));
$pipe->add('users', $client->method('users.all', ['limit'=>10]));

$response = $client->executePipe($pipe);

$m1 = $response['batch'][$m2_id];

var_dump($m1->getResult());
var_dump($client->getTotalTime());

单元测试

cd path/to/jrf-root
php composer.phar update --dev
vendor/bin/phpunit

无 HTTP 使用

如果确实需要,JRF 允许在不使用任何监听器的情况下处理自定义输入接口。通过这种方式,JRF 不提供响应输出。然而,如果您需要使用多个提供商,您可以通过添加 $service->listen() 来运行服务。

// input interface from example
use MyInput;

$payload = ["jsonrpc"=>"2.0", "id"=>1, "method"=>"my.method"];
$input   = new MyInput(json_encode($payload));

// ... defining service

$result_string = $service->handleInputProvider($input);
$result_array  = json_decode($result_string, true);

// if HTTP listener needed
$service->listen();

许可

版权 (c) 2014 Rambler&Co

特此授予任何人免费获得此软件及其相关文档文件(“软件”)的副本的权利,以无限制地处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本,并允许向软件提供者提供软件的人这样做,前提是以下条件

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、适用于特定目的和无侵犯性的保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论此类责任是基于合同、侵权或其他方式,源于、因之或与此软件或软件的使用或其他交易有关。