以下解释假设您已经按照通常的方式定义了您的名称:
<config>
<modules>
<Mycompany_Landing>
<version>0.1.0</version>
</Mycompany_Landing>
</modules>
<frontend>
<routers>
<landing>
<use>standard</use>
<args>
<module>Mycompany_Landing</module>
<frontName>landing</frontName>
</args>
</landing>
</routers>
</frontend>
</config>
在这种情况下,Magento 标准路由器会将 URL landing/cool 映射到
Mycompany_Landing_CoolController::indexAction()
这是因为 Magento 标准路由器使用 frontname/controller/action 模式处理 URL,在您的情况下它知道
- frontname为
landing,映射到Mycompany_Landing模块
- 控制器名称为
cool,将转换为CoolController
- 缺少动作名称,导致默认使用
indexAction
但您希望cool 成为参数,而不是控制器。
我猜这背后的原因是,除了landing/cool,你还想拥有多个登陆区域,比如landing/awesome、landing/insane等等。这意味着您必须设置多个控制器,每个控制器用于不同的着陆区。
在这种情况下避免多个控制器的一种可能解决方案是实现您的自己的路由器。
实现你自己的路由器
要实现自己的路由器,您需要挂钩controller_front_init_routers 事件,例如通过像这样扩展您的app/code/local/Mycompany/Landing/etc/config.xml:
<config>
<global>
<events>
<controller_front_init_routers>
<observers>
<landing>
<class>Mycompany_Landing_Controller_Router</class>
<method>controllerFrontInitRouters</method>
</landing>
</observers>
</controller_front_init_routers>
</events>
</global>
</config>
接下来创建一个合适的app/code/local/Mycompany/Landing/Controller/Router.php 文件:
class Mycompany_Landing_Controller_Router extends Mage_Core_Controller_Varien_Router_Abstract
{
/**
* Add own router to Magento router chain
*
* @param Varien_Event_Observer $oObserver
*/
public function controllerFrontInitRouters($oObserver)
{
// Add this router to the current router chain
$oObserver
->getEvent()
->getFront()
->addRouter('landing', $this);
}
/**
* Match routes for the landing module
*
* @param Zend_Controller_Request_Http $oRequest
* @return bool
*/
public function match(Zend_Controller_Request_Http $oRequest)
{
$sPathInfo = trim($oRequest->getPathInfo(), '/');
$aPathInfo = explode('/', $sPathInfo);
// Cancel if the route request is for some other module
if ($aPathInfo[0] != 'landing') {
return false;
}
// Cancel if it's not a valid landing zone
if (!in_array($aPathInfo[1], array('cool'))) {
return false;
}
// Rewrite the request object
$oRequest
->setModuleName('landing')
->setControllerName('index')
->setActionName('index')
->setParam('zone', $aPathInfo[1])
->setAlias(
'landing_router_rewrite',
true
);
// Tell Magento that this router can match the request
return true;
}
}
上面文件的controllerFrontInitRouters() 方法负责将您自己的路由器合并到Magento 路由器链中,使其看起来像这样:
Mage_Core_Controller_Varien_Router_Admin
Mage_Core_Controller_Varien_Router_Standard
Mage_Cms_Controller_Router
Mycompany_Landing_Controller_Router
Mage_Core_Controller_Varien_Router_Default
Magento 在调度时会按照给定的顺序循环这个链。这意味着,像您这样的自定义路由器总是最早在第 4 位被调用。只有在前三个路由器都不能匹配路由请求的情况下,才会调用您的路由器。
当调用文件的match()方法并检测到有效路由时(目前只有landing/cool),它会改变请求对象,这样Mycompany_Landing_IndexController::indexAction()就会被调度,有一个参数zone和值cool。
请注意,这个match() 过于简单化了。它不包含消毒等。不要忘记修复这个^^
最后创建一个app/code/local/Mycompany/Landing/controllers/IndexController.php文件:
class Mycompany_Landing_IndexController extends Mage_Core_Controller_Front_Action
{
public function indexAction()
{
if (!$this->getRequest()->getAlias('landing_router_rewrite')) {
$this->_forward('noRoute');
return;
}
$sZone = $this->getRequest()->getParam('zone');
die(__METHOD__ . ' called with zone = ' . $sZone);
}
}
如果请求对象中没有设置 landing_route_rewrite 别名,indexAction 的第一个 if 块将取消操作(请参阅路由器的 match() 方法中的 setAlias())。
这样做是因为用户也可以通过使用其他 URL(如 landing、landing/index、landig/index/index、landing/index/index/zone/cool 等)访问此 indexAction()。
我猜你不想让其他 URL 被 SEO 排名,也不想执行两次验证和清理,但如果你不需要它,只需删除 if 块。
现在您可以扩展 indexAction() 以对您的着陆区做任何您喜欢做的事情。