src/EventSubscriber/SourceSubscriber.php line 68

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use App\Entity\Source;
  4. use App\Entity\User;
  5. use App\Entity\UserInterface;
  6. use App\Event\ObjectEvent;
  7. use App\Events;
  8. use Doctrine\Persistence\ManagerRegistry;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
  11. use Symfony\Component\HttpFoundation\RequestStack;
  12. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  13. use Symfony\Component\HttpKernel\Event\RequestEvent;
  14. use Symfony\Component\HttpKernel\KernelEvents;
  15. /**
  16.  * Listens for user registration events and attaches a source entity to the user
  17.  * based on referral or UTM parameters found in the request query string.
  18.  *
  19.  * This subscriber stores the source identifier in the session during the initial
  20.  * request, then associates the matching Source entity to the User entity when the
  21.  * user is created.
  22.  *
  23.  * Supported query parameters:
  24.  * - ?source=SOURCE_ID
  25.  * - ?utm_source=UTM_IDENTIFIER
  26.  *
  27.  * Session key used: self::SESSION_NAME
  28.  */
  29. class SourceSubscriber implements EventSubscriberInterface
  30. {
  31.     public const SESSION_NAME 'app_source_data';
  32.     public const SOURCE_PARAMETER 'source';
  33.     public const UTM_PARAMETER 'utm_source';
  34.     /** @var RequestStack */
  35.     private $requestStack;
  36.     /** @var ManagerRegistry */
  37.     private $managerRegistry;
  38.     /**
  39.      * @param RequestStack    $requestStack
  40.      * @param ManagerRegistry $managerRegistry
  41.      */
  42.     public function __construct(RequestStack $requestStackManagerRegistry $managerRegistry)
  43.     {
  44.         $this->requestStack $requestStack;
  45.         $this->managerRegistry $managerRegistry;
  46.     }
  47.     /**
  48.      * {@inheritdoc}
  49.      */
  50.     public static function getSubscribedEvents(): array
  51.     {
  52.         return [
  53.             KernelEvents::REQUEST => 'onKernelRequest',
  54.             Events::USER_CREATED => 'onUserCreated',
  55.         ];
  56.     }
  57.     /**
  58.      * @param RequestEvent $event
  59.      */
  60.     public function onKernelRequest(RequestEvent $event): void
  61.     {
  62.         if (!$event->isMainRequest()) {
  63.             return;
  64.         }
  65.         $request $event->getRequest();
  66.         if ($request->isXmlHttpRequest()) {
  67.             return;
  68.         }
  69.         if (!$request->query->has(self::SOURCE_PARAMETER)
  70.             && !$request->query->has(self::UTM_PARAMETER)
  71.         ) {
  72.             return;
  73.         }
  74.         $request->getSession()->set(
  75.             self::SESSION_NAME,
  76.             $request->query->get(self::SOURCE_PARAMETER) ?: $request->query->get(self::UTM_PARAMETER)
  77.         );
  78.     }
  79.     /**
  80.      * @param ObjectEvent $event
  81.      */
  82.     public function onUserCreated(ObjectEvent $event): void
  83.     {
  84.         try {
  85.             /** @var SessionInterface $session */
  86.             $session $this->requestStack->getSession();
  87.         } catch (SessionNotFoundException $e) {
  88.             return;
  89.         }
  90.         if (!$session->has(self::SESSION_NAME)) {
  91.             return;
  92.         }
  93.         /** @var Source|null $source */
  94.         $source null;
  95.         // Find via ID (ref)
  96.         try {
  97.             $source $this->managerRegistry
  98.                 ->getRepository(Source::class)
  99.                 ->find($session->get(self::SESSION_NAME));
  100.         } catch (\Exception $e) {
  101.         }
  102.         // Find via UTM_SOURCE
  103.         if (!$source) {
  104.             $source $this->managerRegistry
  105.                 ->getRepository(Source::class)
  106.                 ->findOneBy([
  107.                     'utmSource' => $session->get(self::SESSION_NAME),
  108.                 ]);
  109.         }
  110.         if (!$source) {
  111.             return;
  112.         }
  113.         $entity $event->getObject();
  114.         if ($entity instanceof UserInterface) {
  115.             $entity->setSource($source);
  116.             $this->managerRegistry
  117.                 ->getRepository(User::class)
  118.                 ->update($entity);
  119.         }
  120.         $session->remove(self::SESSION_NAME);
  121.     }
  122. }