How To Create a Suite of Modules in Magento
Carlo Tasca / September 17, 2012

In a recent project, I had to deal with creating a suite of modules in Magento (a module that contains other modules). After several searches on Google, I realised that nobody had created a proper solution for this - I was looking to create the following module structure:

app/code/local/Company/SuiteModule
app/code/local/Company/SuiteModule/Core
app/code/local/Company/SuiteModule/OtherModule

After setting up the above structure, I started testing whether Blocks, Helpers and Models could be instantiated correctly by Magento Factory methods, and I also tested setting up resources for each module to ensure that they would install correctly. 

The following structure would work perfectly in Magento without any modification:

app/code/local/Company/SuiteModule
app/code/local/Company/SuiteModule/etc
app/code/local/Company/SuiteModule/Helper
app/code/local/Company/SuiteModule/Model
app/code/local/Company/SuiteModule/Core
app/code/local/Company/SuiteModule/Core/etc
app/code/local/Company/SuiteModule/Core/Block
app/code/local/Company/SuiteModule/Core/Helper
app/code/local/Company/SuiteModule/Core/Model
app/code/local/Company/SuiteModule/OtherModule
app/code/local/Company/SuiteModule/OtherModule/etc
app/code/local/Company/SuiteModule/OtherModule/Block
app/code/local/Company/SuiteModule/OtherModule/Helper
app/code/local/Company/SuiteModule/OtherModule/Model

Magento Factory methods would look as follows:

Mage::helper('suitemodule');
Mage::getModel('suitemodule/model');
Mage::helper('suitemodule_core');
Mage::getModel('suitemodule_core/model');
Mage::helper('suitemodule_othermodule');
Mage::getModel('suitemodule_othermodule/model');

The problems with such a module structure started when I tried adding controllers to nested Modules. Magento could not correctly route the request to the correct controller. This sent me back on Google big time!!!

After a bit of searching I found a post on the Magento Forum that put me in the right direction...Read post here.

I had to find a way to have my own implementation of getControllerFileName method defined in Mage_Core_Controller_Varien_Router_Standard class. After a bit of thinking I decided that creating custom routers for the suite of modules would have allowed me to implement getControllerFileName as I needed.

I didn't want the new router's classes encapsulated in the suite though, as projects with similar requirements could come up. Because I was not overriding any already defined Magento class, I thought the best way would be to put the new routers in local/Mage/Core namespace (extending like this Mage Core codebase).

I added app/code/local/Mage directory and defined the following:

app/code/local/Mage/Core/Controller/Varien/Router/Suite.php
app/code/local/Mage/Core/Controller/Varien/Router/Suiteadmin.php

In app/code/local/Mage/Core/Controller/Varien/Router/Suite.php I defined getControllerFileName method as follow:

public functiongetControllerFileName($realModule, $controller)
    {
        $parts = explode('_', $realModule);
        $realModule = implode('_', array_splice($parts, 0, 3));
        $file= Mage::getModuleDir('controllers', $realModule);
        if(count($parts)) {
            $file.= DS . implode(DS, $parts);
        }
        $file.= DS.uc_words($controller, DS).'Controller.php';
        return$file;
    }

All I did in the above method was change the following line:

$realModule = implode('_', array_splice($parts, 0, 2));

to:

$realModule = implode('_', array_splice($parts, 0, 3));

The final step was to edit config.xml for my suite modules and set them to use the suite routers instead of Magento Standard/Admin ones.

Firstly, I had to register the router in 'default/web' config area:

     
 
<default>
        <web>
            <routers>
                <suiteadmin>
                    <area>admin</area>
                    <class>Mage_Core_Controller_Varien_Router_Suiteadmin</class>
                </suiteadmin>
                <suite>
                    <area>frontend</area>
                    <class>Mage_Core_Controller_Varien_Router_Suite</class>
                </suite>     
            </routers>
        </web>
</default>

And then to specify routers for frontend and admin config area:

<frontend>
    <routers>
        <othermodule>
            <use>suite</use>
            <args>
                <module>GPMD_SuiteModule_OtherModule</module>
                <frontName>othermodule</frontName>
            </args>
        </othermodule>
    </routers>
</frontend>
 
<admin>
        <routers>
            <othermodule>
                <use>suiteadmin</use>
                <args>
                    <module>GPMD_SuiteModule_OtherModule</module>
                    <frontName>othermodule</frontName>
                </args>
            </othermodule>
        </routers>
</admin>

That's it!!!