Loading objects based on URL parameters in Magento

こ雲淡風輕ζ 提交于 2019-12-10 18:02:54

问题


I am having trouble creating a custom module for my Magento store.

I have successfully added a route (/landing), and created/layout files that display template content within my base layout. I now need to move beyond that a bit.

I want to be able to load a parameter from a URL, grab an object based on that parameter, and display things based on the contents of my object.

Example: User browsers to domain.com/landing/cool/. This (hopefully) would call the landing controller. Controller would somehow be able to pull the 'cool' parameter, and pull a landing object associated with cool. Then, my template can get that object and display its elements.

I know there are a lot of bits there, but I have been cracking my head on this for a while and getting nowhere. Magento has to do this for all its categories, items, etc. Does anyone out there know how I can do it?


回答1:


If you do domain.com/landing/[controller]/cool/[key]/[value], you can do $this->getRequest()->getParam('[key]') to get the value of [value]. You can then set the template based on that, but I think that's a different question. Let me know if you're still confused.




回答2:


The following explanations assume that you've defined your frontname the usual way:

<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>

In this scenario the Magento Standard Router would map the URL landing/cool to

Mycompany_Landing_CoolController::indexAction()

This is because the Magento Standard Router handles URLs using a frontname/controller/action pattern and in your case it knows that

  • the frontname is landing, which is mapped to the Mycompany_Landing module
  • the controller name is cool, which will be transformed to CoolController
  • the action name is missing, which will result in using indexAction by default

But you want cool to be a parameter, not a controller.

I guess the reasoning behind this is that you want to have multiple landing zones besides landing/cool, like landing/awesome, landing/insane and so on. And this would mean you'd have to setup multiple controllers, one for each different landing zone.

A possible solution to avoid multiple controllers in this case would be to implement your own router.

Implementing your own router

To implement your own router, you need to hook into the controller_front_init_routers event, e.g. by extending your app/code/local/Mycompany/Landing/etc/config.xml like this:

<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>

Next create a proper app/code/local/Mycompany/Landing/Controller/Router.php file:

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;

    }

}

The controllerFrontInitRouters() method of the file above takes care that your own router will be merged into the Magento router chain so that it looks like this:

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 will loop this chain in the given order when dispatching. That means, a custom router like yours will always be called at 4th position at the earliest. Your router will only be called, if none of the previous three routers could already match the route request.

When the match() method of the file is called and detects a valid route (currently landing/cool only), it will change the request object, so that Mycompany_Landing_IndexController::indexAction() will be dispatched, having a parameter zone with the value cool.

Note that this match() is oversimplified. It doesn't contain sanitizing, etc. Don't forget to fix this^^

Finally create a app/code/local/Mycompany/Landing/controllers/IndexController.php file:

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);

    }

}

The first if block of the indexAction cancels the action, if there's no landing_route_rewrite alias set in the request object (see setAlias() in your router's match() method).

This is done because a user otherwise could also reach this indexAction() by using other URLs like landing, landing/index, landig/index/index, landing/index/index/zone/cool, and so on.

I guess you don't want to have such other URLs been SEO ranked, nor to implement validation and sanitizing twice, but if you don't need it, just remove that if block.

Now you can extend the indexAction() to do whatever you like to do with your landing zones.




回答3:


I'm looking into it a bit more here in a moment, but right now the only thing that's coming to mind is exploding on '/' to grab them.




回答4:


Here's how I did it through Javascript for one of my projects:

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);
                }
            }
    });
}


来源:https://stackoverflow.com/questions/11766355/loading-objects-based-on-url-parameters-in-magento

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!