Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why there is no removeListener() method? #5

Open
foxkill opened this issue Jul 19, 2019 · 2 comments
Open

Why there is no removeListener() method? #5

foxkill opened this issue Jul 19, 2019 · 2 comments

Comments

@foxkill
Copy link

foxkill commented Jul 19, 2019

No description provided.

@maks-rafalko
Copy link
Owner

Could you please explain your use case why is it needed?

@foxkill
Copy link
Author

foxkill commented Jul 20, 2019

Maybe my use case is somewhat constructed, but I have set up a comand bus decorator via an di container (php-di) which allows me to access the event dispatcher through a public method. I have also created an event which is then triggered in the command handler when a record is deleted. If a client (listener) is interested in that event it calls the public method, gets the event dispatcher and registers itself to be notified. To test that, I’ve written two test methods, one which wants to be notified and another one which just tests the successful execution of the command. As the command bus and therefore the event dispatcher are not destroyed between the two test methods, the test method which not wants to be notified becomes also notified, because the listener is still active in the listener array from the first call to addListener(). As code says more then 1000 words, here some sample code:

/**
 * @test
 *
 * @expectedException \DomainException
 */
public function it_should_notify_the_caller_when_deleting_a_registration()
{
  $bus = resolve(CommandBus::class);

  $eventDispatcher = $bus->getEventDispatcher();

  $eventName = (new RegistrationWasDeleted())->getName();

  $eventDispatcher->addListener(
      $eventName,
      function ($event) use ($eventName, $eventDispatcher) {
          // if would be nice here if coulds say: please, dont notify me again.

          // $eventDispatcher->removeListener($eventName, $this);
          throw new \DomainException( ‘i have been notified’);
      }
  );

  $bus->handle(new DeleteRegistrationCommand($this->registration->getId()));
}

/** @test */
public function it_should_soft_delete_a_registration()
{
  $bus = resolve(CommandBus::class);

  $bus->handle(new DeleteRegistrationCommand($this->registration->getId()));

  // Domain exception is thrown, but it should not.
}

I helped myself by reimplementing a class which uses the EventDispatcherInterface and ContainsListenersInterface and of course added the removeListenerMethod($eventName, $listener).
As storage for the listeners I used the SplObjectStorage class so the i can lookup the listener and remove it if necessary. I do not know whether this the removeListener() method fits into the architecture of domain events, but i found a signature for the removeListener() method also available in the symfony event dispatcher interface. Here my implementation of addListener() and removeListener()

public function addListener($eventName, callable $listener)
{
    if (!$this->hasListeners($eventName)) {
       $this->listeners[$eventName] = new \SplObjectStorage;
    }

    $this->listeners[$eventName]->attach($listener)
}

public function removeListener($eventName, $listener = null)
{
   if (!$this->hasListeners($eventName)) {
        return;
   }

   if ($listener === null) {
        if ($this->listeners[$eventName] instanceof \SplObjectStorage) {
            $this->listeners[$eventName]->removeAll($this->listeners[$eventName]);
        }
        unset($this->listeners[$eventName]);
        return;
   }

   $this->listeners[$eventName]->detach($listener);
}

Hopefully, that makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants