打开文件 configs/routes.yaml 文件,可以看到目前的默认路由规则:
_default_:
pattern: /:controller/:action/*
defaults:
controller: default
action: index
上面的规则中,“_default_”是规则的名称,每一条规则必须有一个唯一的名称。
pattern 表示该规则是一个基于模式的规则,如果是 regx 则是基于正则的规则。同一条规则只能两者之中选一种,不同规则可以不同的类型。defaults 则指定各个变量的默认值。
基于正则的路由适合非常复杂的情况。限于篇幅这里我们只大概说明一下基于模式的路由规则。
pattern 的值就是要解析或最终生成的 URL 地址样式。这个 URL 用“/”符号分割为多个部分。而每一个以“:”开头的部分都是一个变量。例如“/:controller/:action/*”这个模式就由三个部分,其中前两个部分都是变量,而最后的则是通配符(关于通配符稍后再详细说明)。
现在来看看这个模式怎么用于正向解析。
解析时,首先用“/”将 URL 地址分割为多个部分,然后与分割后的模式依次比对。
这个 URL 分割后有 4 个部分,按照前面的过程,前两个部分都会比对成功。而通配符则比对成功最后的“id”和“2”两个部分,最终将 URL 导向 docs 控制器的 show 动作,并且附带参数 id=2。
再看一个复杂一点的例子:
projects_download: pattern: "/projects/:name/download/:file" defaults: controller: "projects" action: "download" config: name: "[a-z0-9]+" file: "[0-9]+"
这个 URL 一共四个部分,依次比对的结果是:
在比对过程中,必须所有部分都比对成功才算通过,否则一律算作比对失败。一条规则比对失败,就会用下一条规则来比对,直到找到可以匹配的规则。如果所有规则都失败,那么会按照 /key/value 形式把 URL 转换为参数对。
所以匹配范围更低的规则应该放在更前面。这样才能确保不会因为一个规则比另一个规则具有更大的匹配范围,而把匹配范围更小那个规则忽略了。
与正向解析相比,反向解析复杂得多。因为反向解析是用参数来比对的,而不是 URL 地址。
array( 'controller' => 'projects', 'action' => 'download', 'name' => 'qeephp', 'file' => 2, )
上面是生成 URL 的参数,用于匹配的规则有:
docs_page: pattern: "/docs/:name/:file" defaults: controller: "docs" action: "page" file: "index" config: name: "[a-z0-9\-]+" file: "[a-z0-9\-]+" projects_show: pattern: "/projects/:name" defaults: controller: "projects" action: "show" config: name: "[a-z0-9]+" projects_download_all: pattern: "/projects/:name/download" defaults: controller: "projects" action: "download" config: name: "[a-z0-9]+" projects_download: pattern: "/projects/:name/download/:file" defaults: controller: "projects" action: "download" config: name: "[a-z0-9]+" file: "[0-9]+"
首先看第一个规则 docs_page 的比对过程:
首先确定 docs_page 规则需要的变量,包括 :controller、:action、:file 和 :name。其中前三个变量都具有默认值。
比对第一个变量 :controller。这个变量在 docs_page 中指定为 docs。而提供的参数中 :controller 的值是 projects。此时就要检查 :controller 是否在 configs 中指定了比对规则。如果指定了比对规则,那么 defaults 中为 :controller 指定的就是一个“建议值”。只要 :controller 符合比对规则也算通过。但现在 configs 并没有指定 :controller 的规则,因此比对失败。
参考 docs_page 的比对过程,:controller 变量可以通过,但 :action 变量却比对失败。
:controller、:action 变量都通过了比对。在比对 :name 时,按照 configs 中为 :name 指定的规则,:name 也通过了比对。接下来该路由规则已经没有更多变量了,但参数中却还有一个 file,因此算作比对失败。
这个规则的四个变量和参数完全符合,因此比对通过。比对通过后,将生成 /projects/qeephp/download/2 这样的 URL。而这个 URL 在正向解析时又符合同一条规则,最终实现了 url() 方法生成 URL 地址导向到正确控制器和动作的目的。
在实际应用中,大多数 URL 使用默认的路由规则就足够了。少数 URL 可以进行适当的美化。例如 /tasks/edit/task_id/1 应该美化为 /tasks/edit/1。为了实现这个目的,我们修改 configs/routes.yaml,在默认规则前添加一条规则:
tasks_edit:
pattern: /tasks/edit/:task_id
defaults:
controller: tasks
action: edit
configs:
task_id: "[0-9]+"
刷新浏览器后,再点击任务标题可以看到 URL 地址已经改变为预期的形式:
改变后的 URL 地址
继续增加规则:
tasks_pagination:
pattern: /tasks/page/:page
defaults:
controller: tasks
action: index
configs:
page: "[0-9]+"
将把 /tasks/index/page/3 改写为 /tasks/page/3。
读者朋友们可以尝试各种写法,找到适合自己的使用方式。更复杂的基于正则的路由,请参考开发指南。