2

How to redirect to module/controller/action when I'm inside an observer method? I need to redirect to myrouter/adminhtml_test/validate.

Why I need this: I try to fire my controller's action which has to perform some additional calculations after "Save Config" was clicked in System -> Configuration -> Mysection. I registered observer for the event admin_system_config_changed_section_{$section}.

In my method handle_adminSystemConfigChangedSection() in Model/Observer.php I try to fire my action but it doesn't redirect to that action:

class My_Module_Model_Observer
{
    public function handle_adminSystemConfigChangedSection()
    {
        //I tried this code but it doesn't trigger the action:
        $url = Mage::helper('adminhtml')->getUrl("myrouter/adminhtml_test/validate");
        Mage::log($url); //To check if URL is correct (and it is correct)
        Mage::app()->getResponse()->setRedirect($url);
    }
}

Observer method and controller work fine (below are configuration details). I replaced the observer method with this code (from Magento forum) using header() and it works:

public function handle_adminSystemConfigChangedSection()
{
    $url = Mage::helper('adminhtml')->getUrl("myrouter/adminhtml_test/validate");
    Mage::log($url);
    header( 'Location: ' . $url );
    exit();
}

But this doesn't seem to be a correct way of redirecting to an action. How it should be done?

Configuration details:

Observer and router configuration in config.xml:

<config>
...
    <global>
        ...
        <events>
            <admin_system_config_changed_section_mysection>
                <observers>
                    <mymodule>
                        <type>singleton</type>
                        <class>mymodule/observer</class>
                        <method>handle_adminSystemConfigChangedSection</method>
                    </mymodule>
                </observers>
            </admin_system_config_changed_section_mysection>
        </events>
    </global>
    <admin>
        <routers>
            <mymodule>
                <use>admin</use>
                <args>
                    <module>My_Module</module>
                    <frontName>myrouter</frontName>
                </args>
            </mymodule>
        </routers>
    </admin>
...
</config>

Controller in controllers/Adminhtml/TestController.php:

class My_Module_Adminhtml_TestController extends Mage_Adminhtml_Controller_Action
{   
    public function validateAction()
    {
        Mage::log('Test: action is working!'); //To check if action is working
        //do something here...
    }
}
4
  • Where are you dispatching the event? Apr 16, 2013 at 11:22
  • stackoverflow.com/questions/5290639/…
    – B00MER
    Apr 16, 2013 at 11:46
  • @JonathanHussey I hook on the event after "Save Config" was clicked in System > Configuration > Mysection. In my method handle_adminSystemConfigChangedSection() I try to fire my controller's action which has to perform some additional calculations.
    – zitix
    Apr 16, 2013 at 13:49
  • @JonathanHussey He isn't; the event is dispatched in the core.
    – benmarks
    Apr 16, 2013 at 13:53

1 Answer 1

4

Again, what are you trying to do? Redirecting someone from sysconfig to your controller is odd UX at best, even if you redirect back to sysconfig after your code executes. If that's all you're doing, you should be consuming the POST and letting sysconfig behave as normal.

The reason your (first) redirect isn't working is that after this event fires, execution flows back to the controller action, which then sets its own redirect per usual:

class Mage_Adminhtml_System_ConfigController extends Mage_Adminhtml_Controller_Action
{
    public function saveAction()
    {
        // snip ...
        try {
            // snip ...
            Mage::dispatchEvent("admin_system_config_changed_section_{$section}",
                array('website' => $website, 'store' => $store)
            );
            // snip ...            }
        catch (Mage_Core_Exception $e) {
            // snip ...
        }
        catch (Exception $e) {
            // snip ...
        }
            // snip ...

        $this->_redirect('*/*/edit', array('_current' => array('section', 'website', 'store')));
    }

You can get around this in a couple ways:

  1. (not ideal) Flush the response after setting the redirect in your browser; while this obeys your current intent, know that you are preventing subsequent native code from executing both in the action and in postDispatch().
  2. (better, but still pretty ugly) Instantiate your observer as a singleton, set a flag, and then set that observer class to also consume the controller_action_postdispatch_adminhtml_system_config_save event using a different method which will set your redirect.

E.g.

public function checkShouldRedirect()
{
    $response = Mage::app()->getResponse();

    //use 'mysection' to check we are in correct section
    if (self::$flag==true && $this->getRequest()->getParam('section') == 'mysection') {
        $response->setRedirect(
            Mage::helper('adminhtml')->getUrl('myrouter/adminhtml_test/validate')
        );
        //below is only necessary for option 1
        //$response->sendResponse();
    }
}

If you are going to engage in the second option - and provided that you aren't opposed to the action saving the open panel state - you might as well just set your observer to consume only the postdispatch event, since you can test that you are saving your section by testing the section param.

7
  • Thank you. What I'm trying to do: fire my controller's action which has to perform some additional calculations after "Save Config" was clicked in System -> Configuration -> Mysection. I registered observer for event admin_system_config_changed_section_{$section}. I edited my post.
    – zitix
    Apr 16, 2013 at 14:05
  • I am fairly convinced that you are going about this the wrong way; redirect is unnecessary. It sounds like you just need to execute your code after the postdata has been saved. You can do this by observing controller_action_postdispatch_adminhtml_system_config_save and testing that it is your section being saved.
    – benmarks
    Apr 16, 2013 at 14:17
  • It is just a solution proposed in this thread. All I need to do is to execute my code (which has to perform some validation on the saved data) in my section in admin. I placed that code inside my controller (it redirects back so user don't know that something happened behind the scenes) because I thought it's how it should be done in Magento. But if it can be done more simple, then I'm opened to any suggestions. :) So you say that this event admin_system_config_changed_section_{$section} is not right for what I'm trying to do here?
    – zitix
    Apr 16, 2013 at 14:33
  • You can use that event and just put/invoke your validation logic in the observer method. I'm wondering why you are validating after the data is saved rather than before.
    – benmarks
    Apr 16, 2013 at 15:30
  • This is rather some additional calculation, my english is poor so I named it validation. Your solution with controller_action_postdispatch_adminhtml_system_config_save event works great. I moved all the logic from controller to observer. But there are 2 issues. 1) Error Access to undeclared static property: My_Module_Model_Observer::$flag, I removed it for testing. What does self::$flag actually do? And how to fix it? 2) Error Call to undefined method: I had to replace $this->getRequest() with Mage::app()->getRequest(). It works but is it correct? Can it cause any issues?
    – zitix
    Apr 16, 2013 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.