7

We have already know that How to redirect from an Observer for magento 1.x version.

but for magento 2,we does not know How to forcefully do redirection from an observer.

I have done google ,but does not get any answer.

  • Did You found solution for this? – BartZalas Jul 11 at 21:06
17

Yup, i have find a solution by myself by doing a research

If you want to do that then on __construct() function of your class observer,you must inject two classes.

  • First, \Magento\Framework\App\ResponseFactory which responsible for redirection,
  • Another class \Magento\Framework\UrlInterface which will make url for that redirection.
  • Then create object for ResponseFactory ,and using setRedirect($YourUrl)->sendResponse(); redirect to your wished url.

Observer

<?php
namespace [Vendor]\[modulename]\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class [YourClass] implements ObserverInterface
{
    /**
     * @var \Magento\Framework\App\ResponseFactory
     */
    private $responseFactory;

    /**
     * @var \Magento\Framework\UrlInterface
     */
    private $url;

    public function __construct(
        ......
        \Magento\Framework\App\ResponseFactory $responseFactory,
        \Magento\Framework\UrlInterface $url,
        ......
    ) {
        $this->responseFactory = $responseFactory;
        $this->url = $url;
    }

    public function execute(Observer $observer)
    {
        $redirectionUrl = $this->url->getUrl('[ModuleName]/[ModuleName]/[[Action]');
        $this->responseFactory->create()->setRedirect($redirectionUrl)->sendResponse();

        return $this;
    }
}

Example:

Here i am write an example of that redirection.

Basically sales_quote_collect_totals_after event,i was try to forcefully redirect to contact us.

Here the observer code:

<?php
namespace Devamit\Mgoto\Observer;
use \Magento\Framework\Event\Observer;
use \Magento\Framework\Event\ObserverInterface;

class Challo implements ObserverInterface {
    protected $_responseFactory;
    protected $_url;

    public function __construct(

        \Magento\Framework\App\ResponseFactory $responseFactory,
        \Magento\Framework\UrlInterface $url
    ) {
        $this->_responseFactory = $responseFactory;
        $this->_url = $url;
    }

    public function execute(Observer $observer) {
        $event = $observer->getEvent();

            $myfile = fopen("var/log/debug.log", "a+") or die("Unable to open file!");
          fwrite($myfile, 'Amitber',true);
          fclose($myfile);
      // $this->_responseFactory->create()->setRedirect('www.google.com')->sendResponse();
           $customerBeforeAuthUrl = $this->_url->getUrl('contact/index/index');
          $this->_responseFactory->create()->setRedirect($customerBeforeAuthUrl)->sendResponse();
      return $this;
    }
}
  • 3
    are you working at early morning 4 a.m ? just unbelievable. there is lot to learn from you. – Baby in Magento Apr 28 '16 at 5:16
  • Hi @amit , I am using 'sales_order_place_before' event and order is placed using ajax. When I use the above code, it do not redirects but it renders the response. I do not want that. can you please suggest a way to redirect to a page when form is saved using ajax. Thanks – anujeet Mar 20 '17 at 12:36
  • 2
    Don't use exit(); because Magento EcgM2 coding standard show error "Use of exit language construct is discouraged." – Prince Patel May 20 '17 at 12:24
  • 1
    @AmitBera If you're not calling exit, you should use \Magento\Framework\App\Response\Http as a constructor argument instead. It won't work when using the factory class. – Milan Simek Jan 19 '18 at 2:29
  • 2
    If you are using a predispatch event then you need to inject \Magento\Framework\App\ActionFlag in your constructor and inside your observer function use $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true); to tell magento to stop processing the further events and then you can use redirectInterface to redirect user whereever you want. – Zeeshan Khuwaja Apr 27 '18 at 8:49
9

injecting the \Magento\Framework\App\ActionFlag $actionFlag and $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);is the way of forcing Magento to stop processing further events and redirect from an observer specially in the case of using predispatch event.

Here is the sample code

public function execute(\Magento\Framework\Event\Observer $observer)
{

    /** @var \Magento\Customer\Controller\Account\LoginPost\Interceptor $controller_action */
    $controller_action = $observer->getData( 'controller_action' );
    $parameters = $controller_action->getRequest()->getParams();
    $session = $this->customerSession;

    if({yourcondition}){


        // setting an action flag to stop processing further hierarchy
        $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);



        /// redirecting back to its referred url
        $observer->getControllerAction()->getResponse()->setRedirect($this->_redirectInterface->getRefererUrl());
        $session->setCustomerFormData($parameters);

    }

    return $this;


}
  • it is a good solution. It will be better if you will add full class in your solution. – Abbas Jan 23 at 8:51
2

Above answer is not working for me I have updated my observer code

public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $params = []; 

        // If you want to redirect with data
        // $url = $this->_urlInterface->getUrl('checkout/cart/index',$params);

        $url = $this->_urlInterface->getUrl('checkout/cart/index');

        $observer->getControllerAction()
                    ->getResponse()
                    ->setRedirect($url);
    }
1

I am also working on a form that use Ajax for request processing. I send the response in the form of json and based on Ajax request success/failure, I use window.location.href to redirect on a page.

You can pass the required URL in the json and can access it in the response using dot (.) operator.

$.ajax({
    url:url,
    data:$("#form-id").serialize(),
    type:'POST',
    dataType:'json',
    showLoader: true,
    success:function(result) {
        if(result.status == true) {
            if (result.product_url) {
                window.location.href = result.product_url;
            }
        }
    },
    error:function(xhr,textStatus,thrownError){
        alert(thrownError);
    }
});

This works fine for me.

1

Depending on the use case, most of proposed solutions have problem: Redirects might be cached, due to other places where the response is set.

Scenario: You do a redirect based on login status -> even after the logs in, the protected page they tried to access before the login still redirects, because the 302 response is cached for one day.

I ended up in doing this:

    if (!$isCustomerLoggedIn && !in_array($actionFullName, self::ALLOWED_ROUTES)) {
        $response = $observer->getEvent()->getControllerAction()->getResponse();
        $response->clearHeaders();
        $this->redirect->redirect($response, 'customer/account/login');
    }

EDIT Does not work --> clearHeaders kills the FPC - working on an alternative solution

EDIT2 Better solution:

        /**
         * @var $action Action
         */
        $action = $observer->getEvent()->getControllerAction();

        /**
         * @var $response \Magento\Framework\App\Response\Http
         */
        $response = $action->getResponse();
        $response->clearHeaders()->setNoCacheHeaders();
        $this->redirect->redirect($response, 'customer/account/login');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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