maer/router

一个小型、简单、可扩展的单文件PHP路由器,具有分组、过滤器和命名路由功能

1.5.2 2019-12-18 15:47 UTC

This package is auto-updated.

Last update: 2024-09-19 02:16:12 UTC


README

Build Status

一个小型、简单、可扩展的单文件PHP路由器,具有分组、过滤器和命名路由功能

我并不声称这个路由器比其他路由器更快或更好。打败像nikic/FastRoute这样的东西有点困难。构建这个的主要原因有两个:1. 我想要一个简单但灵活的路由器,即插即用,几乎无需配置。2. 建造东西很有趣,你也会从中学到很多东西!

使用方法

安装

克隆此存储库或使用composer通过以下命令下载库

composer require maer/router dev-master

dev-master更改为最后一个已标记的版本。

简单示例

// Load composers autoloader
include '/path/to/vendor/autoload.php';

$r = new Maer\Router\Router;

// Define routes
$r->get('/', function() {
    return "Hello there";
});

// It also works with:
$r->post('/', function() {});
$r->put('/', function() {});
$r->delete('/', function() {});
$r->patch('/', function() {});
$r->options('/', function() {});
$r->head('/', function() {});
$r->connect('/', function() {});
$r->trace('/', function() {});
$r->any('/', function() {}); // Catches all methods

// ...or if you want to use some non-standard HTTP verb
$r->add('SOMEVERB', '/', function() {});

// ...or if you want to define multiple verbs at once
$r->add(['GET', 'POST', ...], function() {});

// Dispatch the router
$response = $r->dispatch();

echo $response;

路由参数

你可以使用一些占位符来使用路由参数。所有参数都将按照在路由中定义的顺序传递给控制器

// Match any alpha [a-z] character
$r->get('/something/(:alpha)', function($param) {
    // Do stuff
});

// Match any numeric [0-9.,] character. It can also start with a -
$r->get('/something/(:num)', function($param) {
    // Do stuff
});

// Match any alphanumeric [a-z0-9] character
$r->get('/something/(:alphanum)', function($param) {
    // Do stuff
});

// Match any character (except /) [^/] character
$r->get('/something/(:any)', function($param) {
    // Do stuff
});

// Catch-all. Match all routes, including / (.*)
$r->get('/something/(:any)', function($param) {
    // Do stuff
});

// Append ? to making a parameter optional.
$r->get('/something/(:alpha)?', function($param = null){
    // Matches /something and /something/anything
});

// Combine mutliple placeholders
$r->get('/something/(:alpha)/(:any)/(:alphanum)?', function($param, $param2, $param3 = null) {
    // Do stuff
});

路由回调

路由回调可以以不同的方式定义

// Anonymous function
$r->get('/', function() {
    // Something
});

// Class method
$r->get('/', ['Namespace\ClassName', 'methodName']);
// or
$r->get('/', 'Namespace\ClassName@methodName');

// Static class method
$r->get('/', 'Namespace\ClassName::methodName');

所有回调都将接收任何路由参数。

如果你发送一个类方法(非静态),当路由器分发并且找到匹配项时,路由器将实例化该类然后调用该方法。

过滤器

beforeafter过滤器

// Defining filters
$r->filter('myfilter', function() {
    // Do some magic stuff.
});

$r->filter('anotherfilter', function() {
    // Do some magic stuff.
});

// Add filter to your routes
$r->get('/something/', function() {

}, ['before' => 'myfilter', 'after' => 'anotherfilter']);

// Add multiple filters by combining them with |
$r->get('/something/', function() {

}, ['before' => 'myfilter|anotherfilter']);

过滤器回调可以与路由回调相同的格式,这意味着你可以将类方法用作过滤器。

在过滤器之前,将接收所有路由参数,就像路由回调一样。在过滤器之后,也将接收所有参数,但第一个参数将是路由回调的响应。

注意:过滤器的调用顺序与它们定义的顺序相同。如果任何过滤器返回的不是null,则分发将停止,并返回该响应。

命名路由

给任何路由添加一个名称

// Name a route
$r->get('/something', function() {

}, ['name' => 'some-page']);

// Resolve a named route
echo $r->getRoute('some-page');
// Returns: /something

// With route parameters
$r->get('/something/(:any)/(:any)', function($param1, $param2) {

});

// Resolve and pass values for the placeholders
echo $r->getRoute('some-page', ['first', 'second']);
// Returns: /something/first/second

如果你没有传递足够的参数来覆盖所有必需的参数,将抛出异常。

添加基本URL

默认情况下,路由器返回不带基本URL(协议 + 主机名)的路径

但是,如果你想使getRoute()的响应包括基本URL,你需要设置基本URL

$r->baseUrl('http://foo.bar');

现在,当你想要获取一个命名路由时,你可以传递一个布尔值作为第三个参数。 true = 包含基本URL,false = 不包含。

$r->getRoute('some-page', [], true);
// Returns: http://foo.bar/something

如果你不想传递第三个参数,而是默认返回基本URL,你可以使用以下方式设置它

$r->alwaysPrependBaseUrl(true);

如果你调用getRoute()而不传递第三个参数,它将始终添加基本URL,除非你将false作为第三个参数传递给getRoute()

分组路由

为了避免为许多路由重复添加相同的过滤器,最好将它们分组在一起。

$r->group(['before' => 'a_before_filter'], function($r) {

    $r->get('/', function() {
        //....
    });

    // Just keep defining routes

});

$r->group()-方法仅接受匿名函数作为回调。路由器实例始终作为参数传递给回调。

在定义分组时,你可以添加与路由相同的beforeafter过滤器。你还可以像下面描述的那样为分组使用前缀。

分组前缀

要为分组添加相同的前缀,请使用prefix参数。

$r->group(['prefix' => '/admin'], function() {

    // This matches: /admin
    $r->get('/', function() {

    });

    // This matches: /admin/something
    $r->get('/something', function() {

    });

});

在创建分组时,您可以混合使用beforeafterprefix

CRUD 路由

为了简化 CRUD 路由的创建,存在一个crud()函数。

$r->crud('/posts', 'PostsController', [
    'name' => 'posts',
]);

上面等同于您定义以下路由

$r->get('/posts', 'PostsController@many', [
    'name' => 'posts.many'
]);

$r->get('/posts/(:any)', 'PostsController@one', [
    'name' => 'posts.one'
]);

$r->post('/posts', 'PostsController@create', [
    'name' => 'posts.create'
]);

$r->put('/posts/(:any)', 'PostsController@update', [
    'name' => 'posts.update'
]);

$r->delete('/posts/(:any)', 'PostsController@delete', [
    'name' => 'posts.delete'
]);

当然,您也可以在分组内使用crud()函数。

重定向

您还可以将路由器注册为重定向某些 URL。

注意:所有重定向路由都将触发在已注册的路由之前。

注册重定向

// A simple redirect
$r->redirect('/from/path', '/to/path');

// It works with absolute targets as well
$r->redirect('/foo', 'https://example.com');

// You can also register a named route as target
$r->redirect('/foo', null, [
    'route' => ['someRouteName'],
    // Add route arguments, if needed
    'params'  => ['argument1', 'argument2', ...]
]);

// If you want to redirect using another http code than 307 (default)
$r->redirect('/foo', '/bar', [
    'code' => 301
]);

您还可以在重定向上注册before过滤器。

将当前请求重定向到命名路由

使用上述方法注册重定向时,它将在调度时处理,就像任何其他路由一样。

有时您可能希望立即重定向用户,也许在路由器已经调度之后(甚至之前)。您可以使用toRoute()来做到这一点。

// Make a redirect to a named route
$r->toRoute('someRouteName', [
    'argument1',
    'argument2',
    ...
]);

// With another http code than 307 (default)
$r->toRoute('someRouteName', [], 301);

上面的代码将立即重定向请求。这就像执行header('location: ...')一样。

分发路由器

要调度路由器,通常只需要调用$r->dispatch()方法即可。然而,如果您想要使用特定的 URL 和方法调度路由器(这在编写测试时很有用),可以将它们传递给调度器。

$response = $r->dispatch('GET', '/some/url');

如果您想自己触发所有回调(过滤器和路由回调),例如,如果您正在使用 IoC 容器,请调用$r->getMatch()方法,您将获得匹配的路由对象。

$r->get('/', function() {

}, ['before' => 'beforefilter', 'after' => 'afterfilter', 'name' => 'somename']);

$route = $r->getMatch('GET', '/');

// Returns:
// object =>
//     pattern   => "/group1"
//     name      => "somename",
//     callback  => object(Closure)#8 (0) {}
//     before    => ['beforefilter'],
//     after     => ['afterfilter'],
//     args      => []
//     method    => "GET"

如果before和after过滤器是闭包,您可以通过以下方式触发它们

$response = $r->executeCallback('beforefilter');

未找到

如果没有匹配,将抛出Maer\Router\NotFoundException异常。您可以使用$router->notFound()方法注册一个将被执行的回调。

$r->notFound(function() {
    return "Ops! The page was not found!";
});

// Callbacks can be in all the same formats as for routes

不允许的方法

如果存在 URL 匹配,但使用了错误的 HTTP 方法,将抛出Maer\Router\MethodNotAllowedException异常。您可以使用$router->methodNotAllowed()方法注册一个将被执行的回调。

$r->methodNotAllowed(function() {
    return "Ops! Method not allowed!";
});

// Callbacks can be in all the same formats as for routes

添加自定义回调解析器

如果您的回调格式为['Classname', 'method'],您可能希望自定义其解析方式。如果您,例如,正在使用某种 IoC 并进行依赖注入,这将很有用。

要创建自定义解析器,请使用$r->resolver()方法。示例

$r->resolver(function($callback) use($container) {
    // The argument will always be an array with ['Class', 'method']
    return [
        $container->get($callback[0]),
        $container[1]
    ];
});

发布说明

1.5.0

1.4.0

  • 添加了crud()方法。

如果您有任何问题、建议或问题,请告诉我!

编码愉快!