5

I have a custom router that I'd like to be used for matching before the Standard router. I'm having issues trying to figure out how to change the order in which the routers are added and used for matching requests subsequently.

It looks like the Admin and Standard routers are defined in Mage_Core's config.xml and loaded in Mage_Core_Controller_Varien_Front::init with following line.

$routersInfo = Mage::app()->getStore()->getConfig(self::XML_STORE_ROUTERS_PATH);

However, I've tried to add my custom router's definition in Mage_Core's config.xml before any of the default routers to test, but it still gets added at the end. I've tried changing the order in which Admin and Standard routers are defined in config.xml, and that doesn't take effect. I clear cache, and I'm not sure why.

I wan to do this without rewriting Mage_Core_Controller_Varien_Router_Standard (app/code/local/Mage/Core/...), if possible. Any ideas?

3
  • did you try to make the Mage_Core module depend on your module?
    – Marius
    Commented Jul 27, 2015 at 15:34
  • Yeah, I did. The problem was that I made a mistake of modifying the config/default/web/routers in config.xml, instead of the config/stores/default/web/routers node that Mage_Core_Controller_Varien_Front uses to add the routers. It seems like I can load mine first now. I didn't realize there was a config/*stores*/... node.
    – laketuna
    Commented Jul 27, 2015 at 16:35
  • @Marius, router load order can be changed when modifying Mage/Core/etc/config.xml, but it doesn't seem possible from a local extension. The only way for me is to comment out config/stores/... note entirely in Mage/Core/etc/config.xml and redefine it in the order I want in my extension. Any idea how to do this without modifying core? For now, I just overrode the entire Standard router to skip matching for a certain request.
    – laketuna
    Commented Jul 30, 2015 at 0:47

2 Answers 2

3

If you want to load your custom router prior to all other routers in Magento, then try this one.

Define your custom router in config.xml

File : app\code\{codePool}\{Namespace}\{Module}\etc\config.xml

<config>
    <default>
        <web>
            <routers>
                <{router_identifier}>
                    <area>{admin|frontend}</area>
                    <class>Namespace_Module_Controller_Router</class>
                </{router_identifier}>
            </routers>
        </web>
    </default>
    <stores>
        <default>
            <web>
                <routers>
                    <{router_identifier}>
                        <area>{admin|frontend}</area>
                        <class>Namespace_Module_Controller_Router</class>
                    </{router_identifier}>
                </routers>
            </web>
        </default>
    </stores>
</config>

Now make core module depend on your module

File : app\etc\modules\Namespace_Module.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Namespace_Module>
            <active>true</active>
            <codePool>{local|community}</codePool>
        </Namespace_Module>
        <Mage_Core>
            <depends>
                <Namespace_Module />
            </depends>
        </Mage_Core>
    </modules>
</config>

Now clear your cache. You are done.

Why does This work

Router loading is happening inside front-controller1. The abbreviated form of router loading code is shown below.

public function init()
{

    //prioriy 1 : routers adding via xml configuration
    $routersInfo = Mage::app()->getStore()->getConfig(self::XML_STORE_ROUTERS_PATH);
    foreach ($routersInfo as $routerCode => $routerInfo) {
        if (isset($routerInfo['disabled']) && $routerInfo['disabled']) {
            continue;
        }
        if (isset($routerInfo['class'])) {
            $router = new $routerInfo['class'];
            if (isset($routerInfo['area'])) {
                $router->collectRoutes($routerInfo['area'], $routerCode);
            }
            $this->addRouter($routerCode, $router);
        }
    }

    //priority 2: routers adding via observer
    Mage::dispatchEvent('controller_front_init_routers', array('front'=>$this));

    // pririry 3 : for default router.
    $default = new Mage_Core_Controller_Varien_Router_Default();
    $this->addRouter('default', $default);

    return $this;
}

This method simply grabs routers from various resources and add it to the protected property $_routers as an array2. As you can see, the priorities are like this:

  1. Routers which are defined via XML files will be added to $_routers first

  2. Routers which are added via the event controller_front_init_routers go next

  3. At last, the Default router will be added to the array

Now, the standard router and admin router are defined in app/code/core/Mage/Core/etc/config.xml and hence they will be loaded first in the $_routers array and thus they will be processed first.

In order to change this intentional priority for the standard and admin router, you need to define your router via your module's config.xml file. This will bring your router to the priority level 1. Making core module depend on your module gives more priority to your module and hence Magento will consider your module first and hence load your router in $_routers array first.

Hope that makes sense.


1: Mage_Core_Controller_Varien_Front::init()

2: $this->addRouter() is actually what populates $_routers.

7
  • I'm very curious how such a thing would be possible if you wouldn't edit core files. A solution that involves editing core files while it would not be necessary, is not a good solution in my opinion.
    – 7ochem
    Commented Sep 21, 2015 at 8:15
  • @7ochem the solution that i provided should work in theory. See the "Why does this work" section. I explained with code why it works there. In my analysis, my method should work without touching any core files in theory. I didnt try this before. I will try my method once I get some free time and update this answer accordingly Commented Sep 21, 2015 at 9:23
  • Sorry I've misread your code example. You're adding the dependency inside the custom module's config.xml. Well, then I understand your doubt whether this will work. If I look at the dependency code, then I think this should work, setting a dependency of a core module in a custom module's config.xml
    – 7ochem
    Commented Sep 21, 2015 at 9:50
  • @7ochem I smelled that mis-read :) Commented Sep 21, 2015 at 9:52
  • Hm I just saw this. I'll try this out when I get the chance in a week or two and report back.
    – laketuna
    Commented Sep 21, 2015 at 16:30
0

Another way to change router load order is through controller_front_init_before event because is invoked right before any router gets added.

so in app\code\{codePool}\{Namespace}\{Module}\etc\config.xml add a listener for that event:

<controller_front_init_before>
  <observers>
    <Namespace_Module>
      <class>Namespace_Module_Controller_Router</class>
      <method>initControllerRouters</method>
    </Namespace_Module>
  </observers>
</controller_front_init_before>

(I've used the same Router Class so $this object represents the router)

Then in app/code/local/Namespace/Module/Controller/Router.php

public function initControllerRouters(Varien_Event_Observer $observer)
{
  $front = $observer->getEvent()->getFront();
  $front->addRouter('Namespace_Module', $this);
}

(change $this object for your router in case your event class is in Model/Observer or somewhere else than the router class itself)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.