nezamy / route
Route - 为 PHP 提供快速灵活的路由功能,使您能够快速轻松地构建 RESTful 网络应用程序。
v2.0-beta
2020-09-17 09:22 UTC
Requires
- php: >=5.4.0
- nezamy/support: 1.0.*
README
Route - 为 PHP 提供快速灵活的路由功能,使您能够快速轻松地构建 RESTful 网络应用程序。
安装
$ composer require nezamy/route
或者,如果您正在寻找使用此路由的现成模板,请访问 https://github.com/nezamy/just
Route 需要 PHP 7.4.0 或更高版本。
变更列表
- 基于 php 7.4 重写路由
- 支持 Swoole 扩展
- 支持地区以构建多语言网站
- 添加了 Auth、Basic、Digest
- 可自定义路由解析器和处理器
- 智能依赖注入和服务容器
用法
仅当使用 composer 时,在根目录中创建 index.php。
创建一个包含以下内容的 index.php 文件
<?php declare(strict_types=1); define('DS', DIRECTORY_SEPARATOR); define('BASE_PATH', __DIR__ . DS); //Show errors //=================================== ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); //=================================== require BASE_PATH.'vendor/autoload.php'; $request = new Just\Http\GlobalRequest; $response = new Just\Http\Response; $route = new Just\Routing\Router($request, $response); // let store them to container, to use them as a singleton container()->set(Just\Http\Request::class, $request); container()->set(Just\Http\Response::class, $response); container()->set(Just\Routing\Router::class, $route); try { include 'app/routes.php'; $output = $route->run(); foreach ($output->headers->all() as $k => $v) { header("$k: $v"); } http_response_code($output->statusCode()); if ($output->hasRedirect()) { list($url, $code) = $output->getRedirect(); header("Location: $url", true, $code); } } catch (\Error $e) { pre($e, 'Error', 6); } catch (\Exception $e) { pre($e, 'Exception', 6); } echo response()->body();
app/routes.php
<?php use Just\Route; Route::get('/', function (){ return 'Welcome to the home page'; }); // Maybe you want to customize 404 page Route::setNotfound(function (){ return 'Page Not found'; });
与 Swoole 一起使用
<?php declare(strict_types=1); use Swoole\Http\Server; use Swoole\Http\Request; use Swoole\Http\Response; use Just\Routing\Router; ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); error_reporting(E_ALL); require __DIR__ . '/vendor/autoload.php'; $http = new Server("0.0.0.0", 9501); $http->set([ 'document_root' => '/var/www/public', 'enable_static_handler' => true, ]); $http->on("request", function (Request $request, Response $response) { $request = new Just\Http\Request( $request->header ?? [], $request->server ?? [], $request->cookie ?? [], $request->get ?? [], $request->post ?? [], $request->files ?? [], $request->tmpfiles ?? [] ); $response = new Just\Http\Response; $route = new Just\Routing\Router($request, $response); container()->set(Just\Http\Request::class, $request); container()->set(Just\Http\Response::class, $response); container()->set(Router::class, $route); try { include __DIR__ .'/app/routes.php'; $output = $route->run(); foreach ($output->headers->all() as $k => $v) { $response->header($k, $v); } $response->setStatusCode($output->statusCode()); if ($output->hasRedirect()) { list($url, $code) = $output->getRedirect(); $response->redirect($url, $code); } } catch (\Error $e) { pre($e, 'Error', 6); } catch (\Exception $e) { pre($e, 'Exception', 6); } $response->end(response()->body(true)); }); $http->start();
工作原理
通过将 URL 模式与回调函数匹配来执行路由。
app/routes.php
Route::any('/', function() { return 'Hello World'; }); Route::post('/contact-us', function(\Just\Http\Request $req) { pre($req->body, 'Request'); });
回调可以是任何可调用的对象。因此,您可以使用常规函数
function pages() { return 'Page Content'; } Route::get('/', 'pages');
或类方法
class home { public function pages() { return 'Home page Content'; } } Route::get('/', [home::class, 'pages']); // OR Route::get('/', 'home@pages');
方法路由
Route::any('/', function() {}); Route::get('/', function() {}); Route::post('/', function() {}); Route::put('/', function() {}); Route::patch('/', function() {}); Route::option('/', function() {}); Route::delete('/', function() {});
参数
// This example will match any page name Route::get('/{page}', function($page) { return "you are in $page"; }); Route::get('/post/{id}', function($id) { // Will match anything like post/hello or post/5 ... // But not match /post/5/title return "post id $id"; }); // more than parameters Route::get('/post/{id}/{title}', function($id, $title) { return "post id $id and title $title"; }); // you can get parameter in any order Route::get('/post/{id}/{title}', function($title, $id) { return "post id $id and title $title"; });
对于“无限”可选参数,您可以这样做
// This example will match anything after blog/ - unlimited arguments Route::get('/blog/{any}:*', function($any) { pre($any); });
正则表达式
您可以使用正则表达式验证参数。
// Validate args by regular expressions uses :(your pattern here) Route::get('/{username}:([0-9a-z_.-]+)/post/{id}:([0-9]+)', function($username, $id) { return "author $username post id $id"; }); // You can add named regex pattern in routes Route::addPlaceholders([ 'username' => '([0-9a-z_.-]+)', 'id' => '([0-9]+)' ]); // Now you can use named regex Route::get('/{username}:username/post/{id}:id', function($username, $id) { return "author $username post id $id"; }); //if the parameter name match the placeholder name just ignore placeholder and route will deduct that Route::get('/{username}/post/{id}', function($username, $id) { return "author $username post id $id"; });
一些已注册在路由中的命名正则表达式模式
[ 'int' => '/([0-9]+)', 'multiInt' => '/([0-9,]+)', 'title' => '/([a-z_-]+)', 'key' => '/([a-z0-9_]+)', 'multiKey' => '/([a-z0-9_,]+)', 'isoCode2' => '/([a-z]{2})', 'isoCode3' => '/([a-z]{3})', 'multiIsoCode2' => '/([a-z,]{2,})', 'multiIsoCode3' => '/([a-z,]{3,})' ];
可选参数
您可以通过添加 (?) 来指定可选的命名参数以进行匹配
Route::get('/post/{title}?:title/{date}?', function($title, $date) { $content = ''; if ($title) { $content = "<h1>$title</h1>"; }else{ $content = "<h1>Posts List</h1>"; } if ($date) { $content .= "<small>Published $date</small>"; } return $content; });
分组
Route::group('/admin', function() { // /admin/ Route::get('/', function() {}); // /admin/settings Route::get('/settings', function() {}); // nested group Route::group('/users', function() { // /admin/users Route::get('/', function() {}); // /admin/users/add Route::get('/add', function() {}); }); // Anything else Route::any('/{any}:*', function($any) { pre("Page ( $any ) Not Found", 6); }); });
带参数的分组
Route::group('/{module}', function($lang) { Route::post('/create', function() {}); Route::put('/update', function() {}); });
地区
// the first language is the default i.e. ar // when you hit the site http://localhost on the first time will redirect to http://localhost/ar Route::locale(['ar','en'], function(){ // will be /ar/ Route::get('/', function($locale){ //get current language pre($locale); }); // /ar/contact Route::get('/contact', function() {}); Route::group('/blog', function() { // /ar/blog/ Route::get('/', function() {}); }); }); // Also you can write locales like that or whatever you want Route::locale(['ar-eg','en-us'], function(){ // will be /ar/ Route::get('/', function($locale){ //get current language list($lang, $country) = explode('-', $locale, 2); pre("Lang is $lang, Country is $country"); }); });
认证
基本认证
$auth = new \Just\Http\Auth\Basic(['users' => [ 'user1' => '123456', 'user2' => '987654' ]]); Route::auth($auth, function (){ Route::get('/secret', function(\Just\Http\Request $req){ pre("Hello {$req->user()->get('username')}, this is a secret page"); }); });
摘要认证
$auth = new \Just\Http\Auth\Digest(['users' => [ 'user1' => '123456', 'user2' => '987654' ]]); Route::auth($auth, function (){ Route::get('/secret', function(\Just\Http\Request $req){ pre("Hello {$req->user()->get('username')}, this is a secret page"); }); });
中间件
全局
Route::use(function (\Just\Http\Request $req, $next){ //validate something the call next to continue or return whatever if you want break if($req->isMobile()){ return 'Please open from a desktop'; } return $next(); }, function ($next){ // another middleware $next(); }); // After Route::use(function ($next){ $response = $next(); // make some action return $response; });
分组上的中间件
// if open from mobile device Route::middleware(fn(\Just\Http\Request $req, $next) => !$req->isMobile() ? '' : $next()) ->group('/mobile-only', function (){ Route::get('/', function(\Just\Http\Request $req){ pre($req->browser()); }); });
如果您将中间件作为类实现,您可以使用命名空间传递该类。该类应具有 handle
方法。
class MobileOnly{ public function handle(\Just\Http\Request $req, $next){ return !$req->isMobile() ? '' : $next(); } } Route::middleware(MobileOnly::class) ->group('/',function (){ Route::get('/', function(\Just\Http\Request $req){ pre($req->browser()); }); });
路由上的中间件
Route::get('/', function(\Just\Http\Request $req){ pre($req->browser()); })->middleware(MobileOnly::class);
依赖注入
有关依赖注入和服务容器的信息,请访问此 链接
处理和解析器自定义
CustomRouteHandler 示例
class CustomRouteHandler implements Just\Routing\RouteHandlerInterface { public function call(callable $handler, array $args = []) { return call_user_func_array($handler, $args); } public function parse($handler): callable { if (is_string($handler) && ! function_exists($handler)) { $handler = explode('@', $handler, 2); } return $handler; } } \Just\Route::setHandler(new CustomRouteHandler);
class CustomRouteParser implements RouteParserInterface { public function parse(string $uri): array { $matchedParameter = []; $matchedPattern = []; $result = []; // parse uri here and return array of 3 elements // /{page} // /{page}? return ['parameters' => $matchedParameter, 'patterns' => $matchedPattern, 'result' => $result]; } } \Just\Route::setParser(new CustomRouteParser);