Question

While I am familiar with registering using a front end controller, I cannot seem to utilize this front end controller from my router class without first hard coding a PHP include of the controller class. Which I do not believe should be necessary if everything is configured correctly. I'd like to utilize this router class to see if the requested URL is a match for my extension, and if so call the appropriate controller/action. My Current setup is as follows:

In my extension's etc/config.xml file I have registered both my router and controller:

<frontend>
    <routers>
        <doall_manual>
            <use>standard</use>
            <args>
                <module>DoALL_Manual</module>
                <frontName>doall_manual</frontName>
            </args>
        </doall_manual>
    </routers>
</frontend>
<default>
    <web>
        <routers>
            <doall_manual>
                <area>frontend</area>
                <class>DoALL_Manual_Controller_Router</class>
            </doall_manual>
        </routers>
    </web>
</default>

Here is my router class:

Notice the require_once statement in here. I am convinced that this line of code is not necessary if my extension were to be setup properly. For example, Mage_Cms_Controller_Router does no such thing.

class DoALL_Manual_Controller_Router extends Mage_Core_Controller_Varien_Router_Standard
{

    public function match(Zend_Controller_Request_Http $request)
    {
        // checking before even try to find out that current module
        // should use this router
        if (!$this->_beforeModuleMatch()) {
            return false;
        }

        $path = explode('/', trim($request->getPathInfo(), '/'));

        if ($path[0] != 'parts-manual') {
            return false;
        }

        $request
            ->setModuleName('doall_manual')
            ->setControllerName('manual');

        switch (count($path)) {
            case 1:
                $request->setActionName('index');
                break;

            case 2:
                $request->setActionName('manual');
                break;

            case 3:
                $request->setActionName('page');
                break;

            default:
                $request->setActionName('noroute');
                break;
        }

        // TODO: This line shouldn't be needed, but I'm unsure as to why it is not detecting the controller's location on it's own.
        require_once 'DoALL'.DS.'Manual'.DS.'controllers'.DS.'ManualController.php';

        $controllerInstance = Mage::getControllerInstance('DoALL_Manual_ManualController', $request, $this->getFront()->getResponse());

        // dispatch action
        $request->setDispatched(true);
        $controllerInstance->dispatch($request->getActionName());

        return true;
    }

}

My Front End Controller:

class DoALL_Manual_ManualController extends Mage_Core_Controller_Front_Action
{
    /**
     * Display all manuals
     */
    public function indexAction()
    {
        echo __METHOD__;
    }

    /**
     * Display a manual's index
     */
    public function manualAction()
    {
        echo __METHOD__;
    }

    /**
     * Display the parts from a manual's page.
     */
    public function pageAction()
    {
        echo __METHOD__;
    }

}

Obviously I am not finished with the development for this controller. However the point of this post not centered around the contents of this controller's actions. It is simply accessing these actions from my router, without having to specifically do a require statement on it first.

The front end controller itself, works just fine. These URL paths will in fact echo out the method names as expected:

/doall_manual/manual/
/doall_manual/manual/manual/
/doall_manual/manual/page/

Furthermore, my current configuration is working. As I expect, these URL paths perform as expected also:

/parts-manual/
/parts-manual/ANYTHING_HERE/
/parts-manual/ANYTHING_HERE/ANYTHING_HERE_ALSO/

And lastly, /parts-manual/ANYTHING_HERE/ANYTHING_HERE_ALSO/longer_url/ results in Magento's 404 page.

Some observations:

My router is extending Mage_Core_Controller_Varien_Router_Standard whereas the Mage_Cms router is extending Mage_Core_Controller_Varien_Router_Abstract. I've attempted to register my router in the same way Magento has:

class DoALL_Manual_Controller_Router extends Mage_Core_Controller_Varien_Router_Abstract

Added this to my etc/config.xml file, and commented out my original registration of the router from default/web/routers:

<global>
    <events>
        <controller_front_init_routers>
            <observers>
                <doall_manual>
                    <class>DoALL_Manual_Controller_Router</class>
                    <method>initControllerRouters</method>
                </doall_manual>
            </observers>
        </controller_front_init_routers>
    </events>
<global>

Then added in this method to my router:

/**
 * 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('doall_manual', $this);
}

This approach, while it works, it still does not resolve my original question as to why do I have to perform a hard coded require statement on my controller class.

Was it helpful?

Solution

Well... after taking nearly an hour to write out this question I resolved it literally just as I finished writing it. So in an effort to at least have this hour not got to waste I decided to post it so that it can maybe contribute something to the community.

This right here, was entirely unnecessary:

$controllerInstance = Mage::getControllerInstance('DoALL_Manual_ManualController', $request, $this->getFront()->getResponse());

$request->setDispatched(true);
$controllerInstance->dispatch($request->getActionName());

These lines I had added in, while taking inspiration from Inchoo's Post from 2012.

Final configuration is as follows:

etc/config.xml

<frontend>
    <routers>
        <doall_manual>
            <use>standard</use>
            <args>
                <module>DoALL_Manual</module>
                <frontName>doall_manual</frontName>
            </args>
        </doall_manual>
    </routers>
</frontend>
<default>
    <web>
        <routers>
            <doall_manual>
                <area>frontend</area>
                <class>DoALL_Manual_Controller_Router</class>
            </doall_manual>
        </routers>
    </web>
</default>

Router:

class DoALL_Manual_Controller_Router extends Mage_Core_Controller_Varien_Router_Standard
{

    public function match(Zend_Controller_Request_Http $request)
    {
        // checking before even try to find out that current module
        // should use this router
        if (!$this->_beforeModuleMatch()) {
            return false;
        }

        $path = explode('/', trim($request->getPathInfo(), '/'));

        if ($path[0] != 'parts-manual') {
            return false;
        }

        $request
            ->setModuleName('doall_manual')
            ->setControllerName('manual');

        switch (count($path)) {
            case 1:
                $request->setActionName('index');
                break;

            case 2:
                $request->setActionName('manual');
                break;

            case 3:
                $request->setActionName('page');
                break;

            default:
                $request->setActionName('noroute');
                break;
        }

        return true;
    }

}

Controller:

(no changes necessary)

So many hours spent so that I could eliminate that one line of code (the require statement)...

Maybe.. just maybe, this post will save someone else hours of frustration someday :)

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top