src/EventListener/RequestListener.php line 51

Open in your IDE?
  1. <?php
  2. namespace App\EventListener;
  3. use App\Enum\User\UserRestrictionsEnum;
  4. use Symfony\Component\HttpKernel\Event\RequestEvent;
  5. use Symfony\Component\HttpFoundation\RedirectResponse;
  6. use App\Entity\User;
  7. use App\Entity\Location;
  8. use Symfony\Component\Routing\RouterInterface;
  9. use Symfony\Component\Security\Core\Security;
  10. use App\Service\DatabaseService;
  11. use App\Service\UserAccessService;
  12. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  13. class RequestListener
  14. {
  15.     /**
  16.      * @var RouterInterface
  17.      */
  18.     private $router;
  19.     /**
  20.      * @var Security
  21.      */
  22.     private $security;
  23.     /**
  24.      * @var DatabaseService
  25.      */
  26.     private $databaseService;
  27.     /**
  28.      * @var UserAccessService
  29.      */
  30.     private $userAccessService;
  31.     /**
  32.      * @var ParameterBagInterface
  33.      */
  34.     private $parameterBag;
  35.     public function __construct(RouterInterface $routerSecurity $securityDatabaseService $databaseServiceUserAccessService $userAccessServiceParameterBagInterface $parameterBag) {
  36.         $this->router $router;
  37.         $this->security $security;
  38.         $this->databaseService $databaseService;
  39.         $this->userAccessService $userAccessService;
  40.         $this->parameterBag $parameterBag;
  41.     }
  42.     public function onKernelRequest(RequestEvent $event): void
  43.     {
  44.         $request $event->getRequest();
  45.         $path $request->getPathInfo();
  46.         $user $this->security->getUser();
  47.         // Check for maintenance mode first (before any other processing)
  48.         $maintenanceResponse $this->checkMaintenanceMode($path);
  49.         if ($maintenanceResponse) {
  50.             $event->setResponse($maintenanceResponse);
  51.             return;
  52.         }
  53.         if (!$user instanceof User) {
  54.             return;
  55.         }
  56.         if ($path === "/login" && $request->getSession()->isStarted()) {
  57.             /** @var User $user */
  58.             $user $this->databaseService->getManager()->getRepository(User::class)->findOneBy(["username" =>$user->getUsername()]);
  59.             $activeLocations $user->getActiveLocations();
  60.             if($activeLocations->isEmpty()) {
  61.                 if ($user->isHatchAdministrator()) {
  62.                     $event->setResponse(new RedirectResponse($this->router->generate('admin_index')));
  63.                     return;
  64.                 } else {
  65.                     $event->getRequest()->getSession()->getFlashBag()->add('error'"No active locations for login");
  66.                     return;
  67.                 }
  68.             }
  69.             $defaultLocation $user->getDefaultLocation();
  70.             if ( $defaultLocation instanceof Location && $activeLocations->contains($defaultLocation) ) {
  71.                 $event->setResponse(new RedirectResponse($this->router->generate('client_index', ['locationId' =>$defaultLocation->getId()])));
  72.                 return;
  73.             }
  74.             if($user->isHatchAdministrator()) {
  75.                 $event->setResponse(new RedirectResponse($this->router->generate('admin_index')));
  76.                 return;
  77.             } elseif ($activeLocations->count() === 1) {
  78.                 $event->setResponse(new RedirectResponse($this->router->generate('client_index', ['locationId' =>$activeLocations->first()->getId()])));
  79.                 return;
  80.             } else {
  81.                 $event->setResponse(new RedirectResponse($this->router->generate('location_login_select')));
  82.                 return;
  83.             }
  84.         }
  85.         if (str_starts_with($path'/admin')) {
  86.             if ($user->isHatchAdministrator() && $user->hasRestrictions()) {
  87.                 $restrictionsMap UserRestrictionsEnum::getRestrictionsMap();
  88.                 $userRestrictions $user->getRestrictions();
  89.                 $allowedPaths = [];
  90.                 $redirectRoute 'app_login';
  91.                 foreach ($userRestrictions as $restriction) {
  92.                     if (isset($restrictionsMap[$restriction])) {
  93.                         $allowedPaths array_merge($allowedPaths$restrictionsMap[$restriction]['paths']);
  94.                         if ($redirectRoute === 'app_login') {
  95.                             $redirectRoute $restrictionsMap[$restriction]['redirect_route'];
  96.                         }
  97.                     }
  98.                 }
  99.                 $isAllowed false;
  100.                 foreach ($allowedPaths as $allowedPath) {
  101.                     // Check if the path contains regex pattern
  102.                     if (strpos($allowedPath'[') !== false) {
  103.                         // Convert simple regex pattern to full regex
  104.                         $pattern '#^' str_replace(['['']'], ['['']'], $allowedPath) . '$#';
  105.                         if (preg_match($pattern$path)) {
  106.                             $isAllowed true;
  107.                             break;
  108.                         }
  109.                     } else {
  110.                         // Use simple string comparison for non-regex paths
  111.                         if (str_starts_with($path$allowedPath)) {
  112.                             $isAllowed true;
  113.                             break;
  114.                         }
  115.                     }
  116.                 }
  117.                 if (!$isAllowed) {
  118.                     $event->setResponse(new RedirectResponse($this->router->generate($redirectRoute)));
  119.                     return;
  120.                 }
  121.             } elseif (!$user->isHatchAdministrator()) {
  122.                 $event->setResponse(new RedirectResponse($this->router->generate('app_login')));
  123.                 return;
  124.             }
  125.         }
  126.         if (str_starts_with($path'/client')) {
  127.             $locationId $request->attributes->get('locationId');
  128.             if ($locationId) {
  129.                 $location $this->databaseService->getManager()->getRepository(Location::class)->find($locationId);
  130.                 if ($location instanceof Location && $location->getCompany() && $location->getCompany()->isBillingHold()) {
  131.                     $firstValidLocation $this->userAccessService->getFirstActiveLocationInFirstNonBillingHoldCompany($user);
  132.                     $companyName $location->getCompany()->getName();
  133.                     $request->getSession()->getFlashBag()->add(
  134.                         'error',
  135.                         sprintf(
  136.                             'Payment is Past Due for %s. Please submit payment to regain access. For any questions, please contact ComplianceBilling@KipuHealth.com.',
  137.                             $companyName
  138.                         )
  139.                     );
  140.                     if ($firstValidLocation) {
  141.                         $event->setResponse(
  142.                             new RedirectResponse(
  143.                                 $this->router->generate('client_index', ['locationId' => $firstValidLocation->getId()])
  144.                             )
  145.                         );
  146.                     }
  147.                 }
  148.             }
  149.         }
  150.     }
  151.     /**
  152.      * Check for maintenance mode and return appropriate redirect response
  153.      */
  154.     private function checkMaintenanceMode(string $path): ?RedirectResponse
  155.     {
  156.         // Skip maintenance check for maintenance preview routes (for testing)
  157.         if (strpos($path'/maintenance-preview') === 0) {
  158.             return null;
  159.         }
  160.         // Check maintenance environment variables in priority order
  161.         $maintenanceChecks = [
  162.             'is_maintenance_planned' => 'maintenance_planned',
  163.             'is_maintenance_unexpected' => 'maintenance_unexpected'
  164.             'is_maintenance_failure' => 'maintenance_failure',
  165.             'is_maintenance_suspended' => 'maintenance_suspended',
  166.         ];
  167.         foreach ($maintenanceChecks as $parameter => $route) {
  168.             if ($this->parameterBag->has($parameter) && $this->parameterBag->get($parameter) === true) {
  169.                 return new RedirectResponse($this->router->generate($route));
  170.             }
  171.         }
  172.         return null;
  173.     }
  174. }