让 FastRoute 支持 URL 反向解析
FastRoute 是一款高性能路由组件,需要运行于 PHP 7.1 及以上版本。很多 PHP Web 框架都用它作为默认路由。然而这款路由组件不支持 URL 反向解析。
Hyperf 框架也采用了这款路由组件,以下代码可以让 Hyperf 支持 URL 反向解析:
php<?php
/**
* Router.php
**/
declare(strict_types=1);
namespace App\Http;
use Hyperf\HttpServer\Router\Router as BaseRouter;
class Router extends BaseRouter
{
/**
* @var array
*/
protected static $routeMethods = ['get', 'post', 'put', 'delete', 'patch', 'head'];
/**
* @var string
*/
protected static $currentGroupPrefix;
protected static function createUrl($route)
{
return new Url(static::$currentGroupPrefix . $route);
}
public static function addGroup(string $prefix, callable $callback, array $options = [])
{
$previousGroupPrefix = static::$currentGroupPrefix;
static::$currentGroupPrefix = $previousGroupPrefix . $prefix;
$router = static::$factory->getRouter(static::$serverName);
$router->addGroup($prefix, $callback, $options);
static::$currentGroupPrefix = $previousGroupPrefix;
}
public static function addRoute($httpMethod, string $route, $handler, array $options = [])
{
$router = static::$factory->getRouter(static::$serverName);
$router->addRoute($httpMethod, $route, $handler, $options);
return static::createUrl($route);
}
public static function __callStatic($name, $arguments)
{
$returnValue = parent::__callStatic($name, $arguments);
return in_array($name, static::$routeMethods) ? static::createUrl($arguments[0]) : $returnValue;
}
}
php<?php
/**
* Url.php
**/
declare(strict_types=1);
namespace App\Http;
use FastRoute\RouteParser\Std as RouteParser;
use LogicException;
class Url
{
/**
* @var string
*/
public $route;
/**
* @var string
*/
public $name;
public function __construct(string $route)
{
$this->route = $route;
}
public function name(string $name)
{
$this->name = $name;
UrlManager::getManager()->addUrl($this);
return $this;
}
public function parse(...$arguments)
{
$routeParser = new RouteParser;
$routes = $routeParser->parse($this->route);
foreach ($routes as $route) {
$parsedUrl = '';
$i = 0;
foreach ($route as $part) {
if (is_string($part)) {
$parsedUrl .= $part;
continue;
}
if ($i === count($arguments)) {
throw new LogicException('Not enough parameters given');
}
$parsedUrl .= $arguments[$i++];
}
if ($i === count($arguments)) {
return $parsedUrl;
}
}
throw new LogicException(
sprintf('The arguments does not matched for the route \'%s\'.', $this->name)
);
}
}
php<?php
/**
* UrlManager.php
**/
declare(strict_types=1);
namespace App\Http;
use RuntimeException;
class UrlManager
{
/**
* @var UrlManager
*/
protected static $manager;
/**
* @var array
*/
protected $urls = [];
public function addUrl(Url $url)
{
if (isset($this->urls[$url->name])) {
throw new RuntimeException(
sprintf('Cannot add the url named \'%s\'. A duplicate name exists.', $url->name)
);
}
$this->urls[$url->name] = $url;
}
public function reverse(string $name, ...$arguments)
{
if (! isset($this->urls[$name])) {
throw new RuntimeException(
sprintf('The url named \'%s\' does not exists.', $name)
);
}
return $this->urls[$name]->parse(...$arguments);
}
/**
* @return UrlManager
*/
public static function getManager()
{
if (! isset(static::$manager)) {
static::$manager = new static();
}
return static::$manager;
}
}
修改项目中的 config\routes.php
配置文件:
php<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact [email protected]
* @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
*/
use App\Http\Router;
Router::get('/user/{id}', 'App\Controller\UserController@info')->name('user-info');
使用 URL 反向解析:
php<?php
use App\Http\UrlManager;
// 返回 '/user/123'
$url = UrlManager::getManager()->reverse('user-info', 123);