o /wp-rest-router
Requires
- php: >=7.1
Requires (Dev)
- guzzlehttp/guzzle: ^6.3
- kahlan/kahlan: ^4.6
- phpstan/phpstan: ^0.11.15
- squizlabs/php_codesniffer: ^3.5
- szepeviktor/phpstan-wordpress: ^0.2.0
This package is not auto-updated.
Last update: 2024-09-27 18:37:46 UTC
README
WP Rest Router是WordPress中注册自定义REST路由的抽象。它的目标是通过提供类似Laravel和Express等框架的开发者体验,简化并增强原生WordPress API。
要求
- PHP >= 7.1
- WordPress >= 4.7
创建路由的方式与大多数流行框架中创建路由的方式相同。
use O\WordPress\Rest\Router; // create a new router, you'll need to provide it a namespace to use when registering routes with WordPress // @see https://developer.wordpress.org/reference/functions/register_rest_route/#parameters $router = new Router('my-namespace'); // unlike regular WordPress endpoint callbacks, you can always expect // to receive a request AND response object in your route callback $router->get('my-route', function (WP_REST_Request $req, WP_REST_Response $res) { // endpoint logic here return $res; }); // POST $router->post('my-route', ...); // PUT $router->put('my-route', ...); // PATCH $router->patch('my-route', ...); // DELETE $router->delete('my-route', ...); // registers routes with WordPress // listen attempts to register routes at the right time // so you can skip hooking into the rest_api_init action if you’d like // listen will throw an exception if its detected that its being called too late in the request $router->listen();
可以使用route
方法将路由范围或分组到特定的路径。
use O\WordPress\Rest\Router; $router = new Router('my-namespace'); // route will accept a callback as its second argument $router->route('foo', function ($scope) { // wp-json/my-namespace/foo/bar $scope->get('bar', ...); // wp-json/my-namespace/foo/baz $scope->get('baz', ...); }); // you may also choose to omit providing a callback and simply use the returned scoped router $fooScope = $router->route('foo'); $fooScope->get('bar', ...); // route may also be used to easily define multiple methods for a single route $router->route('foo', function ($scope) { // GET wp-json/my-namespace/foo $scope->get('', ...); // POST wp-json/my-namespace/foo $scope->post('', ...) });
类似于Laravel使用控制器类,可以使用由类名和方法名组成的字符串(由@字符分隔)作为回调来创建路由。路由器将负责在后台实例化类并调用给定方法。
use O\WordPress\Rest\Router; class MyController { /** * Lists some items * * @param WP_REST_Request $req * @param WP_REST_Response $res * @return WP_REST_Response */ public function list(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Response { // endpoint logic here return $res; } } $router = new Router('my-namespace'); // the router will take care of instantiating MyController and invoking the list method under the hood $router->get('my-route', 'MyController@list'); // or if you're using namespaces $router->get('my-route', 'MyNamespace\Controllers\MyController@list');
请注意,路由器不知道如何解析控制器类上的构造函数参数。如果您发现自己处于这种情况或者使用依赖注入容器,则需要向路由器提供一个解析函数。
use O\WordPress\Rest\Router; class SomeRepository { /** * Queries the database * * @param string $id * @return array */ public function find(string $id): array } class MyController { /** * @var SomeRepository */ protected $repo; /** * @param SomeRepository $repo */ public function __construct(SomeRepository $repo) { $this->repo = $repo; } /** * Lists some items * * @param WP_REST_Request $req * @param WP_REST_Response $res * @return WP_REST_Response */ public function list(WP_REST_Request $req, WP_REST_Response $res): WP_REST_Response { $id = $req->get_param('id'); $items = $this->repo->find($id); $res->set_data(json_encode($items)); return $res; } } $router = new Router('my-namespace'); // provide the router with a function that resolves classes through a DI container $router->setResolver(function (string $classname) { $container = SomeDIContainer::getInstance(); return $container->create($classname); }); // when the router needs to create a new instance of MyController it will first check // if a resolver function has been provided and invoke it with the name of the class // its trying to create, your resolver function should return a new instance of that class $router->get('my-route', 'MyController@list');
WP Rest Router的一个很酷的功能是它使得定义和使用类似Express的中间件函数变得容易。请注意,与Express不同,路由回调将在所有中间件函数之后始终被调用。
use O\WordPress\Rest\Router; $router = new Router('my-namespace'); // similar to route callbacks, middleware functions will always be provided with // a request and response object, the only difference here is that middleware functions // are also provided with a next function as their last argument - just like Express middlewares // calling $next() at the end of your middleware allows the chain to continue function fooMiddleware(WP_REST_Request $req, WP_REST_Response $res, callable $next) { $res->header('x-foo', true); $next(); } // you may however choose to conditionally not call $next // this will short circuit the chain and prompt the router to return the current // response object as-is, skipping any remaining middleware and the route callback function barMiddleware(WP_REST_Request $req, WP_REST_Response $res, callable $next) { // continue the chain if my-param is truthy if ($req->get_param('my-param')) { $next(); } // otherwise stop the chain and return the response as-is } // any callable can be added as a middleware with the use method // middleware functions are called in the order that they are added $router->use('fooMiddleware'); $router->use('barMiddleware');
中间件也可以应用于范围路由。
use O\WordPress\Rest\Router; $router = new Router('my-namespace'); function fooMiddleware(WP_REST_Request $req, WP_REST_Response $res, callable $next) { $res->header('x-foo', true); $next(); } function barMiddleware(WP_REST_Request $req, WP_REST_Response $res, callable $next) { $res->header('x-bar', true); $next(); } // apply the foo middleware to all incoming requests $router->use('fooMiddleware'); $router->route('scoped-route', function ($scope) { // apply the barMiddleware to all requests within this scope only // middleware applied to all requests will run first $scope->use('barMiddleware'); });
WP Rest Router主要保留了原生WordPress API注册路由的一些功能,包括权限回调和查询参数模式,几乎没有改变。
use O\WordPress\Rest\Router; $router = new Router('my-namespace'); // get, post, put, patch, and delete methods return a Route object // Routes have two chainable methods, setPermission and setArg $router ->get('foo', 'MyController@foo') // set a permission callback on the route // @see https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#permissions-callback ->setPermission(function () { return current_user_can('edit_others_posts'); }); $router ->get('bar', 'MyController@bar') // set query parameter schemas on routes // @see https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#arguments ->setArg('my-param', [ 'required' => true, 'type' => 'integer', ]);
WP Rest Router将所有中间件和路由回调包装在单个try-catch中,将异常转换为WP_Error
对象。这使得您可以安全地抛出常规异常并从客户端获得有效的响应。
use O\WordPress\Rest\Router; $router = new Router('my-namespace'); $router->get('foo', function (WP_REST_Request $req, WP_REST_Response $res) { // if nothing else catches this exception, wp rest router will catch it // and convert it to a WP_Error object which will be returned to the client by WordPress throw new \Exception('oops!'); });
开发
要求
- composer
- docker
- docker-compose
- php 7.1
安装依赖项
$ composer install
代码风格检查
$ composer lint $ composer analyse
测试
$ composer test:unit
集成测试需要WordPress和MySql docker容器正在运行
$ composer:docker-up
$ composer test:integration
贡献
所有更改都需要有自己的分支,拉取请求应简洁且范围有限。CI作业由github actions运行,并在推送提交时自动触发。PR必须通过CI中运行的测试,并获得批准后才能合并。