本文介绍的是typecho的路由机制,引自 不烦恼
路由机制是typecho的核心,有很多功能都是基于路由功能设计的,理解并熟悉TE的路由机制将非常有助于插件的开发。完整的路由表如下:
array (
0 => array ( 'index' => array ( 'url' => '/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^[/]?$|', 'format' => '/', 'params' => array ( ), ), 'do' => array ( 'url' => '/action/[action:alpha]', 'widget' => 'Widget_Do', 'action' => 'action', 'regx' => '|^/action/([_0-9a-zA-Z-]+)[/]?$|', 'format' => '/action/%s', 'params' => array ( 0 => 'action', ), ), 'post' => array ( 'url' => '/archives/[cid:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/archives/([0-9]+)[/]?$|', 'format' => '/archives/%s/', 'params' => array ( 0 => 'cid', ), ), 'attachment' => array ( 'url' => '/attachment/[cid:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/attachment/([0-9]+)[/]?$|', 'format' => '/attachment/%s/', 'params' => array ( 0 => 'cid', ), ), 'category' => array ( 'url' => '/category/[slug]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/category/([^/]+)[/]?$|', 'format' => '/category/%s/', 'params' => array ( 0 => 'slug', ), ), 'tag' => array ( 'url' => '/tag/[slug]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/tag/([^/]+)[/]?$|', 'format' => '/tag/%s/', 'params' => array ( 0 => 'slug', ), ), 'author' => array ( 'url' => '/author/[uid:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/author/([0-9]+)[/]?$|', 'format' => '/author/%s/', 'params' => array ( 0 => 'uid', ), ), 'search' => array ( 'url' => '/search/[keywords]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/search/([^/]+)[/]?$|', 'format' => '/search/%s/', 'params' => array ( 0 => 'keywords', ), ), 'index_page' => array ( 'url' => '/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/page/([0-9]+)[/]?$|', 'format' => '/page/%s/', 'params' => array ( 0 => 'page', ), ), 'category_page' => array ( 'url' => '/category/[slug]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/category/([^/]+)/([0-9]+)[/]?$|', 'format' => '/category/%s/%s/', 'params' => array ( 0 => 'slug', 1 => 'page', ), ), 'tag_page' => array ( 'url' => '/tag/[slug]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/tag/([^/]+)/([0-9]+)[/]?$|', 'format' => '/tag/%s/%s/', 'params' => array ( 0 => 'slug', 1 => 'page', ), ), 'author_page' => array ( 'url' => '/author/[uid:digital]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/author/([0-9]+)/([0-9]+)[/]?$|', 'format' => '/author/%s/%s/', 'params' => array ( 0 => 'uid', 1 => 'page', ), ), 'search_page' => array ( 'url' => '/search/[keywords]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/search/([^/]+)/([0-9]+)[/]?$|', 'format' => '/search/%s/%s/', 'params' => array ( 0 => 'keywords', 1 => 'page', ), ), 'archive_year' => array ( 'url' => '/[year:digital:4]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([0-9]{4})[/]?$|', 'format' => '/%s/', 'params' => array ( 0 => 'year', ), ), 'archive_month' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([0-9]{4})/([0-9]{2})[/]?$|', 'format' => '/%s/%s/', 'params' => array ( 0 => 'year', 1 => 'month', ), ), 'archive_day' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/[day:digital:2]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([0-9]{4})/([0-9]{2})/([0-9]{2})[/]?$|', 'format' => '/%s/%s/%s/', 'params' => array ( 0 => 'year', 1 => 'month', 2 => 'day', ), ), 'archive_year_page' => array ( 'url' => '/[year:digital:4]/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([0-9]{4})/page/([0-9]+)[/]?$|', 'format' => '/%s/page/%s/', 'params' => array ( 0 => 'year', 1 => 'page', ), ), 'archive_month_page' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([0-9]{4})/([0-9]{2})/page/([0-9]+)[/]?$|', 'format' => '/%s/%s/page/%s/', 'params' => array ( 0 => 'year', 1 => 'month', 2 => 'page', ), ), 'archive_day_page' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/[day:digital:2]/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([0-9]{4})/([0-9]{2})/([0-9]{2})/page/([0-9]+)[/]?$|', 'format' => '/%s/%s/%s/page/%s/', 'params' => array ( 0 => 'year', 1 => 'month', 2 => 'day', 3 => 'page', ), ), 'comment_page' => array ( 'url' => '[permalink:string]/comment-page-[commentPage:digital]', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^(.+)/comment-page-([0-9]+)[/]?$|', 'format' => '%s/comment-page-%s', 'params' => array ( 0 => 'permalink', 1 => 'commentPage', ), ), 'feed' => array ( 'url' => '/feed[feed:string:0]', 'widget' => 'Widget_Archive', 'action' => 'feed', 'regx' => '|^/feed(.*)[/]?$|', 'format' => '/feed%s', 'params' => array ( 0 => 'feed', ), ), 'feedback' => array ( 'url' => '[permalink:string]/[type:alpha]', 'widget' => 'Widget_Feedback', 'action' => 'action', 'regx' => '|^(.+)/([_0-9a-zA-Z-]+)[/]?$|', 'format' => '%s/%s', 'params' => array ( 0 => 'permalink', 1 => 'type', ), ), 'page' => array ( 'url' => '/[slug].html', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^/([^/]+)\\.html[/]?$|', 'format' => '/%s.html', 'params' => array ( 0 => 'slug', ), ), ), 'index' => array ( 'url' => '/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'do' => array ( 'url' => '/action/[action:alpha]', 'widget' => 'Widget_Do', 'action' => 'action', ), 'post' => array ( 'url' => '/archives/[cid:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'attachment' => array ( 'url' => '/attachment/[cid:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'category' => array ( 'url' => '/category/[slug]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'tag' => array ( 'url' => '/tag/[slug]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'author' => array ( 'url' => '/author/[uid:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'search' => array ( 'url' => '/search/[keywords]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'index_page' => array ( 'url' => '/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'category_page' => array ( 'url' => '/category/[slug]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'tag_page' => array ( 'url' => '/tag/[slug]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'author_page' => array ( 'url' => '/author/[uid:digital]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'search_page' => array ( 'url' => '/search/[keywords]/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'archive_year' => array ( 'url' => '/[year:digital:4]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'archive_month' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'archive_day' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/[day:digital:2]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'archive_year_page' => array ( 'url' => '/[year:digital:4]/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'archive_month_page' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'archive_day_page' => array ( 'url' => '/[year:digital:4]/[month:digital:2]/[day:digital:2]/page/[page:digital]/', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'comment_page' => array ( 'url' => '[permalink:string]/comment-page-[commentPage:digital]', 'widget' => 'Widget_Archive', 'action' => 'render', ), 'feed' => array ( 'url' => '/feed[feed:string:0]', 'widget' => 'Widget_Archive', 'action' => 'feed', ), 'feedback' => array ( 'url' => '[permalink:string]/[type:alpha]', 'widget' => 'Widget_Feedback', 'action' => 'action', ), 'page' => array ( 'url' => '/[slug].html', 'widget' => 'Widget_Archive', 'action' => 'render', ),)上面的数组分为两个部分:$routingTable[0] 的作用是路由解析(反解析),以下称“路由解析数组”(一个数组$routingTable[0])$routingTable['string'] 的作用是生成路由解析数组(当$routingTable[0] 不存在时生成routingTable[0]),以下称“路由生成数组”(多个数组$routingTable['string'],string 代表路由名称)例:先看路由表中评论页的路由生成数组:$routingTable = array(
'comment_page' = array ( 'url' => '[permalink:string]/comment-page-[commentPage:digital]', 'widget' => 'Widget_Archive', 'action' => 'render', ));数组中的内容代表什么:$routingTable 中的 KEY 值 comment_page 是路由名称$routingTable['comment_page'] 是一个数组,数组中 'url'、'widget'、 'action' 值的作用只是为了生成路由解析数组(见下面的代码,至于如何解析的,可以看 Typecho\Router\Parser.php 中的代码)再看路由表中评论页的路由解析(反解析)数组(这个是重点,上面的了解就行):
$routingTable = array(
[0] = array( 'comment_page' => array ( 'url' => '[permalink:string]/comment-page-[commentPage:digital]', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^(.+)/comment-page-([0-9]+)[/]?$|', 'format' => '%s/comment-page-%s', 'params' => array ( 0 => 'permalink', 1 => 'commentPage', ), ), ),);数组中的内容代表什么:$routingTable['0'] 中的 KEY 值 comment_page 是路由名称(可以在路由解析完成后用 Typecho_Router::$current 调用)$routingTable['0']['comment_page'] 是一个数组,数组中键 'url' 的值是从路由生成数组过渡过来的,其作用是为了生成路由解析数组中的其他三个值,分别为:一是生成键 'regx'(值的作用是解析 pathInfo 时的正则表达式规则);二是生成键 'format'(值的作用是反解析路由时生成 pathInfo 的格式);三是生成键 'params'(值的作用是pathInfo被路由解析后传递给widget的参数),键 'params' 的值是一个数组,数组内容与 'regx' 正则表达式中的子模式顺序值相对应;键 'widget' 的值是路由解析后分发执行的组件(传递给“组件工厂”);键 'action' 的值是组件实例化后执行的方法。组件工厂执行流程:组件实例化(生成组件对象) —— 执行构造函数(将上述 'params' 传递给对象) —— 执行execute方法 —— 执行action方法
完整的例子(扩展讲解):浏览器中文章评论页的URL:
http://www.bufannao.com/archives/__slide__top__gridLayout.html/comment-page-1
得到文章评论页的 pathInfo 为:/archives/__slide__top__gridLayout.html/comment-page-1
搜索路由表得到文章评论页的路由为:$routingTable = array(
[0] = array( 'comment_page' => array ( 'url' => '[permalink:string]/comment-page-[commentPage:digital]', 'widget' => 'Widget_Archive', 'action' => 'render', 'regx' => '|^(.+)/comment-page-([0-9]+)[/]?$|', 'format' => '%s/comment-page-%s', 'params' => array ( 0 => 'permalink', 1 => 'commentPage', ), ), ),);执行顺序:Typecho_Widget::widget('Widget_Archive', NULL, array('permalink' => '/archives/__slide__top__gridLayout.html', 'commentPage' => 1));
// $responseObject = Typecho_Response::getInstance();// $requestObject = new Typecho_Request();// $requestObject->setParams(array('permalink' => '/archives/__slide__top__gridLayout.html', 'commentPage' => 1));// 此时$requestObject附加两个属性// $requestObject->permalink = '/archives/__slide__top__gridLayout.html';// $requestObject->commentPage = 1;// $widget = new Widget_Archive($requestObject, $responseObject , null);// $widget->__construct();// $widget->execute();// $widget->render();内容比较多,写得也比较乱,如果上述内容有误欢迎指正。