3

I'm implementing a SSO extension for Magento2. Right now I want to add an observer to the customer_logout event in order to execute a redirection to my custom logout endpoint.

I followed what is described at this other question, and also what I saw at CheckContactUsFormObserver class:.

I defined my event file (/etc/frontend/events.xml)

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="customer_logout">
    <observer name="{company_module}_customer_logout" instance="{Company}\{Module}\Observer\Frontend\CustomerLogOutObserver" />
</event>

I described my observer in {Company}{Module}\Observer\Frontend\CustomerLogOutObserver.php

namespace {Company}\{Module}\Observer\Frontend;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\ActionFlag;
use Magento\Framework\App\Response\RedirectInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use {Company}\{Module}\Helper\Data;

class CustomerLogOutObserver implements ObserverInterface
{
    protected $_customerSession;
    protected $_helper;
    protected $_redirect;

    public function __construct(
        Session $customerSession,
        Data $helper,
        ActionFlag $actionFlag,
        RedirectInterface $redirect
    ) {
        $this->_customerSession = $customerSession;
        $this->_helper = $helper;
        $this->_actionFlag = $actionFlag;
        $this->_redirect = $redirect;
    }

    public function execute(EventObserver $observer)
    {
        $controller = $observer->getControllerAction();
        $this->_actionFlag->set('', Action::FLAG_NO_DISPATCH, true);
        $this->_redirect->redirect($controller->getResponse(), 'sso/saml2/logout');
    }
}

But when I executed it, I got:

 Call to a member function getResponse() on a non-object 

It seems that the getControllerAction returns nothing.

Why a similar code is supoosed to be working for the CheckContactUsFormObserver class and not for me?

4

the objects you can get from an observer object depend on which objects are passed into it when the event is dispatched.

In the case of customer_logout, only the customer is provided: https://github.com/magento/magento2/blob/1d97cd9ddee038c9b93c43b74c8e318702a70a33/app/code/Magento/Customer/Model/Session.php#L464

The response seems to be a shared object (since it is not declared as non shared): https://github.com/magento/magento2/blob/1f5214730533c4e80f4bf00416aa5a3d82433571/app/etc/di.xml#L18

Given that, you should be able to inject the Object in your constructor using \Magento\Framework\App\ResponseInterface and you should get the actual used response.

namespace {Company}\{Module}\Observer\Frontend;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\ActionFlag;
use Magento\Framework\App\Response\RedirectInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use {Company}\{Module}\Helper\Data;
use Magento\Framework\App\ResponseInterface;

class CustomerLogOutObserver implements ObserverInterface
{
    protected $_customerSession;
    protected $_helper;
    protected $_redirect;
    protected $_response;

    public function __construct(
        Session $customerSession,
        Data $helper,
        ActionFlag $actionFlag,
        RedirectInterface $redirect,
        ResponseInterface $response
    ) {
        $this->_customerSession = $customerSession;
        $this->_helper = $helper;
        $this->_actionFlag = $actionFlag;
        $this->_redirect = $redirect;
        $this->_response = $response;
    }

    public function execute(EventObserver $observer)
    {
        $this->_actionFlag->set('', Action::FLAG_NO_DISPATCH, true);
        $this->_redirect->redirect($this->_response, 'sso/saml2/logout');
    }
}

Let me know if this doesn't work. The response Object might also be created by a factory in a Controller Action. In this cas, it would be another Instance of the Object and you would have to obtain the correct instance

Design hint: for easier maintenance, you should name your observers after the task it does, not after the event it is dispatched from

| improve this answer | |
  • I had no errors, but redirection is not working – smartin Mar 18 '16 at 18:39
  • ok, i think the problem is, that in the logOut Controller Action, the redirect path is hardcoded: github.com/magento/magento2/blob/develop/app/code/Magento/…. A solution might be, to create an after Plugin on the Logout Controller Action execute method and modify the resultRedirect return value. An explanation on how to use an after Plugin can be found here: alanstorm.com/magento_2_object_manager_plugin_system – David Verholen Mar 18 '16 at 18:48
  • It seems quite complex for just a redirection :( I will try – smartin Mar 18 '16 at 19:02
  • currently i see no other way to edit the redirect other then via a plugin or completely replacing the logout controller action – David Verholen Mar 18 '16 at 19:05
  • Really appreciate your help. with this Plugin then I don't need the observer anymore, right? Can I set a __construct on the Plugin and get the Helpers and the customerSession? And since I don't want the logout action to take place, make I use beforePlugin rather than afterPlugin? – smartin Mar 18 '16 at 19:24
0

Yeah, I have found 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: In your code

namespace {Company}\{Module}\Observer\Frontend;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\ActionFlag;
use Magento\Framework\App\Response\RedirectInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use {Company}\{Module}\Helper\Data;


class CustomerLogOutObserver implements ObserverInterface
{
    protected $_customerSession;
    protected $_helper;
    protected $_redirect;
    /**
     * @var \Magento\Framework\App\ResponseFactory
     */
    private $responseFactory;

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

    public function __construct(
        Session $customerSession,
        Data $helper,
        ActionFlag $actionFlag,
        RedirectInterface $redirect,
       \Magento\Framework\App\ResponseFactory $responseFactory,
        \Magento\Framework\UrlInterface $url
    ) {
        $this->_customerSession = $customerSession;
        $this->_helper = $helper;
        $this->_actionFlag = $actionFlag;
        $this->_redirect = $redirect;
        $this->responseFactory = $responseFactory;
        $this->url = $url;
    }

    public function execute(EventObserver $observer)
    {
       $redirectionUrl = $this->url->getUrl( 'sso/saml2/logout');
        $this->responseFactory->create()->setRedirect($redirectionUrl)->sendResponse();
    }
}
| improve this answer | |

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.