在Magento中根据URL参数加载对象

时间:2012-08-01 19:40:10

标签: magento parameter-passing magento-1.5

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

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

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

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

我知道那里有很多东西,但是我已经开了一段时间并且无处可去。 Magento必须为其所有类别,项目等执行此操作。有没有人知道我该怎么做?

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

以下解释假设您已按照常规方式定义了您的前缀:

<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,在您的情况下,它知道

  • 前缀为landing,映射到Mycompany_Landing模块
  • 控制器名称为cool,将转换为CoolController
  • 缺少操作名称,默认情况下会导致使用indexAction

但您希望cool成为参数,而不是控制器。

我猜这背后的原因是你希望除了landing/cool之外还有多个着陆区,例如landing/awesomelanding/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()landinglanding/indexlandig/index/index等其他网址来覆盖此landing/index/index/zone/cool。上。

我想您不希望其他网址被SEO排名,也不希望两次实施验证和清理,但如果您不需要,只需删除if阻止。

现在,您可以扩展indexAction()以执行您对着陆区所做的任何操作。

答案 2 :(得分:1)

我稍后会在这里稍微调查一下,但是现在我想到的唯一一件就是'/'来抓住它们。

答案 3 :(得分: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);
                }
            }
    });
}