fizk/router 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

fizk/router

Composer 安装命令:

composer require fizk/router

包简介

A very simple PSR-7 Router

README 文档

README

A very simple PRS-7 compatible router.

How it works.

This Router doesn't try to be smart or clever. It doesn't have an opinion on what's it's routing. It doesn't re-write a route expression into RegExp, instead, it wants the expression to be expressed in a Regular Expression upfront. This allows greater control on what will be match against a URI.

This Router is constructed as a tree. This makes the Router that just a little bit faster as it doesn't need to go through a whole list (and every route definition) to find a match.

2 3 4 1

How to use it.

Define a Route, give it a name, an Expression and the Parameters you want returned when the Route is a match, then match it against a PSR-7 Request

use Fizk\Router\Route;
use Laminas\Diactoros\Request;

$routes = new Route(
    'root',
    '/path/(?<id>\d+)',
    ['handler' => SomeHandler::class]
);

$request = new Request('http://this.is/path/1');

$match = $routes->match($request);

print_r($match->getAttributes())
// Will print
//[
//  'id' => '1'
//]

print_r($match->getParams())
// Will print
//[
//  'handler' => 'Namespace\\SomeHandler'
//]

As you can see, there is none of that /path/:id syntax, instead you need to write the full expression. If you want to capture the Attributes in the URI, you have to give them a name by using Named Captures

Nested routes.

Let's say we have a root path: /path and then we can have either numbers or letters as Attributes and we want different handlers/controller to run depending on which type Attribute is provided. We can express it like this:

use Fizk\Router\Route;
use Laminas\Diactoros\Request;

$routes = (new Route('path', '/path', []))
    ->addRoute(new Route('letters', '/(?<id>[a-z]+)', ['controller' => SomeLetterController::class]))
    ->addRoute(new Route('number', '/(?<slug>\d+)', ['controller' => SomeNumberController::class]))
    ;

echo $routes->match(new Request('http://this.is/path/1'))->getParam('handler');
// Will print
// Namespace\\SomeNumberController

echo $routes->match(new Request('http://this.is/path/arg'))->getParam('handler');
// Will print
// Namespace\\SomeLetterController

Routes can be nested "infinitely" deep.

The Router Class.

Defining routes with the ->addRoute(...) syntax can be a bit verbose. This library provides a class than can take in configuration as an array and build the Router Tree, that way the router configuration is a little bit simpler to manage.

// router.config.php
return [
    'base' => [
        'pattern' => '/',
        'options' => ['handler' => 'IndexHandler'],
    ],
    'albums' => [
        'pattern' => '/albums',
        'options' => ['handler' => 'AlbumsHandler'],
        'children' => [
            'album' => [
                'pattern' => '/(?<id>\d+)',
                'options' => ['handler' => 'AlbumHandler'],
            ],
        ]
    ],
];
// index.php

$router = new Router(require './router.config.php');

$request = new Request('http://example.com/albums/1');
echo $router->match($request)->getParams('handler');

// Will print
// AlbumHandler

The array key will become the name of the Route. The required pattern and options keys will be passed to the Route instance. An optional children key can be defined, those routes will become children of the parent route.

Because this class has all the configuration inside of it, it can provide a method called public function construct(string $path, ?array $arguments = []): ?string; It can construct a URI based off the names you have given to the Routes. An example of this would be:

$config = [
    'index' => [
        'pattern' => '/',
        'options' => ['handler' => 'IndexHandler'],
    ],
    'albums' => [
        'pattern' => '/albums',
        'options' => ['handler' => 'AlbumsHandler'],
        'children' => [
            'album' => [
                'pattern' => '/(?<id>\d+)',
                'options' => ['handler' => 'AlbumHandler'],
            ],
        ]
    ],
];

$router = new Router($config);
echo $router->construct('albums/album', ['id' => 1]);

// This will print
//  /albums/1

Example

This examples uses Fizk\Router in conjunction with Psr\Http\Message\ResponseInterface and Psr\Http\Message\ServerRequestInterface. What is important to understand is that the Router is not going in inject any values from the URI into the $responce object or invoke the Controller/Handler. These are things you have to manage on your own.

The benefit of this is that the Router is not dependent on how Controllers/Handlers are implemented or which PSR standard it is using.

use Fizk\Router\Route;
use Laminas\Diactoros\Request;
use Laminas\Diactoros\Response\JsonResponse;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

//Define Handlers/Controllers
class SomeNumberController implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $id = $request->getAttribute('id');
        $data = $service->getById($id);
        return new JsonResponse($data);
    }
}

class SomeLetterController implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $slug = $request->getAttribute('slug');
        $data = $service->getBySlug($slug);
        return new JsonResponse($slug);
    }
}

class ResourceNotFoundController implements RequestHandlerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        return new JsonResponse(['message' => 'Resource Not Found'], 404);
    }
}

// Create a Request Object, pulling CGI values from global scope
$request = ServerRequestFactory::fromGlobals(
    $_SERVER,
    $_GET,
    $_POST
    $_COOKIE,
    $_FILES
);
// Define an Emitter, which will set HTTP headers and body before delivering to client
$emitter = new SapiEmitter();

// Define Routes
$routes = (new Route('path', '/path', []))
    ->addRoute(new Route('letters', '/(?<id>[a-z]+)', ['controller' => new SomeLetterController()]))
    ->addRoute(new Route('number', '/(?<slug>\d+)', ['controller' => new SomeNumberController]))
    ;

// ...OR USE THE MORE COMPACT WAY OF DEFINING ROUTES
$routes = new Router([
    'path' => [
        'pattern' => '/path',
        'options' => []
        'children' => [
            'letters' => [
                'pattern' => '/(?<id>[a-z]+)',
                'options' => ['controller' => new SomeLetterController()]
            ],
            'numbers' => [
                'pattern' => '/(?<slug>\d+)',
                'options' => ['controller' => new SomeNumberController()]
            ],
        ]
    ]
]);

// Match Routes against Request Object
$match = $routes->match($request);

if ($match) {
    //Add attributes from URI to the Request Object
    foreach ($match->getAttributes() as $name => $value) {
        $request = $request->withAttribute($name, $value);
    }

    // Run the Handler/Controller
    $response = $match->getParam('controller')->handle($request);

    // Emit a Response back to client
    $emitter->emit($response);
} else {
    // Run the Error Handler/Controller
    $response = (new ResourceNotFoundController())->handle($request);

    // Emit a Response back to client
    $emitter->emit($response);
}

统计信息

  • 总下载量: 84
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-02-09

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固