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