3

我在为我的 Magento 商店创建自定义模块时遇到问题。

我已经成功添加了一条路线(/着陆),并创建了/布局文件,这些文件在我的基本布局中显示了模板内容。我现在需要超越这一点。

我希望能够从 URL 加载参数,根据该参数获取对象,并根据对象的内容显示内容。

示例:用户浏览器访问 domain.com/landing/cool/。这(希望)会调用着陆控制器。控制器将能够以某种方式拉取“cool”参数,并拉取与cool关联的着陆对象。然后,我的模板可以获取该对象并显示其元素。

我知道那里有很多东西,但我一直在努力解决这个问题,但一无所获。Magento 必须对其所有类别、项目等执行此操作。有没有人知道我该怎么做?

4

4 回答 4

2

如果你做domain.com/landing/[controller]/cool/[key]/[value],你可以做$this->getRequest()->getParam('[key]')来获取[value]的值]。然后您可以基于此设置模板,但我认为这是一个不同的问题。如果您仍然感到困惑,请告诉我。

于 2012-08-01T19:53:32.450 回答
2

以下解释假设您已经以通常的方式定义了您的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块取消操作(请参阅路由器的方法)。indexActionlanding_route_rewritesetAlias()match()

这样做是因为用户也可以indexAction()通过使用其他 URL(如landinglanding/indexlandig/index/index、等)来达到此目的landing/index/index/zone/cool

我猜您不希望对此类其他 URL 进行 SEO 排名,也不希望实施两次验证和清理,但如果您不需要它,只需删除该if块。

现在您可以扩展indexAction()以对您的着陆区做任何您喜欢做的事情。

于 2012-08-12T15:19:36.737 回答
1

我稍后会在这里进一步研究它,但现在唯一想到的是在“/”上爆炸以抓住它们。

于 2012-08-01T19:57:45.537 回答
0

以下是我通过 Javascript 为我的一个项目执行此操作的方法:

function populateSelect(url, element, target) {
    var selectedValue = document.getElementById(element);
    var elementValue = selectedValue.options[selectedValue.selectedIndex].value;

    pathArray = url.split( '/' );
    pathArray.shift();
    pathArray.shift();
    pathArray.splice(5,0, element);
    pathArray.splice(6,0, elementValue);
    url = pathArray.join("/");
    url = 'http://' + url;

    new Ajax.Request(url, {
        method:    "POST",
        onSuccess:
            function(transport) {
                var json    = transport.responseText.evalJSON(true);
                var options = '';
                $(target).descendants().each(Element.remove);

                 for (var i = 0; i < json.length; i++) {
                    var opt = document.createElement('option');
                    opt.text = json[i].optionName;
                    opt.value = json[i].optionValue;
                    $(target).options.add(opt);
                }
            }
    });
}
于 2012-08-01T20:02:01.577 回答