sevens / router

遵守PSR-7规范的简单、高效PHP Web应用路由库

v1.1.0 2021-03-27 09:39 UTC

This package is auto-updated.

Last update: 2024-09-27 16:57:33 UTC


README

=> Seven Router is developed by Elisha Temiloluwa [ TemmyScope ]	

=> The Library uses the PHP-DI dependency container to inject dependencies.

=> The Library has been completely unit tested and is ready for use.

安装

composer require sevens/router

PHP >=7.4 性能优化

=> Use preloader to preload the cached route file after compilation on a production server.

Seven\Router\Router: 使用方法

初始化类

use \Seven\Router\Router;

#namespace: refers to the namespace from which the classes should be loaded
$route = new Router($namespace = 'App\Controllers');

性能优化和缓存

=> To Improve performance on a production server, you should enable cache.

缺点:每次添加新路由时,您必须从缓存目录中删除缓存文件,以便重新加载新路由。

$route->enableCache($directory = __DIR__.'/cache');

注册PSR-7兼容的/实现请求和响应对象

=> This is an optional feature; You don't have to register PSR-7 request & response objects
/**
* @param $request
* @param $response
* 
* @return void
*/
$route->registerProviders($request, $response);

注册您在路由调用中想要使用的中间件:: 所有可调用对象都适用

**注意:已注册的中间件仅在关联的路由匹配/找到后运行/加载。
在匹配路由之前运行中间件只能通过在我们的应用程序中实现它或通过扩展路由来实现。

"next" 是PSR-15 RequestHandlerInterface的对象

=> This means the handle method is available as well as it can be invoked like a function.

注意:只有当您注册了实现PSR-7接口的请求和响应对象时,才能使用"next"对象的"handle"方法;否则,只需将next作为函数|闭包调用即可,即 next(request, response)

$route->middleware('auth', function($request, $response, RequestHandlerInterface $next){
 #do something with request or set headers for response
	
 #if required conditions are met do:
 $next->handle($request);
});

当路由定义在不同的文件中时,这是最好的。

=> route definition are included/required/loaded into the current file

=> Note: routes can also be defined in the front controller (i.e. in your index.php);
require __DIR__.'/routes.php';

路由过程从这里开始

=> The "run" method processes routes and calls the appropriate action if the request succeeds.
$route->run(
 $_SERVER['REQUEST_METHOD'], 
 $_SERVER['REQUEST_URI'] ?? $_SERVER['PATH_INFO'] ?? '/'
);

路由文件中的路由定义,该文件在前端控制器(例如index.php)中要求

=> All Standard Http Methods are supported: GET, POST, PUT, OPTIONS, PATCH, HEAD, DELETE;

=>All methods accept a callable as the second parameter 

=>All callables are injected with the request & response objects that were previously registered
$route->get('/post/:id/creator/:name', function($request, $response){

});

同一路由的多种方法

$route->addRoute(['OPTIONS', 'GET'], 'home', [HomeController::class, 'index']);

要使所有请求到某个端点的调用返回相同的可调用对象,请使用"all"方法

$route->all('/posts', function($request, $response){
 return $response->send("This handles all requests to /posts endpoint, regardless of request method");
});

uri中的所有参数都可通过请求参数对象访问

$route->put('/post/:key', function($request, $response){
 return $response->send("This is a request containing key: ". $request->params->key )
});

使用"use"方法在返回端点的可调用对象之前调用已注册的中间件

=> The middlewares are called in the order in which they were written/passed

=> The second parameter passed to the "use" method must be a closure that accepts no parameter
#cors middleware is called first in this case.
$route->use(['middleware' => ['cors', 'auth'],'prefix'=>'api' ], function() use ($route){
 $route->get('/post/:id', function($request, $response){
 
 });

 # request & response objects are passed as arguments automagically
 $route->post('/post', [ PostController::class, 'create' ]);

});

Use关键字的简写

=> There is a shorthand way to use the "use" method (Of-course it is negligibly slower, if you're performance-anxious)
$route->use('cors,auth;prefix:api;', function() use ($route){
 $route->get('/post/:id', function($request, $response){

 });
	
 # request & response objects are passed as arguments automagically
 $route->post('/post', [ PostController::class, 'create' ]);

});

#start with a ';' if no middleware is being used
$route->use(';prefix:api/test;', function() use ($route){

});

Apache - .HTACCESS

=> An example .htaccess directive file fit for this router would look sth like this: 
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond $1 !^(cdn|robots.txt)
    RewriteRule ^(.*)$ index.php/$1 [L]
</IfModule>

NGINX站点配置指令

=> An example nginx configuration directive fits for this router would look sth like this: 
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

真实应用场景中的示例用法

use Seven\Router\Router;
use Symfony\Component\HttpFoundation\{Request, Response};
use App\Auth;

/*
|---------------------------------------------------------------------------|
| Register The Auto Loader 																									|
|---------------------------------------------------------------------------|
|
*/
require __DIR__.'/vendor/autoload.php';

$request = Request::createFromGlobals();
$response = new Response();

/**
* @package  SevenPHP
* @author   Elisha Temiloluwa <temmyscope@protonmail.com>
|-------------------------------------------------------------------------------|
|	SevenPHP by Elisha Temiloluwa a.k.a TemmyScope 																|
|-------------------------------------------------------------------------------|
*/
$router = new Router('App\Controllers');

//$router->enableCache(__DIR__.'/cache');

$router->registerProviders($request, $response);

$router->middleware('cors', function($request, $response, $next){
 $headers = [
  'Access-Control-Allow-Origin'      => '*',
  'Access-Control-Allow-Methods'     => '*',
  'Access-Control-Allow-Credentials' => 'true',
  'Access-Control-Max-Age'           => '86400',
  'Access-Control-Allow-Headers'     => 'Content-Type, Authorization, X-Requested-With'
 ];
 if ($request->isMethod('OPTIONS')){
 	return $response->send('{"method":"OPTIONS"}', 200, $headers);
 }
 foreach($headers as $key => $value){
  $response->headers->set($key, $value);
 }
 $next($request, $response);
});

$router->middleware('auth', function($request, $response, $next){
 $token = $request->getHeader('Authorization');
 if ( !$token || Auth::isValid($token) ) {
	return $response->send('Unauthorized.', 401);
 }
 $request->userId = Auth::getValuesFromToken($token)->user_id;
 $next->handle($request);
});

require __DIR__.'/routes/web.php';

$router->run(
 $_SERVER['REQUEST_METHOD'], 
 $_SERVER['REQUEST_URI'] ?? $_SERVER['PATH_INFO'] ?? '/'
);

在利用Symfony/http-foundation的应用程序中使用PSR-7请求-响应处理器的示例用法

注意:并非所有PSR-7兼容请求和响应处理器的使用都是这样有压力的。
给出此示例是因为它可能是最复杂的场景用法。

use Seven\Router\Router;
use Nyholm\Psr7\Factory\Psr17Factory;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use Symfony\Component\HttpFoundation\{Request, Response};
use App\Auth;

/*
|---------------------------------------------------------------------------|
| Register The Auto Loader 																									|
|---------------------------------------------------------------------------|
|
*/
require __DIR__.'/vendor/autoload.php';

$psr17Factory = new Psr17Factory();
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);

$request = $psrHttpFactory->createRequest(Request::createFromGlobals());

$response = $psrHttpFactory->createResponse(new Response());

/**
* @package  SevenPHP
* @author   Elisha Temiloluwa <temmyscope@protonmail.com>
|-------------------------------------------------------------------------------|
|	SevenPHP by Elisha Temiloluwa a.k.a TemmyScope 																|
|-------------------------------------------------------------------------------|
*/

$router = new Router('App\Controllers');

$router->registerProviders($request, $response);

$router->middleware('cors', function($request, $response, $next){
 $headers = [
  'Access-Control-Allow-Origin'      => '*',
  'Access-Control-Allow-Methods'     => '*',
  'Access-Control-Allow-Credentials' => 'true',
  'Access-Control-Max-Age'           => '86400',
  'Access-Control-Allow-Headers'     => 'Content-Type, Authorization, X-Requested-With'
 ];
 if ($request->getMethod() === 'OPTIONS'){
  return $response->send('{"method":"OPTIONS"}', 200, $headers);
 }
 foreach($headers as $key => $value){
  $response->withHeader($key, $value);
 }
 $next->handle($request);
});

$router->middleware('auth', function($request, $response, $next){
 $token = $request->getHeader('Authorization');
 if ( !$token || Auth::isValid($token) ) {
	return $response->send('Unauthorized.', 401);
 }
 $request->userId = Auth::getValuesFromToken($token)->user_id;
 $next->handle($request);
});

require __DIR__.'/routes/web.php';

$router->run( 
 $_SERVER['REQUEST_METHOD'], 
 $_SERVER['REQUEST_URI'] ?? $_SERVER['PATH_INFO'] ?? '/'
);

注意:不带参数的路由比接受参数的路由解析得更快