Domanda

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?

È stato utile?

Soluzione

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;
    }
}

Altri suggerimenti

[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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a magento.stackexchange
scroll top