以下解释假设您已经以通常的方式定义了您的frontname:
<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
, likelanding/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);
}
}
如果请求对象中没有设置别名,则第一个if
块取消操作(请参阅路由器的方法)。indexAction
landing_route_rewrite
setAlias()
match()
这样做是因为用户也可以indexAction()
通过使用其他 URL(如landing
、landing/index
、landig/index/index
、等)来达到此目的landing/index/index/zone/cool
。
我猜您不希望对此类其他 URL 进行 SEO 排名,也不希望实施两次验证和清理,但如果您不需要它,只需删除该if
块。
现在您可以扩展indexAction()
以对您的着陆区做任何您喜欢做的事情。