Magento的路由系统,需要考虑到两个抽象层。
1,首先你需要了解,可能会有无数多个路由对象负责处理路由逻辑,最后只有一个路由对象能够获取并处理该请求。默认情况下,Magento拥有四个路由对象。
2,在这四种路由对象内,又有一系列不同的规则用于匹配url地址到相应的控制器方法。这些规则非常相似,只有一些细微的差别。
路由匹配迭代过程
Magneto的路由开始于前端控制器对象的Mage_Core_Controller_Varien_Front::dispatch()方法,在如下循环中,选择合适的路由对象,
01
02
03
04
05
06
07
|
while (! $request ->isDispatched() && $i ++<100) {
foreach ( $this ->_routers as $router ) {
if ( $router ->match( $this ->getRequest())) {
break ;
}
}
}
|
Mage_Core_Controller_Varien_Front::$_routers是前端控制器类的一个属性,用于存放系统中可用的路由规则。该属性被定义为一个数组,默认为空,数组键为路由对象表示,如admin,standard,cms,default,对应的数组值分别为实例化的路由对象。那么它是如何被系统赋值的呢?在系统APP模型中实例化前端控制器类的时候,调用了该类的init()方法,该方法按照一定的方式,实例化系统中可用的路由对象,并通过addRouter()方法,将获取到的路由对象赋值给$_routers数组,另外,在addRouter()中,每个路由对象都通过setFront()方法,获得了前端控制器的引用。
01
02
03
04
05
06
|
public function addRouter( $name , Mage_Core_Controller_Varien_Router_Abstract $router )
{
$router ->setFront( $this );
$this ->_routers[ $name ] = $router ;
return $this ;
}
|
回过头来在看init()方法,下面是该方法的完整代码,
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
public function init()
{
Mage::dispatchEvent( 'controller_front_init_before' , array ( 'front' => $this ));
$routersInfo = Mage::app()->getStore()->getConfig(self::XML_STORE_ROUTERS_PATH);
/* $routersInfo需要的config.xml文件节点如下
<web>
<!-- ... -->
<routers>
<admin>
<area>admin</area>
<class>Mage_Core_Controller_Varien_Router_Admin</class>
</admin>
<standard>
<area>frontend</area>
<class>Mage_Core_Controller_Varien_Router_Standard</class>
</standard>
</routers>
<!-- ... -->
</web>
*/
Varien_Profiler::start( 'mage::app::init_front_controller::collect_routers' );
foreach ( $routersInfo as $routerCode => $routerInfo ) {
if (isset( $routerInfo [ 'disabled' ]) && $routerInfo [ 'disabled' ]) {
continue ;
}
if (isset( $routerInfo [ 'class' ])) {
$router = new $routerInfo [ 'class' ];
if (isset( $routerInfo [ 'area' ])) {
$router ->collectRouters( $routerInfo [ 'area' ], $routerCode );
}
$this ->addRouter( $routerCode , $router );
}
}
Varien_Profiler::stop( 'mage::app::init_front_controller::collect_routers' );
//这里实际上分发事件,为了添加CMS路由对象
Mage::dispatchEvent( 'controller_front_init_routers' , array ( 'front' => $this ));
// 最后添加默认路由
$default = new Mage_Core_Controller_Varien_Router_Default();
$this ->addRouter( 'default' , $default );
return $this ;
}
|
如上所述,该方法只用于收集可用路由,并使用addRouter()方法添加路由对象到属性Mage_Core_Controller_Varien_Front::$_routers中。稍微深入点的话,可以看到,在foreach循环中,每次实例化路由时,都会调用路由对象的collectRouters()方法。该方法可以在standard路由对象中一探究竟。