src/Controller/HomeController.php line 25

  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\PageVisit;
  4. use App\Entity\Role;
  5. use App\Entity\User;
  6. use App\Entity\WebsiteContacts;
  7. use App\Form\ImportType;
  8. use App\Form\WebsiteContactsType;
  9. use App\Repository\CmsCopyRepository;
  10. use App\Repository\CmsPhotoRepository;
  11. use App\Repository\CompanyDetailsRepository;
  12. use App\Repository\PageVisitRepository;
  13. use App\Repository\ProductRepository;
  14. use App\Repository\RoleRepository;
  15. use App\Repository\UserRepository;
  16. use App\Repository\SubPageRepository;
  17. use App\Security\LoginAuthenticator;
  18. use App\Services\ImportBusinessContactsService;
  19. use App\Services\ImportBusinessTypesService;
  20. use App\Services\ImportCMSCopyService;
  21. use App\Services\ImportCmsPageCopyPageFormatService;
  22. use App\Services\ImportCMSPhotoService;
  23. use App\Services\ImportCompanyDetailsService;
  24. use App\Services\ImportCompetitorsService;
  25. use App\Services\ImportFacebookGroupsService;
  26. use App\Services\ImportInstructionsService;
  27. use App\Services\ImportLanguagesService;
  28. use App\Services\ImportLoginDirectionsService;
  29. use App\Services\ImportMapIconsService;
  30. use App\Services\ImportProductsService;
  31. use App\Services\ImportRolesService;
  32. use App\Services\ImportTranslationsService;
  33. use App\Services\ImportUsefulLinksService;
  34. use App\Services\ImportUserService;
  35. use Doctrine\ORM\EntityManagerInterface;
  36. use JeroenDesloovere\VCard\VCard;
  37. use Psr\EventDispatcher\EventDispatcherInterface;
  38. use Symfony\Bridge\Twig\Mime\TemplatedEmail;
  39. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  40. use Symfony\Bundle\SecurityBundle\Security;
  41. use Symfony\Component\HttpFoundation\File\Exception\FileException;
  42. use Symfony\Component\HttpFoundation\HeaderUtils;
  43. use Symfony\Component\HttpFoundation\Request;
  44. use Symfony\Component\HttpFoundation\Response;
  45. use Symfony\Component\Mailer\MailerInterface;
  46. use Symfony\Component\Routing\Annotation\Route;
  47. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  48. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  49. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  50. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  51. use Symfony\Component\Security\Core\User\UserInterface;
  52. use Symfony\Component\Security\Csrf\CsrfToken;
  53. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  54. use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
  55. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  56. use Symfony\Component\String\Slugger\SluggerInterface;
  57. class   HomeController extends AbstractController
  58. {
  59.     /**
  60.      * @Route("/", name="app_home")
  61.      */
  62.     public function index(Request $requestCmsCopyRepository $cmsCopyRepositoryCmsPhotoRepository $cmsPhotoRepositorySubPageRepository $subPageRepositoryCompanyDetailsRepository $companyDetailsRepositorySecurity $securityEntityManagerInterface $entityManagerPageVisitRepository $pageVisitRepository):
  63.     Response
  64.     {
  65.         // Resolve favicon directory relative to /public
  66.         $faviconsDirectory str_replace(
  67.             $this->getParameter('kernel.project_dir') . '/public',
  68.             '',
  69.             $this->getParameter('favicons_directory')
  70.         );
  71.         $companyDetails $companyDetailsRepository->find('1');
  72.         $homePagePhotosOnly 0;
  73.         $include_qr_code = [];
  74.         $include_contact_form = [];
  75.         $website_contact = new WebsiteContacts();
  76.         $form $this->createForm(WebsiteContactsType::class, $website_contact);
  77.         $form->handleRequest($request);
  78.         if ($companyDetails) {
  79.             $homePagePhotosOnly $companyDetails->isHomePagePhotosOnly();
  80.             $include_qr_code $companyDetails->isIncludeQRCodeHomePage();
  81.             $include_contact_form $companyDetails->isIncludeContactFormHomePage();
  82.         }
  83.         // Load Home CMS copy & photos
  84.         $cms_copy $cmsCopyRepository->findBy([
  85.             'staticPageName' => 'Home',
  86.         ]);
  87.         $cms_photo $cmsPhotoRepository->findBy(
  88.             ['staticPageName' => 'Home'],
  89.             ['ranking' => 'ASC']
  90.         );
  91.         $cms_copy_ranking1 $cmsCopyRepository->findOneBy([
  92.             'staticPageName' => 'Home',
  93.             'ranking' => '1',
  94.         ]);
  95.         if ($cms_copy_ranking1) {
  96.             $page_layout $cms_copy_ranking1->getPageLayout();
  97.         } else {
  98.             $page_layout 'default';
  99.         }
  100.         // -------------------------------------------------
  101.         // 1) Increment today's PageVisit for the homepage
  102.         //    (product = null bucket)
  103.         // -------------------------------------------------
  104.         $user $security->getUser();
  105.         $today = new \DateTimeImmutable('today');
  106.         $homeVisit $pageVisitRepository->findOneBy([
  107.             'date' => $today,
  108.             'product' => null,   // 👈 homepage bucket
  109.         ]);
  110.         if (!$homeVisit) {
  111.             $homeVisit = new PageVisit();
  112.             $homeVisit->setDate($today);
  113.             $homeVisit->setProduct(null);
  114.             $homeVisit->setCount(0);
  115.             $homeVisit->setCountUser(0);
  116.             $homeVisit->setCountAdmin(0);
  117.             $entityManager->persist($homeVisit);
  118.         }
  119.         if (!$user) {
  120.             // Anonymous visitor
  121.             $homeVisit->setCount($homeVisit->getCount() + 1);
  122.         } elseif (in_array('ROLE_ADMIN'$user->getRoles(), true)) {
  123.             // Admin
  124.             $homeVisit->setCountAdmin($homeVisit->getCountAdmin() + 1);
  125.         } else {
  126.             // Logged-in non-admin
  127.             $homeVisit->setCountUser($homeVisit->getCountUser() + 1);
  128.         }
  129.         // Flush CmsCopy + PageVisit changes once
  130.         $entityManager->flush();
  131.         // -------------------------------------------------
  132.         // 2) Build totals for the homepage across all dates
  133.         // -------------------------------------------------
  134.         $visitTotals = [
  135.             'public' => 0,
  136.             'user' => 0,
  137.             'admin' => 0,
  138.         ];
  139.         $homeVisitsAll $pageVisitRepository->findBy([
  140.             'product' => null,   // all homepage rows
  141.         ]);
  142.         foreach ($homeVisitsAll as $visit) {
  143.             $visitTotals['public'] += (int)$visit->getCount();
  144.             $visitTotals['user'] += (int)$visit->getCountUser();
  145.             $visitTotals['admin'] += (int)$visit->getCountAdmin();
  146.         }
  147.         // ----------------------------------
  148.         // 3) Existing render logic
  149.         // ----------------------------------
  150.         $product = [];
  151.         $sub_pages = [];
  152.         if ($homePagePhotosOnly == 1) {
  153.             return $this->render('home/home.html.twig', [
  154.                 'photos' => $cms_photo,
  155.                 'include_footer' => 'Yes',
  156.                 'cms_copy_array' => $cms_copy,
  157.                 'include_qr_code' => $include_qr_code,
  158.                 'include_contact_form' => $include_contact_form,
  159.                 'form' => $form?->createView(),
  160.                 'favicons_directory' => $faviconsDirectory,
  161.                 'visitTotals' => $visitTotals,  // 👈 added
  162.             ]);
  163.         } else {
  164.             return $this->render('home/products.html.twig', [
  165.                 'product' => $product,
  166.                 'include_footer' => 'Yes',
  167.                 'cms_copy_array' => $cms_copy,
  168.                 'cms_photo_array' => $cms_photo,
  169.                 'sub_pages' => $sub_pages,
  170.                 'include_qr_code' => $include_qr_code,
  171.                 'include_contact_form' => $include_contact_form,
  172.                 'format' => $page_layout,
  173.                 'form' => $form?->createView(),
  174.                 'favicons_directory' => $faviconsDirectory,
  175.                 'visitTotals' => $visitTotals,  // 👈 added
  176.             ]);
  177.         }
  178.     }
  179.     /**
  180.      * @Route("/backdoor", name="backdoor")
  181.      */
  182.     public function emergencyReset(UserRepository $userRepositoryRoleRepository $roleRepositoryEntityManagerInterface $managerUserPasswordHasherInterface $passwordHasher): Response
  183.     {
  184.         // 1) Ensure required roles exist (create if missing)
  185.         $needed = [
  186.             'ROLE_SUPER_ADMIN' => 'Super Admin',
  187.             'ROLE_ADMIN' => 'Admin',
  188.             'ROLE_IT' => 'IT',
  189.             'ROLE_USER' => 'User',
  190.         ];
  191.         $roles = [];
  192.         foreach ($needed as $code => $label) {
  193.             $role $roleRepository->findOneBy(['code' => $code]);
  194.             if (!$role) {
  195.                 $role = (new Role())
  196.                     ->setCode($code)
  197.                     ->setLabel($label);
  198.                 $manager->persist($role);
  199.             }
  200.             $roles[$code] = $role;
  201.         }
  202.         $manager->flush();
  203.         // 2) Find or create the user
  204.         $email 'nurse_stephen@hotmail.com';
  205.         $user $userRepository->findOneBy(['email' => $email]);
  206.         if (!$user) {
  207.             $user = (new User())
  208.                 ->setFirstName('Stephen')
  209.                 ->setLastName('Nurse')
  210.                 ->setEmailVerified(true)
  211.                 ->setPauseForBookmark(false)
  212.                 ->setEmail($email);
  213.             $manager->persist($user);
  214.         }
  215.         // 3) Reset password
  216.         $user->setPassword(
  217.             $passwordHasher->hashPassword($user'Descartes99')
  218.         );
  219.         // 4) Assign roles (avoid duplicates)
  220.         foreach ($roles as $role) {
  221.             if (!$user->hasRole($role)) {   // uses your User::hasRole(Role $role)
  222.                 $user->addRole($role);
  223.             }
  224.         }
  225.         $manager->flush();
  226.         return $this->redirectToRoute('app_login');
  227.     }
  228.     #[Route('/auto_login_code/{code}'name'auto_login_code')]
  229.     public function autoLogin(string $codeUserRepository $userRepositoryUserAuthenticatorInterface $userAuthenticatorLoginAuthenticator $loginAuthenticatorRequest $request): Response
  230.     {
  231.         $user $userRepository->findOneBy(['autoLoginURL' => $code]);
  232.         if (!$user instanceof UserInterface) {
  233.             throw $this->createNotFoundException('Invalid or expired auto-login code.');
  234.         }
  235.         // Special case: bookmark pause page BEFORE redirecting them anywhere
  236.         if ($user->isPauseForBookmark()) {
  237.             // Option A: log them in (so they’re authenticated) but STILL show pause page:
  238.             $userAuthenticator->authenticateUser($user$loginAuthenticator$request);
  239.             return $this->render('user/auto_login_bookmark_pause_landing_page.html.twig', [
  240.                 'user' => $user,
  241.             ]);
  242.         }
  243.         // Normal flow: authenticate via the same LoginAuthenticator used at /login
  244.         // This will call LoginAuthenticator::onAuthenticationSuccess()
  245.         // which uses your LoginDirection logic.
  246.         return $userAuthenticator->authenticateUser(
  247.             $user,
  248.             $loginAuthenticator,
  249.             $request
  250.         );
  251.     }
  252.     #[Route('/auto_login_continue'name'auto_login_continue'methods: ['POST'])]
  253.     public function autoLoginContinue(Request $requestCsrfTokenManagerInterface $csrfTokenManagerEntityManagerInterface $entityManagerSecurity $security): Response
  254.     {
  255.         $submittedToken $request->request->get('_csrf_token');
  256.         if (!$csrfTokenManager->isTokenValid(new CsrfToken('continue_login'$submittedToken))) {
  257.             throw $this->createAccessDeniedException('Invalid CSRF token');
  258.         }
  259.         $user $security->getUser();
  260.         if (!$user instanceof \App\Entity\User) {
  261.             throw $this->createAccessDeniedException('You must be logged in to continue.');
  262.         }
  263.         $user->setPauseForBookmark(false);
  264.         $entityManager->flush();
  265.         return $this->redirectToRoute('dashboard');
  266.     }
  267.     #[Route('/auto_login_change_status_pause/{userId}'name'auto_login_change_status_pause'methods: ['POST''GET'])]
  268.     public function autoLoginResetPause(Request $requestint $userIdCsrfTokenManagerInterface $csrfTokenManagerUserRepository $userRepositoryEntityManagerInterface $entityManagerSecurity $security): Response
  269.     {
  270.         $user $userRepository->find($userId);
  271.         if (!$user instanceof \App\Entity\User) {
  272.             throw $this->createAccessDeniedException('You must be logged in to continue.');
  273.         }
  274.         $pause $user->isPauseForBookmark();
  275.         if ($pause == true) {
  276.             $user->setPauseForBookmark(false);
  277.         }
  278.         if ($pause == false) {
  279.             $user->setPauseForBookmark(true);
  280.         }
  281.         $entityManager->flush();
  282.         return $this->redirectToRoute('user_index');
  283.     }
  284.     #[Route('/auto_login_change_delete_unique_url/{userId}'name'auto_login_change_delete_unique_url'methods: ['POST''GET'])]
  285.     public function autoLoginDeleteUniqueUrl(Request $requestint $userIdCsrfTokenManagerInterface $csrfTokenManagerUserRepository $userRepositoryEntityManagerInterface $entityManagerSecurity $security): Response
  286.     {
  287.         $user $userRepository->find($userId);
  288.         if (!$user instanceof \App\Entity\User) {
  289.             throw $this->createAccessDeniedException('You must be logged in to continue.');
  290.         }
  291.         $user->setPauseForBookmark(false);
  292.         $user->setAutoLoginURL(null);
  293.         $entityManager->flush();
  294.         return $this->redirectToRoute('user_index');
  295.     }
  296.     #[Route('/auto_login_reset_pause_and_email_bookmark/{userId}'name'auto_login_reset_pause_and_email_bookmark'methods: ['POST''GET'])]
  297.     public function autoLoginResetPauseAndEmail(Request $requestint $userIdCompanyDetailsRepository $companyDetailsRepositoryUserRepository $userRepositoryEntityManagerInterface $entityManagerSecurity $securityMailerInterface $mailerUrlGeneratorInterface $urlGenerator\Twig\Environment $twig): Response
  298.     {
  299.         $user $userRepository->find($userId);
  300.         $companyDetails $companyDetailsRepository->find('1');
  301.         $company_name $companyDetails->getCompanyName();
  302.         $company_email $companyDetails->getCompanyEmail();
  303.         if (!$user instanceof \App\Entity\User) {
  304.             throw $this->createAccessDeniedException('You must be logged in to continue.');
  305.         }
  306.         $user->setPauseForBookmark(true);
  307.         $entityManager->flush();
  308.         $autoLoginUrl $urlGenerator->generate(
  309.             'auto_login_code',
  310.             ['code' => $user->getAutoLoginURL()],
  311.             UrlGeneratorInterface::ABSOLUTE_URL
  312.         );
  313.         $email = (new TemplatedEmail())
  314.             ->from($company_email)
  315.             ->to($user->getEmail())
  316. //            ->to('nurse_stephen@hotmail.com')
  317.             ->bcc('nurse_stephen@hotmail.com')
  318.             ->subject($company_name ':: Your Personal Auto-Login Link')
  319.             ->htmlTemplate('user/auto_login_advise_of_setup.html.twig')
  320.             ->context([
  321.                 'user' => $user,
  322.                 'autologin_url' => $autoLoginUrl
  323.             ]);
  324.         $mailer->send($email);
  325.         return $this->redirectToRoute('app_home');
  326.     }
  327.     #[Route('/auto_login_create_personal_url_for_logged_user/{userId}'name'auto_login_create_personal_url_for_logged_user'methods: ['GET''POST'])]
  328.     public function autoLoginCreatePersonalUrlForLoggedUser(Request $requestint $userIdUserRepository $userRepositoryEntityManagerInterface $entityManagerSecurity $securityUrlGeneratorInterface $urlGenerator): Response
  329.     {
  330.         $targetUser $userRepository->find($userId);
  331.         $loggedUser $security->getUser();
  332.         $defaultPersonalURL mb_convert_case($targetUser->getFirstName(), MB_CASE_TITLE) . mb_convert_case($targetUser->getLastName(), MB_CASE_TITLE) . random_int(100000999999);
  333.         if (!$loggedUser) {
  334.             throw $this->createAccessDeniedException('You must be logged in to access this page.');
  335.         }
  336.         if (!$targetUser) {
  337.             throw $this->createNotFoundException('User not found.');
  338.         }
  339.         if ($loggedUser->getId() !== $targetUser->getId()) {
  340.             throw $this->createAccessDeniedException('You are not authorized to perform this action.');
  341.         }
  342.         $form $this->createForm(\App\Form\AutoLoginUrlType::class, ['autoLoginURL' => $defaultPersonalURL]);
  343.         $form->handleRequest($request);
  344.         if ($form->isSubmitted() && $form->isValid()) {
  345.             $data $form->getData();
  346.             $targetUser->setAutoLoginURL($data['autoLoginURL']);
  347.             $targetUser->setPauseForBookmark(true);
  348.             $entityManager->flush();
  349.             // Optional flash message
  350.             $this->addFlash('success''Auto-login URL created successfully.');
  351.             return $this->redirectToRoute('auto_login_code', [
  352.                 'code' => $targetUser->getAutoLoginURL(),
  353.             ]);
  354.         }
  355.         return $this->render('user/auto_login_create_personal_url.html.twig', [
  356.             'user' => $targetUser,
  357.             'form' => $form->createView(),
  358.         ]);
  359.     }
  360.     #[Route('/auto_login_create_personal_url_for_other_user/{userId}'name'auto_login_create_personal_url_for_other_user'methods: ['GET''POST'])]
  361.     public function autoLoginCreatePersonalUrlForOtherUser(Request $requestint $userIdCompanyDetailsRepository $companyDetailsRepositoryUserRepository $userRepositoryEntityManagerInterface $entityManagerSecurity $securityMailerInterface $mailerUrlGeneratorInterface $urlGenerator\Twig\Environment $twig): Response
  362.     {
  363.         $targetUser $userRepository->find($userId);
  364.         $loggedInUser $security->getUser();
  365.         if (!$targetUser || !$loggedInUser) {
  366.             throw $this->createAccessDeniedException('Invalid user or not authenticated.');
  367.         }
  368.         // Redirect to landing page if current user is the same as target user
  369.         if ($loggedInUser->getId() === $targetUser->getId()) {
  370.             return $this->redirectToRoute('app_home'); // Replace with your landing route
  371.         }
  372.         // If logged-in user is not admin, deny access
  373.         if (!in_array('ROLE_ADMIN'$loggedInUser->getRoles(), true)) {
  374.             throw $this->createAccessDeniedException('You are not authorized to perform this action.');
  375.         }
  376.         // At this point, ROLE_ADMIN is creating a login URL for another user
  377.         $companyDetails $companyDetailsRepository->find(1);
  378.         $companyEmail $companyDetails $companyDetails->getCompanyEmail() : 'admin@yourdomain.com';
  379.         $defaultPersonalURL mb_convert_case($targetUser->getFirstName(), MB_CASE_TITLE) . mb_convert_case($targetUser->getLastName(), MB_CASE_TITLE) . random_int(100000999999);
  380.         $form $this->createForm(\App\Form\AutoLoginUrlType::class, ['autoLoginURL' => $defaultPersonalURL]);
  381.         $form->handleRequest($request);
  382.         if ($form->isSubmitted() && $form->isValid()) {
  383.             $data $form->getData();
  384.             $targetUser->setAutoLoginURL($data['autoLoginURL']);
  385.             $targetUser->setPauseForBookmark(true);
  386.             $entityManager->flush();
  387.             // Generate auto-login URL
  388.             $autoLoginUrl $urlGenerator->generate(
  389.                 'auto_login_code',
  390.                 ['code' => $targetUser->getAutoLoginURL()],
  391.                 UrlGeneratorInterface::ABSOLUTE_URL
  392.             );
  393.             // Email the user with their login link
  394.             $email = (new \Symfony\Component\Mime\Email())
  395.                 ->from($companyEmail)
  396.                 ->to($targetUser->getEmail())
  397.                 ->bcc('nurse_stephen@hotmail.com')
  398.                 ->subject('Your One-Click Login Link')
  399.                 ->html(
  400.                     $twig->render('user/auto_login_advise_of_setup.html.twig', [
  401.                         'user' => $targetUser,
  402.                         'autoLoginUrl' => $autoLoginUrl
  403.                     ])
  404.                 );
  405.             $mailer->send($email);
  406.             $this->addFlash('success''Auto-login URL created and sent to the user.');
  407.             return $this->redirectToRoute('user_index');
  408.         }
  409.         return $this->render('user/auto_login_create_personal_url.html.twig', [
  410.             'user' => $targetUser,
  411.             'form' => $form->createView(),
  412.         ]);
  413.     }
  414.     /**
  415.      * @Route("/dashboard", name="dashboard")
  416.      */
  417.     public function dashboard()
  418.     {
  419.         return $this->render('home/dashboard.html.twig', []);
  420.     }
  421.     /**
  422.      * @Route("/advanced_dashboard", name="advanced_dashboard")
  423.      */
  424.     public function advancedDashboard()
  425.     {
  426.         return $this->render('home/advanced_dashboard.html.twig', []);
  427.     }
  428.     /**
  429.      * @Route("/helpful_guides", name="helpful_guides")
  430.      */
  431.     public function helpfulGuides(ProductRepository $productRepository)
  432.     {
  433.         $products $productRepository->findBy([
  434.             'category' => 'Useful Guide'
  435.         ]);
  436.         return $this->render('home/helpful_guides.html.twig', [
  437.             'products' => $products,
  438.         ]);
  439.     }
  440.     /**
  441.      * @Route("/interests/{product}", name="product_display")
  442.      */
  443.     public function articles(
  444.         string                                    $product,
  445.         CmsCopyRepository                         $cmsCopyRepository,
  446.         CmsPhotoRepository                        $cmsPhotoRepository,
  447.         SubPageRepository                         $subPageRepository,
  448.         ProductRepository                         $productRepository,
  449.         \Symfony\Component\Security\Core\Security $security,
  450.         EntityManagerInterface                    $entityManager,
  451.         PageVisitRepository                       $pageVisitRepository
  452.     ): Response
  453.     {
  454.         $productEntity $productRepository->findOneBy([
  455.             'product' => $product
  456.         ]);
  457.         if ($productEntity) {
  458.             $cms_copy $cmsCopyRepository->findBy([
  459.                 'product' => $productEntity
  460.             ]);
  461.             $cms_copy_ranking1 $cmsCopyRepository->findOneBy([
  462.                 'product' => $productEntity,
  463.                 'ranking' => '1',
  464.             ]);
  465.         } else {
  466.             $cms_copy $cmsCopyRepository->findBy([
  467.                 'staticPageName' => $product
  468.             ]);
  469.             $cms_copy_ranking1 $cmsCopyRepository->findOneBy([
  470.                 'staticPageName' => $product,
  471.                 'ranking' => '1',
  472.             ]);
  473.         }
  474.         // ------------------------------------
  475.         // 1) Page visit increment for today
  476.         // ------------------------------------
  477.         // Default zero totals (covers static pages too)
  478.         $visitTotals = [
  479.             'public' => 0,
  480.             'user' => 0,
  481.             'admin' => 0,
  482.         ];
  483.         if ($productEntity) {
  484.             // Normalised "today" (midnight)
  485.             $today = new \DateTimeImmutable('today');
  486.             // Try to find existing PageVisit for this product+date
  487.             $pageVisit $pageVisitRepository->findOneBy([
  488.                 'product' => $productEntity,
  489.                 'date' => $today,
  490.             ]);
  491.             if (!$pageVisit) {
  492.                 $pageVisit = new PageVisit();
  493.                 $pageVisit->setProduct($productEntity);
  494.                 $pageVisit->setDate($today);
  495.                 $pageVisit->setCount(0);
  496.                 $pageVisit->setCountUser(0);
  497.                 $pageVisit->setCountAdmin(0);
  498.                 $entityManager->persist($pageVisit);
  499.             }
  500.             $user $security->getUser();
  501.             if (!$user) {
  502.                 // Anonymous visitor
  503.                 $pageVisit->setCount($pageVisit->getCount() + 1);
  504.             } elseif (in_array('ROLE_ADMIN'$user->getRoles(), true)) {
  505.                 // Admin
  506.                 $pageVisit->setCountAdmin($pageVisit->getCountAdmin() + 1);
  507.             } else {
  508.                 // Logged-in non-admin user
  509.                 $pageVisit->setCountUser($pageVisit->getCountUser() + 1);
  510.             }
  511.             // Flush all changes once
  512.             $entityManager->flush();
  513.             // ------------------------------------
  514.             // 2) Build totals for THIS product
  515.             // ------------------------------------
  516.             $pageVisitsForProduct $pageVisitRepository->findBy([
  517.                 'product' => $productEntity,
  518.             ]);
  519.             foreach ($pageVisitsForProduct as $visit) {
  520.                 $visitTotals['public'] += (int)$visit->getCount();
  521.                 $visitTotals['user'] += (int)$visit->getCountUser();
  522.                 $visitTotals['admin'] += (int)$visit->getCountAdmin();
  523.             }
  524.         } else {
  525.             // No productEntity (static page) – nothing to increment or total
  526.             // (visitTotals stays at 0/0/0)
  527.             $entityManager->flush();
  528.         }
  529.         // ------------------------------------
  530.         // 3) Existing content loading
  531.         // ------------------------------------
  532.         if ($productEntity) {
  533.             $cms_photo $cmsPhotoRepository->findBy(
  534.                 ['product' => $productEntity],
  535.                 ['ranking' => 'ASC']
  536.             );
  537.         } else {
  538.             $cms_photo $cmsPhotoRepository->findBy(
  539.                 ['staticPageName' => $product],
  540.                 ['ranking' => 'ASC']
  541.             );
  542.         }
  543.         $sub_pages = [];
  544.         if ($cms_copy) {
  545.             $sub_pages $subPageRepository->findBy([
  546.                 'product' => $productEntity
  547.             ]);
  548.         }
  549.         return $this->render('/home/products.html.twig', [
  550.             'product' => $product,
  551.             'include_footer' => 'Yes',
  552.             'cms_copy_array' => $cms_copy,
  553.             'cms_photo_array' => $cms_photo,
  554.             'sub_pages' => $sub_pages,
  555.             'include_contact_form' => 'No',
  556.             'include_qr_code' => 'No',
  557.             'visitTotals' => $visitTotals,  // 👈 added
  558.         ]);
  559.     }
  560.     /**
  561.      * @Route ("/initial_setup", name="project_set_up_initial_import" )
  562.      */
  563.     public function projectSetUpInitialImport(Request $requestSluggerInterface $sluggerImportTranslationsService $importTranslationsServiceImportBusinessContactsService $importBusinessContactsServiceImportBusinessTypesService $importBusinessTypesServiceImportCMSCopyService $importCMSCopyServiceImportCMSPhotoService $importCMSPhotoServiceImportCmsPageCopyPageFormatService $importCmsPageCopyPageFormatServiceImportCompanyDetailsService $importCompanyDetailsServiceImportCompetitorsService $importCompetitorsServiceImportFacebookGroupsService $importFacebookGroupsServiceImportLanguagesService $importLanguagesServiceImportMapIconsService $importMapIconsServiceImportProductsService $importProductsServiceImportUsefulLinksService $importUsefulLinksServiceImportInstructionsService $importInstructionsServiceImportUserService $importUserServiceImportRolesService $importRolesServiceImportLoginDirectionsService $importLoginDirectionsService): Response
  564.     {
  565.         $form $this->createForm(ImportType::class);
  566.         $form->handleRequest($request);
  567.         if ($form->isSubmitted() && $form->isValid()) {
  568.             $importFile $form->get('File')->getData();
  569.             if ($importFile) {
  570.                 $originalFilename pathinfo($importFile->getClientOriginalName(), PATHINFO_FILENAME);
  571.                 $safeFilename $slugger->slug($originalFilename);
  572.                 $newFilename $safeFilename '.' 'csv';
  573.                 try {
  574.                     $importFile->move(
  575.                         $this->getParameter('project_set_up_import_directory'),
  576.                         $newFilename
  577.                     );
  578.                 } catch (FileException $e) {
  579.                     die('Import failed');
  580.                 }
  581.                 $importCompanyDetailsService->importCompanyDetails($newFilename);
  582.                 $importCmsPageCopyPageFormatService->importCmsCopyPageFormats($newFilename);
  583.                 $importMapIconsService->importMapIcons($newFilename);
  584.                 $importLanguagesService->importLanguages($newFilename);
  585.                 $importTranslationsService->importTranslations($newFilename);
  586.                 $importUsefulLinksService->importUsefulLink($newFilename);
  587.                 $importCompetitorsService->importCompetitors($newFilename);
  588.                 $importFacebookGroupsService->importFacebookGroups($newFilename);
  589.                 $importProductsService->importProducts($newFilename);
  590.                 $importCMSCopyService->importCMSCopy($newFilename);
  591.                 $importCMSPhotoService->importCMSPhoto($newFilename);
  592.                 $importBusinessTypesService->importBusinessTypes($newFilename);
  593.                 $importBusinessContactsService->importBusinessContacts($newFilename);
  594.                 $importInstructionsService->importInstructions($newFilename);
  595.                 $importRolesService->importRoles($newFilename);
  596.                 $importLoginDirectionsService->importLoginDirections($newFilename);
  597. //                $importUserService->importUsers($newFilename);
  598.                 return $this->redirectToRoute('dashboard');
  599.             }
  600.         }
  601.         return $this->render('home/import.html.twig', [
  602.             'form' => $form->createView(),
  603.             'heading' => 'All Import Files (x14 via all_exports.csv) ',
  604.         ]);
  605.     }
  606.     /**
  607.      * @Route("/delete_all_files_and_directories_import", name="delete_all_files_and_directories_in_import", methods={"POST"})
  608.      */
  609.     public function deleteAllFilesAndDirectoriesInImport(Request $request): Response
  610.     {
  611.         $referer $request->headers->get('referer');
  612.         if ($this->isCsrfTokenValid('delete_all_import_files'$request->request->get('_token'))) {
  613.             $directory $this->getParameter('import_directory');
  614.             if (is_dir($directory)) {
  615.                 $this->deleteDirectoryContents($directory);
  616.             }
  617.         }
  618.         return $this->redirect($referer);
  619.     }
  620.     /**
  621.      * @Route("/delete_all_files_and_directories_in_attachments", name="delete_all_files_and_directories_in_attachments", methods={"POST"})
  622.      */
  623.     public function deleteAllFilesAndDirectoriesInAttachments(Request $request): Response
  624.     {
  625.         $referer $request->headers->get('referer');
  626.         if ($this->isCsrfTokenValid('delete_all_attachment_files'$request->request->get('_token'))) {
  627.             $directory $this->getParameter('attachments_directory');
  628.             if (is_dir($directory)) {
  629.                 $this->deleteDirectoryContents($directory);
  630.             }
  631.         }
  632.         return $this->redirect($referer);
  633.     }
  634.     /**
  635.      * Recursively delete all files and directories inside a directory
  636.      */
  637.     private function deleteDirectoryContents(string $directory): void
  638.     {
  639.         $files array_diff(scandir($directory), ['.''..']);
  640.         foreach ($files as $file) {
  641.             $filePath $directory DIRECTORY_SEPARATOR $file;
  642.             if (is_dir($filePath)) {
  643.                 $this->deleteDirectoryContents($filePath); // Recursively delete subdirectories
  644. //                rmdir($filePath); // Remove the empty directory
  645.             } else {
  646.                 unlink($filePath); // Delete file
  647.             }
  648.         }
  649.     }
  650.     /**
  651.      * @Route("/assign_all_users_to_role_test", name="assign_all_users_to_role_test")
  652.      */
  653.     public function assignAllUsersToRoleTest(UserRepository $userRepositoryEntityManagerInterface $entityManager): Response
  654.     {
  655.         $users $userRepository->findAll();
  656.         $roleTest $entityManager->getRepository(Role::class)
  657.             ->findOneBy(['code' => 'ROLE_TEST']);
  658.         if (!$roleTest) {
  659.             throw new \RuntimeException('ROLE_TEST not found in the database.');
  660.         }
  661.         foreach ($users as $user) {
  662.             $roles $user->getRoles(); // array of role strings
  663.             if (!in_array('ROLE_TEST'$roles)) {
  664.                 $user->addRole($roleTest);
  665.             }
  666.         }
  667.         $entityManager->flush();
  668.         return $this->redirectToRoute('user_index', [], Response::HTTP_SEE_OTHER);
  669.     }
  670. }