解析 SEF URL
使用以下 SEF URL,让我们考虑一下解析函数涉及的内容
http://localhost/joom/index.php/en/mountain/21-mont-blanc
解析完成后,我们希望得到一个查询参数数组(选项、视图、布局、语言等),这使 Joomla 能够知道要调用哪个组件(选项参数),其他参数则为组件提供构建 HTML(或 json 或 xml 等)输出所需的详细信息。
http://localhost/joom
- 这是 Joomla 实例的基地址。由于它对于站点上的所有 URL 都是通用的,并且与路由无关,因此将其移除。
index.php
- 这是入口点(可能缺失,具体取决于站点的配置方式)。它也因与路由无关而被移除。
我们剩下的部分是 3 个片段
/en/mountain/21-mont-blanc
Joomla 在内部使用 2 个数组来保存片段和查询参数(也称为查询变量)。在此阶段,我们拥有
$segments = array('en', 'mountain', '21-mont-blanc')
$queryVars = array()
接下来,语言过滤器插件开始参与。当此插件实例化时,它会将“规则”注入站点路由器,该规则基本上告诉路由器“当您开始处理片段时,请调用我的 parseRule()
函数”。调用 parseRule()
时,它会识别 'en' 为有效的语言代码(在我的站点上等同于 'en-GB'),将其从 $segments
中移除,并将语言添加到查询参数中。现在,在此阶段之后,我们拥有
$segments = array('mountain', '21-mont-blanc')
$queryVars = array('lang' => 'en-GB')
接下来,路由器尝试将 $segments
数组的第一个元素(即 'mountain')与站点菜单之一中顶级菜单项的别名字段匹配。
如果找不到,则会引发异常并返回 HTTP 状态 404(页面未找到)。
如果找到,则检查此菜单项下方是否有子菜单,并尝试将下一个片段 ('21-mont-blanc') 与子菜单项的别名字段匹配。它会继续执行此操作,向下遍历任何子菜单链并尝试匹配连续的片段,以找到最低可能的菜单项。
让我们假设它匹配了别名为 'mountain' 的菜单项,但其下方没有子菜单项。还假设此菜单项的 ID 为 6。由于 'mountain' 片段现已匹配,因此将其从 $segments
中移除,并将菜单项的 ID 包含在查询变量中
$segments = array('21-mont-blanc')
$queryVars = array('lang' => 'en-GB', 'Itemid' => '6')
此外,如果您查看管理后端中菜单项关联的链接字段,则会发现通常与菜单项关联的其他变量。例如,您可能拥有
Link: index.php?option=com_content&view=article&id=10
因此,现在有其他变量需要包含在查询变量中
$segments = array('21-mont-blanc')
$queryVars = array('lang' => 'en-GB', 'Itemid' => '6', 'option' => 'com_content', 'view' => 'article', 'id' => '10')
顺便说一句,菜单项的识别出于多种原因非常重要。它不仅标识要使用的组件(例如 option=com_content
),而且还定义网页的大部分格式,包括将出现在该页面上的模块以及将应用于该页面的模板(即,除非 URL 中包含“?template=anothertemplate”参数)。
找到此菜单项后,路由器使用 Menu setActive()
函数将其设置为“活动”菜单项。这意味着其他代码可以使用 getActive()
轻松获取此菜单项(如 菜单和菜单项 中所述)。
在此阶段,站点路由器已走到尽头。它现在开始将剩余的片段交给组件路由器进行解析。当您编写使用 SEF URL 的组件时,几乎总是必须提供组件路由器,这包括提供 parse()
函数
public function parse(&$segments)
路由器通过引用传递片段,并期望组件路由器的 parse
函数处理传递的片段以识别查询变量,然后
- 取消设置已使用的片段(如果在此阶段之后仍有剩余片段,则路由器将导致生成 HTTP 404 页面未找到异常),以及
- 返回识别出的查询变量数组。
例如,如果我们的站点显示山脉,并且 Itemid=6 的菜单项链接到关于珠穆朗玛峰的文章(文章 ID 为 10),但我们的勃朗峰文章 ID 为 21,则将使用以下内容调用解析函数
$segments = array('21-mont-blanc')
代码应包含类似以下内容
unset($segments[0]);
$vars = array('view' => 'article', 'id' => '21-mont-blanc');
return $vars;
返回 '21-mont-blanc' 的 ID 没有问题,因为变量将通过 int
过滤器传递,该过滤器会忽略 21 之后的所有内容。此外,最好专门返回 'view'(以及其他变量,如 'layout'),而不是依赖路由器从菜单项合并这些值。
在此阶段,我们的 URL 解析完成,我们最终得到了
$segments = array()
$queryVars = array('lang' => 'en-GB', 'Itemid' => '6', 'option' => 'com_content', 'view' => 'article', 'id' => '21')
Joomla 现在拥有服务请求所需的所有内容
- 要使用的语言 INI 文件将是
en-GB
的文件 - 从菜单项
Itemid
中,它了解页面格式的详细信息,包括要使用的模板以及要包含的模块 - 要使用的组件是
com_content
,它知道要使用的view
以及要显示的文章的id
。