Create a custom router in Magento using Event/Observer

Posted on

Have you ever wanted to create a seo-friendly url management feature for a custom module like News module or blog Module in Magento.
Here we are going to create a custom router as done by the CMS module to route a url to a specific page created in admin.

A little background into Magento Routers.
Magento by default has 4 routers which are Admin, Standard, Cms and Default respectively.
In short, during a page load, Magento loads the Mage_Core_Controller_Varien_Action class. This class is responsible for finding the routers that matches with the current request url and identify the controller and action to be called.

While loading the routers, “controller_front_init_routers” event is fired.

We can use this event to add our custom router feature into Magento.

So, Here we go.

Step 1.
Setup an observer in config.xml file of your module that listens to the “controller_front_init_routers” event.
<config>
<global>
<events>
<controller_front_init_routers>
<observers>
<magentotraining_router>
<class>Companyname_ModuleName_Controller_Router</class>
<method>initControllerRouters</method>
</magentotraining_router>
</observers>
</controller_front_init_routers>
</events>
</global>
</config>

Step 2.
Create a event listener class that actually does the job of adding a new router and also matches the url request to the required content in our module. For ease of coding, we will be using the cms class “Mage_Cms_Controller_Router” as the Magento’s core CMS module uses the same appraoch. We will make the changes as required.
So create a new file Router.php at app/code/codePool/CompanyName/ModuleName/Controller/ which is an exact copy of “app/code/core/Mage/Cms/Controller/Router.php”
and put the following code.

Read the comment in the code to make the necessary changes.

class CompanyName_ModuleName_Controller_Router extends Mage_Core_Controller_Varien_Router_Abstract
{
/**
* Initialize Controller Router
*
* @param Varien_Event_Observer $observer
*/
public function initControllerRouters($observer)
{
/* @var $front Mage_Core_Controller_Varien_Front */
$front = $observer->getEvent()->getFront();

$front->addRouter(‘router_name’, $this);//replace router_name with a suitable name
}

/**
* Validate and Match router with the Page and modify request
*
* @param Zend_Controller_Request_Http $request
* @return bool
*/
public function match(Zend_Controller_Request_Http $request)
{
if (!Mage::isInstalled()) {
Mage::app()->getFrontController()->getResponse()
->setRedirect(Mage::getUrl(‘install’))
->sendResponse();
exit;
}

$identifier = trim($request->getPathInfo(), ‘/’);

$condition = new Varien_Object(array(
‘identifier’ => $identifier,
‘continue’ => true
));
Mage::dispatchEvent(‘magentotraining_controller_router_match_before’, array(
‘router’ => $this,
‘condition’ => $condition
));

$identifier = $condition->getIdentifier();

if ($condition->getRedirectUrl()) {
Mage::app()->getFrontController()->getResponse()
->setRedirect($condition->getRedirectUrl())
->sendResponse();
$request->setDispatched(true);
return true;
}

if (!$condition->getContinue()) {
return false;
}

/** this is the actual implementation in CMS module to find the page ID from the request url, we can write something similar to **get the id of our item from the requested URL.
* for eg. we could have url = ‘about-us’ for id 1.
* So if the current url is http://site_url/about-us
* we will get 1 as pageId by quering through our module.
*/

// $page = Mage::getModel(‘cms/page’);
// $pageId = $page->checkIdentifier($identifier, Mage::app()->getStore()->getId());
// if (!$pageId) {
// return false;
// }

$pageId = 1; //1 is retrieved by quering our custom module table.
$request->setModuleName(‘modulename’)// replace modulename with the frontname of the router of your controller
->setControllerName(‘index’)// replace index with your controller name
->setActionName(‘index’) // replace index with your action name
->setParam(‘page_id’, $pageId); //$pageid is the id param that is passed into the action to retrieve the desired item

$request->setAlias(
Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS,
$identifier
);

return true;
}
}

And we’re done.

Now when Magento processes the current request it also passes through our module to check if it finds a match and set the controller and action of our module for processing the request.
So, now we have a clean and elegant url for our item pages.
http://magento.com/test-content.html
instead of
http://magento.com/testmodule/testcontroller/testaction/view/1
Looks good 😀

For more detail and intensive study on Magento routers and front Action Processing, you can have a look at the following posts:
http://blog.belvg.com/magento-certified-developer-exam-request-routing.html
http://blog.belvg.com/magento-front-controller-pattern.html

Thank you for reading.
Hope this was helpful to you.
Cheers!!

Advertisements

7 thoughts on “Create a custom router in Magento using Event/Observer

    Ravi said:
    September 1, 2016 at 8:22 AM

    I am generating dynamic url’s ends with ‘-s.html’. will the above code works for this url’s or what should be the code change for this url’s to work

    example urls
    1. example.com/aa/bbb-s.html
    2. example.com/cc/adfdk-s.html
    3. example.com/fdfdfdfdfj/djhfdjfdjhf-s.html

      shakyaabiral responded:
      September 2, 2016 at 1:48 AM

      Hello Ravi,
      You need to code some mechanism to recognize argument corresponding to aa/bbb-s.html
      like the cms module does for converting url like about-us to corresponding page id.

      $page = Mage::getModel(‘cms/page’);
      $pageId = $page->checkIdentifier($identifier, Mage::app()->getStore()->getId());
      if (!$pageId) {
      return false;
      }

    Ravi said:
    September 2, 2016 at 6:42 AM

    This pages not created using cms(Your code perfectly works for cms pages).this urls created from the third party and this pages doesn’t have any pageid. i did below changes it works when ‘aa’ or ‘cc’ not a category name or product name

    public function match(Zend_Controller_Request_Http $request)
    {
    if (strpos($request->getRequestUri(), ‘-s.html’) !== false) {
    $request->setModuleName(“mymodule”)
    ->setControllerName(“index”)
    ->setActionName(‘index’);
    return true;
    }
    }

      shakyaabiral responded:
      September 2, 2016 at 7:03 AM

      Thats good.
      You have to implement some logic in your code to handle the urls. If you don’t have page_ids then you must have some kind of logic behind what content the specific url is supposed to retrieve.

        Ravi said:
        September 2, 2016 at 7:16 AM

        I am actually beginner to magento i dont have much knokledge could you please help me to solve this issues.

        Requirments
        1. when this kind of urls comes it should come to my controller(From this controllers i will display products)

        shakyaabiral responded:
        September 5, 2016 at 5:15 AM

        Hello Ravi,
        The
        ->setControllerName(“index”)// replace index with your controller name
        ->setActionName(“index”) // replace index with your action name
        ->setParam(“someparameter”, “your_parameter_value”);

        These lines in the article make it possible for the request to be routed to your controller

        If you know how to build a custom module in Magento, then it should take you to “IndexController”‘s “IndexAction” with “someparameter” as request parameters.

    Ravi said:
    September 6, 2016 at 7:46 AM

    The above condition is working fine for the url’s like example.com/something/extra-s.html(Here something is not category name in my DB) but for the url’s like example.com/outdoor/sample-s.html not working bcs here outdoor is a category name. when this kind of url’s comes my module not considered for the execution bcs magento trying to get category based routing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s