Question

Is there any examples of using __call in a controller to replace a specific action method.

I have a situation where I need to provide different endpoints to the same controller. A reference to each of these end points is available in the database and so instead of hardcoding a method per endpoint I would like every request that hits the controller to be handled by one method.

The only way I have got this to come close to working is by sticking exit and other similar undesirable functions within the __call method. Surely it's possible to handle the request from here and tell magento not to look for a specific method?

Was it helpful?

Solution

Alternatively, you could extend the preDispatch method of your controller, check which actions are allowed and which not (I recommend you against calling exit, send a proper HTTP status instead), and redirect the request to a single action in your controller, say foobarAction, by using $this->_forward('foobar').

UPDATE

I tested my solution, have a look at Mage_Core_Controller_Varien_Router_Standard::match. This calls a method hasAction on your controller. If you extend that method in the controller and implement your checks (or simply return true, even though I don't recommend it), then you can do what I suggested. Also, since everything happens in preDispatch, to prevent the loop you get add something like this:

if ($this->getRequest()->getActionName() !== 'foobar') {
    $this->_forward('foobar');
}

Here for your reference is what I did:

class Acme_Module_FoobarController extends Mage_Core_Controller_Front_Action
{
    public function preDispatch()
    {
        parent::preDispatch();
        if ($this->getRequest()->getActionName() !== 'foobar') {
            $this->_forward('foobar');
        }
        return $this;
    }

    public function foobarAction()
    {
        $this->getResponse()->setBody('Hey!');
    }

    public function hasAction($action)
    {
        return true;
    }
}

OTHER TIPS

[Edit]
It seams you cannot use __call in controllers starting from version CE - 1.8 (and EE 1.13)
it was possible up to 1.7 because of the method Mage_Core_Controller_Varien_Action::hasAction.
in 1.7 and lower it looked like this:

public functionhasAction($action)
{
    return is_callable(array($this, $this->getActionMethodName($action)));
}

Starting 1.8 it looks like

public functionhasAction($action)
{
    return method_exists(array($this, $this->getActionMethodName($action)));
}

This method is called in the standard router when handling the request:

Mage_Core_Controller_Varien_Router_Standard::match

...
if (!$controllerInstance->hasAction($action)) {
    continue;
}
...

So starting from CE 1.8 the method somethingAction really has to exist, not just be callable.

[Original Answer - works only for versions before CE-1.8]
yes, you can definitely use __call in a controller.
Check this example
but your __call will be called for each method that does not exist in the controller.
So you have to make sure that your method called ends with Action.
Something like this:

public function __call($function, $args){
    if (substr($function, -6) == 'Action') {
         $this->loadLayout('some_default_layout_handle');
         $this->renderLayout();
    }
    else {//otherwise throw an exeption
        throw new Exception ("Method {$function} cannot be called in ". __CLASS__);
    }
}

or, if you want to also get the function name you can do this:

public function __call($function, $args){
    if (substr($function, -6) == 'Action') {
         $functionName = substr($function, 0, strlen($function) - 6);
         //do something with $functionName
    }
    else {//otherwise throw an exeption
        throw new Exception ("Method {$function} cannot be called in ". __CLASS__);
    }
}

so if you call ROOT/module/controller/something (and somethingAction() does not exist) you end up in the __call method.
in the first case you end up with a default page you set, in the second case $functionName will be equal with something.

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