如何用Nette Router实现数据库页面映射至域名根并兼容现有路由
Nette Router 配置:优先匹配数据库页面路径
问题背景
当前路由形式:
/posts/post1-url /posts/post2-url/slashed
期望路由形式:
/post1-url /post2-url/slashed
需要让Nette Router优先匹配数据库中的路径字符串,匹配失败后再走现有路由规则,现有路由代码如下:
public static function createRouter(): RouteList { $router = new RouteList; $router->addRoute('/', 'Home:default'); $router->addRoute('/auth', 'Auth:default'); $router->addRoute('/auth/<action>', 'Auth:<action>'); $router->addRoute('/admin', 'Admin:default'); $router->addRoute('/admin[/<action>][/<slug>]', 'Admin:<action>'); $router->addRoute('/<slug>', 'Home:viewPage'); $router->addRoute('<presenter>/<action>', '<presenter>:<action>'); return $router; }
已有处理数据库文章的Presenter动作,需将数据库匹配逻辑与RouteList结合。
解决方案
核心思路
Nette Router按路由添加顺序匹配,优先级从上到下。只需在路由链最前端加入数据库匹配逻辑即可实现优先匹配。
方法1:回调路由(轻量推荐)
修改createRouter方法,在最前面添加回调路由实现数据库匹配:
public static function createRouter(): RouteList { $router = new RouteList; // 1. 优先匹配数据库页面路径 $router->addRoute('<path .+>', function (array $params): ?array { $requestedPath = $params['path']; // 替换为你的数据库查询逻辑:检查路径是否存在 $page = YourPageModel::findOneBy(['url' => $requestedPath]); if ($page) { // 匹配成功,返回对应Presenter、Action及参数 return [ 'presenter' => 'Home', // 替换为处理数据库页面的Presenter 'action' => 'viewPage', // 替换为对应Action 'slug' => $page->slug, // 传递页面标识给Action ]; } // 匹配失败,返回null,交由后续路由处理 return null; }); // 2. 原有路由规则保持不变 $router->addRoute('/', 'Home:default'); $router->addRoute('/auth', 'Auth:default'); $router->addRoute('/auth/<action>', 'Auth:<action>'); $router->addRoute('/admin', 'Admin:default'); $router->addRoute('/admin[/<action>][/<slug>]', 'Admin:<action>'); $router->addRoute('/<slug>', 'Home:viewPage'); $router->addRoute('<presenter>/<action>', '<presenter>:<action>'); return $router; }
说明:
<path .+>匹配任意非空路径,覆盖所有可能的数据库页面路径- 回调内完成数据库查询,匹配成功则返回路由参数,失败则放行给后续规则
- 建议给数据库
url字段加索引,提升查询效率
方法2:自定义Route类(复杂场景适用)
若需更复杂的匹配逻辑,可自定义Route类继承Nette\Routing\Route,重写match方法:
class DatabasePageRoute extends \Nette\Routing\Route { public function match(\Nette\Http\IRequest $request): ?array { $path = ltrim($request->getUrl()->getPath(), '/'); $page = YourPageModel::findOneBy(['url' => $path]); if ($page) { return [ 'presenter' => 'Home', 'action' => 'viewPage', 'slug' => $page->slug, ]; } // 不匹配则返回null,交给后续路由 return null; } }
然后在createRouter中添加:
$router->addRoute(new DatabasePageRoute); // 后续接原有路由规则
注意事项
- 路由顺序:数据库匹配路由必须放在最前面,确保优先级最高
- 性能优化:频繁数据库查询会影响性能,可通过Nette Cache组件或Redis缓存已存在的路径
- 冲突处理:确保数据库路径不会与
/auth、/admin等系统路由重复,或在查询时排除这些系统路径
内容的提问来源于stack exchange,提问作者PM_KLS
相关产品推荐
相关产品推荐

