跳至主要内容
版本:5.1

解析 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