12

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.

1
  • Did You found solution for this?
    – BartZalas
    Commented Jul 11, 2019 at 21:06

9 Answers 9

25

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;
    }
}
14
  • 3
    are you working at early morning 4 a.m ? just unbelievable. there is lot to learn from you. Commented Apr 28, 2016 at 5:16
  • 1
    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
    Commented Mar 20, 2017 at 12:36
  • 2
    Don't use exit(); because Magento EcgM2 coding standard show error "Use of exit language construct is discouraged." Commented May 20, 2017 at 12:24
  • 2
    @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. Commented Jan 19, 2018 at 2:29
  • 3
    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. Commented Apr 27, 2018 at 8:49
12

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;


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

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);
    }
3
namespace Adnan\Redirect\Observer;

use Magento\Framework\Event\ObserverInterface;

/**
 * Class Example
 *
 * phpcs:disable Generic.Files.LineLength
 *
 * @package Adnan\Example\Redirect
 */
class Example implements ObserverInterface
{
    /**
     * @var \Magento\Framework\App\ActionFlag
     */
    private $actionFlag;
    /**
     * @var \Magento\Framework\UrlInterface
     */
    private $url;

    /**
     * Data constructor.
     *
     * @param \Magento\Framework\App\ActionFlag $actionFlag
     * @param \Magento\Framework\UrlInterface   $url
     */
    public function __construct(
        \Magento\Framework\App\ActionFlag $actionFlag,
        \Magento\Framework\UrlInterface $url
    ) {

        $this->actionFlag = $actionFlag;
        $this->url = $url;
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        // Stop further processing if your condition is met
        $this->actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
        // then in last redirect
        $observer->getControllerAction()->getResponse()->setRedirect($this->url->getUrl("[FrontName]/[Controller]/[Action]"));

        return $this;
    }
}

Remember to use \Magento\Framework\UrlInterface to generate URL otherwise, you will not be redirected to a top-level structure, e.g. if you are not using UrlInterface and want to redirect from "checkout" with "a/b/c" then it will process "checkout/a/b/c".

You have an option to use \Magento\Framework\App\ActionFlag, it will stop further processing of observers.

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
  • 1
    The question was about Observer/backend, not frontend.
    – LucianDex
    Commented Jan 17, 2023 at 19:52
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');
1

After many solutions tried I found one working code. Here I used the controller_action_predispatch_cms_page_save event which is working fine.

<?php

namespace VendorName\ModuleName\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\App\ActionFlag;

class ObserverClassName implements ObserverInterface
{
    protected $_urlInterface;
    protected $actionFlag;

    public function __construct(
        UrlInterface $urlInterface,
        ActionFlag $actionFlag
    ) {
        $this->_urlInterface = $urlInterface;
        $this->actionFlag = $actionFlag;
    }

    public function execute(Observer $observer)
    {
        $customRedirectionUrl = $this->_urlInterface->getUrl('cms/page/index');
        $this->actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
        $controller = $observer->getControllerAction();
        $response = $controller->getResponse();
        return $response->setRedirect($customRedirectionUrl);
    }
}
1
  • this is the only solution that actually worked for me thanks (on controller_action_predispatch_checkout_index_index )
    – SimoneB
    Commented Jul 25 at 9:46
0

Adnan Answer worked for me.

In event.xml

    <?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xs  d">
    <event name="controller_action_predispatch_checkout_cart_add">
        <observer name="Name-Your-Observer" instance="[Vendor]\[Module]\Observer\[YourClassName]" />
    </event>
</config>

After that in Observer Folder Create YourClassName.php

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

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

class [YourClassName] implements ObserverInterface    
{
    /**
     * @var \Magento\Framework\App\ActionFlag
     */
    private $actionFlag;
    /**
     * @var \Magento\Framework\UrlInterface
     */
    private $url;

    /**
     * Data constructor.
     *
     * @param \Magento\Framework\App\ActionFlag $actionFlag
     * @param \Magento\Framework\UrlInterface   $url
     */
    public function __construct(
        \Magento\Framework\App\ActionFlag $actionFlag,
        \Magento\Framework\UrlInterface $url
    ) {

        $this->actionFlag = $actionFlag;
        $this->url = $url;
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        // Stop further processing if your condition is met
        $this->actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
        // then in last redirect
        $observer->getControllerAction()->getResponse()->setRedirect($this->url->getUrl("[route]/[controller]/[action]"));

        return $this;
    }
}

Let me know if this helps and need all of the files.

-2

You can simply use header("Location: ".$storeUrl."/register-success"); in your observer

2

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.