我的团队正在为我们的平台开发R.E.S.T api。
我们目前拥有的端点的一些示例:
- 活动/24566/图片
- 活动/24566/用户
- 用户/23345646
- 用户/活动
我们目前以一种丑陋的方式编写端点来检查路径,我们正试图构建一个抽象的端点类,该类将包括它的路径并对其进行验证
我们的目标是创建这个抽象类,以便能够通过添加或删除Endpoint类来轻松添加或删除端点。
显然,这种端点结构要求二进制树结构,但我在实现它时遇到了一些麻烦
这是我的伪逻辑:
- 端点/sub_endpoint_1/sub_endpoint _5的请求
- 如果有一个名为endpoint的类,并且它可以是route,则创建一个实例
- 如果端点具有名为sub_endpoint1的子级-创建它的实例
- 如果sub_endpoint_1有一个名为sub_endpoint _5的子级-创建它的实例
- 如果这是一个叶子-在这个端点中运行代码
我在想每个终点都应该容纳它的父母和孩子,但我很难理解如何首先验证整个路径是正确的。
如果每个端点都只能知道在它之前和之后可以是什么,我可能会得到:
端点1/sub_endpoint_1/sub_endpoint_5
对于一些伪指南来说会很好:)
我不确定这是否是你想要的,但如果我是你,我会使用经过良好测试的、来自知名框架的东西。即使您已经习惯性地编写了PHP应用程序,并且没有使用任何框架,您也只能通过composer
安装所需的组件。
让我们以symfony/ruoting
为例。为了获取HTTP请求上下文,还需要symfony/http-foundation
。为了安装两者,请转到您的项目根目录,如果尚未安装composer,请安装它,然后
composer需要symfony/http基础composer需要符号/路由
那么你需要在你的项目入口点中包括vendor/autoload.php
,就这样,你现在可以使用symfony/routing
了。好的是,由于symfony2是一个组件框架,您不需要安装所有的框架,只需要安装这两个包。
现在,如果您使用以下代码创建一个测试文件:
require_once(realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'));
use Symfony'Component'HttpFoundation'Request;
use Symfony'Component'Routing'Matcher'UrlMatcher;
use Symfony'Component'Routing'RequestContext;
use Symfony'Component'Routing'RouteCollection;
use Symfony'Component'Routing'Route;
$routes = new RouteCollection();
$route = new Route('/{endpoint}/{subendpoint}/{subsubendpoint}');
$route->setDefaults(array(
'endpoint' => null,
'subendpoint' => null,
'subsubendpoint' => null,
));
$routes->add('main', $route);
$context = new RequestContext();
// this is optional and can be done without a Request instance
$context->fromRequest(Request::createFromGlobals());
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/hello');
var_dump($parameters);
$parameters = $matcher->match('/');
var_dump($parameters);
$parameters = $matcher->match('/campaigns/24566/pictures');
var_dump($parameters);
$parameters = $matcher->match('/campaigns/24566/users');
var_dump($parameters);
$parameters = $matcher->match('/users/23445646');
var_dump($parameters);
$parameters = $matcher->match('/users/campaigns');
var_dump($parameters);
试着打开它,你会看到这样的东西:
array(4) {
["endpoint"]=>
string(5) "hello"
["subendpoint"]=>
NULL
["subsubendpoint"]=>
NULL
["_route"]=>
string(4) "main"
}
array(4) {
["endpoint"]=>
NULL
["subendpoint"]=>
NULL
["subsubendpoint"]=>
NULL
["_route"]=>
string(4) "main"
}
array(4) {
["endpoint"]=>
string(9) "campaigns"
["subendpoint"]=>
string(5) "24566"
["subsubendpoint"]=>
string(8) "pictures"
["_route"]=>
string(4) "main"
}
array(4) {
["endpoint"]=>
string(9) "campaigns"
["subendpoint"]=>
string(5) "24566"
["subsubendpoint"]=>
string(5) "users"
["_route"]=>
string(4) "main"
}
array(4) {
["endpoint"]=>
string(5) "users"
["subendpoint"]=>
string(8) "23445646"
["subsubendpoint"]=>
NULL
["_route"]=>
string(4) "main"
}
array(4) {
["endpoint"]=>
string(5) "users"
["subendpoint"]=>
string(9) "campaigns"
["subsubendpoint"]=>
NULL
["_route"]=>
string(4) "main"
}
如果将其集成到REST API入口脚本中,则可以将$_SERVER['REQUEST_URI']
传递到::match()
方法中,然后传递类似以下内容:
if(!empty($parameters['subsubendpoint'])) {
//instantiate the "leaf"-subclass
} elseif(!empty($parameters['subendpoint'])) {
//instantiate the "middle"-subclass
} else {
//instantiate the "main" class
}