Search code examples
phpsymfonyfosuserbundlesylius

How to listen to the event when a shop user is doing email confirmation at Sylius?


After the registration of a shop user in Sylius as the base framework of my web application, the user would receive an email with a verification link.

After the user clicks on this event, the user will be enabled in the database due to some magic stuff that happens in the behind of Sylius.

I want to catch this event for being able to add more actions on this step.

Steps taken:

First, i've tried to find an event, that could be fired in case of a successfully user authentication.

bin/console debug:event-dispatcher

"sylius.admin_user.post_create" event
"sylius.admin_user.post_update" event
"sylius.admin_user.pre_delete" event
"sylius.admin_user.pre_update" event
"sylius.cart_change" event
"sylius.channel.pre_delete" event
"sylius.customer.post_register" event
"sylius.customer.pre_register" event
"sylius.customer.pre_update" event
"sylius.menu.shop.account" event
"sylius.oauth_user.post_create" event
"sylius.oauth_user.post_update" event
"sylius.oauth_user.pre_delete" event
"sylius.order.post_address" event
"sylius.order.post_complete" event
"sylius.order.post_payment" event
"sylius.order.post_select_shipping" event
"sylius.order.pre_complete" event
"sylius.order_item.pre_create" event
"sylius.order_item.pre_delete" event
"sylius.order_item.pre_update" event
"sylius.product.initialize_update" event
"sylius.product.pre_create" event
"sylius.product.pre_update" event
"sylius.product_review.pre_create" event
"sylius.product_variant.initialize_update" event
"sylius.shipment.post_ship" event
"sylius.shop_user.post_create" event
"sylius.shop_user.post_update" event
"sylius.shop_user.pre_delete" event
"sylius.taxon.pre_create" event
"sylius.taxon.pre_update" event
"sylius.user.email_verification.token" event
"sylius.user.password_reset.request.pin" event
"sylius.user.password_reset.request.token" event
"sylius.user.post_email_verification" event
"sylius.user.pre_password_change" event
"sylius.user.pre_password_reset" event
"sylius.user.security.impersonate" event
"sylius.user.security.implicit_login" event

This will list many events but nothing indicating any email-verification process besides "sylius.user.email_verification.token", which is only responsible to create the final auth token.

Then i stepped through the code of Sylius and found the UserController and the action verifyAction, that sounds promiseful.

Within this action, several events are dispatched:

$eventDispatcher->dispatch(UserEvents::PRE_EMAIL_VERIFICATION, new GenericEvent($user));

and

$eventDispatcher->dispatch(UserEvents::POST_EMAIL_VERIFICATION, new GenericEvent($user));

These constants are defined as:

public const PRE_EMAIL_VERIFICATION = 'sylius.user.pre_email_verification';
public const POST_EMAIL_VERIFICATION = 'sylius.user.post_email_verification';

However, both Event types aren't registered in the global event dispatcher of symfony, they both where not listed with debug:event-dispatcher as shown before and thus can't be listened to.

We already have a custom EventLister that works well for the registration-process, but it won't catch any email-verification events:

/**
 * {@inheritdoc}
 */
public static function getSubscribedEvents()
{
    return [
        'sylius.customer.pre_register' => ['onCustomerPreRegister', 0],
        'sylius.customer.post_register' => ['onCustomerPostRegister', 0],
        UserEvents::POST_EMAIL_VERIFICATION => ['onPostEmailVerification', 0]
    ];
}

Then i tried to overwrite the UserController in an own Implementation overriding the original controller and duplicating the verifyAction-Method (despite the fact that this wouldn't be a good option for the long tail)

Still no success.

While we have successfully overridden several controllers, the UserController seems to be on an island that can't be changed to another class:

Our services.yml looks like this:

sylius.controller.shop_user:
    class: AppBundle\Controller\User\UserController
    public: true

sylius.controller.shop.homepage:
    class: AppBundle\Controller\Shop\HomepageController
    public: true

The custom controller for the Homepage is working well, while any entries for UserController will be always ignored.

Possible solutions:

in short, i tried several approaches and are thinking about other one (even those that would be very ugly):

  1. listen to appropriate events -> no chance
  2. overwrite the UserController -> no chance or did it the wrong way
  3. create a cronjob that will fetch the sylius_customer-table in an interval of 5 min or so to find customers that have enabled their account recently -> yeah, can be done but is ugly too

Something else?

Any idea how to solve our issue?


Solution

  • Tried code below, and successfully received a dump message after opening verification link (in my case it was http://localhost/app_dev.php/en_US/verify/mUJjxjiI0OjWhRC2)

    <?php
    
    namespace AppBundle\EventListener;
    
    use Sylius\Bundle\UserBundle\UserEvents;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\EventDispatcher\GenericEvent;
    
    class CustomVerificationSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return [
                UserEvents::POST_EMAIL_VERIFICATION => 'onVerification'
            ];
        }
    
        public function onVerification(GenericEvent $event)
        {
            dump('it works');
        }
    
    }