Preventing events from triggering again – alternative solution
This article is a continuation of my previous article Preventing events from triggering again (and again, and again..). Recently, I have found out, that the solution described there does not work in some cases. So I have had to come with an alternative solution and it is actually more simple and ‘pure PHP’. So let’s take a look at it..
In my case, this solution did not work, when Shopware 6 event CustomerBeforeLoginEvent was triggered multiple times, because of its logic, that caused a recursion:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Shopware\Core\Checkout\Customer\Event\CustomerBeforeLoginEvent; class Subscriber implements EventSubscriberInterface { private $dispatcher; public function __construct( EventDispatcherInterface $dispatcher ) { $this->dispatcher = $dispatcher; } public static function getSubscribedEvents(): array { return [ CustomerBeforeLoginEvent::class => 'onBeforeLogin' ]; } public function onBeforeLogin (CustomerBeforeLoginEvent $event) { //remove this subscriber from the dispatcher $this->dispatcher->removeSubscriber($this); //do something, that triggers the login once more } } |
I am not sure, why this works in other cases and not in this one, but a solution to this is basically just saving the status, e.g. “this was already triggered” to the class property (variable, that is available within the whole class). Here is how it looks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Shopware\Core\Checkout\Customer\Event\CustomerBeforeLoginEvent; class Subscriber implements EventSubscriberInterface { private $dispatched; public static function getSubscribedEvents(): array { return [ CustomerBeforeLoginEvent::class => 'onBeforeLogin' ]; } public function onBeforeLogin (CustomerBeforeLoginEvent $event) { //make sure, that this gets called just once if (!$this->dispatched) { //set value, when first called $this->dispatched = 1; //do something, that triggers the login once more } } } |
I actually like this solution more, that the other one. The advantages ae quite clear – no dependency injection is needed and we get the ability to define, not just if, but how many times we allow the subscriber to trigger the recursion. Let’s allow it just two times:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Shopware\Core\Checkout\Customer\Event\CustomerBeforeLoginEvent; class Subscriber implements EventSubscriberInterface { private $dispatched; public static function getSubscribedEvents(): array { return [ CustomerBeforeLoginEvent::class => 'onBeforeLogin' ]; } public function onBeforeLogin (CustomerBeforeLoginEvent $event) { //make sure, that this gets called just twice if ($this->dispatched <= 2) { //raise value, when called $this->dispatched += 1; //do something, that triggers the login once more } } } |
I hope that this will help someone. For me, it is a reminder, that sometimes the simplest solution is the best. Well, most times actually. 🙂