src/Controller/PageDefaultController.php line 450

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Page;
  4. use App\Entity\HtmlBlocks;
  5. use App\Entity\PagePreview;
  6. use App\Service\SimpleCache;
  7. use App\Service\OpenAiService;
  8. use App\Service\SitemapService;
  9. use App\Annotation\CmsComponent;
  10. use Doctrine\ORM\EntityManagerInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Routing\RouterInterface;
  14. use Symfony\Component\Routing\Annotation\Route;
  15. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  16. class PageDefaultController extends AbstractController
  17. {
  18.     private array $invalidSetters = [
  19.         'setCreatedAt',
  20.         'setUpdatedAt',
  21.         'setTranslatableLocale',
  22.     ];
  23.     public function __construct(private readonly \App\Service\ServiceController $serviceController, private readonly EntityManagerInterface $em, private readonly RouterInterface $router, private readonly SitemapService $sitemapService, private readonly SimpleCache $cache)
  24.     {
  25.     }
  26.     /**
  27.      * @CmsComponent("Sitemap", active=true, routeName="embed_sitemap")
  28.      */
  29.     #[Route('/tlb/sitemap'name'embed_sitemap')]
  30.     public function embedSitemap(): Response
  31.     {
  32.         $sitemapData $this->sitemapService->getSitemapData();
  33.         return $this->render('@theme/sitemap/sitemap.html.twig', [
  34.             'sitemapData' => $sitemapData
  35.         ]);
  36.     }
  37.     #[Route(path'/members/dash'name'members_dash')]
  38.     public function membersDash(): Response
  39.     {
  40.         return $this->render('@theme/members/members-dash.html.twig');
  41.     }
  42.     public function generateAndModifyMetaDataTags($page$componentEnity)
  43.     {
  44.         if (!$componentEnity) {
  45.             return $page;
  46.         }
  47.         $possibleMetaTitles = ['getHeadline''getHeading''getTitle''getName''getMetaTitle'];
  48.         $possibleMetaDescription = ['getContent''getDescription''getExcerpt''getMetaDescription'];
  49.         if ('' == $page->getMetatitle()) {
  50.             $page->setMetatitle($page->getTitle());
  51.         }
  52.         if ('' == $page->getMetadescription()) {
  53.             $page->setMetadescription($page->getContent());
  54.         }
  55.         $metaDataArray = [];
  56.         foreach ($possibleMetaTitles as $metaTitle) {
  57.             if (method_exists($componentEnity$metaTitle)) {
  58.                 $data call_user_func([$componentEnity$metaTitle]);
  59.                 if ('' != $data) {
  60.                     $metaDataArray['title'] = call_user_func([$componentEnity$metaTitle]);
  61.                 }
  62.             }
  63.         }
  64.         foreach ($possibleMetaDescription as $metaDescription) {
  65.             if (method_exists($componentEnity$metaDescription)) {
  66.                 $data call_user_func([$componentEnity$metaDescription]);
  67.                 if ('' != $data) {
  68.                     $metaDataArray['description'] = $data;
  69.                 }
  70.             }
  71.         }
  72.         if (method_exists($componentEnity'getOgImage')) {
  73.             $data call_user_func([$componentEnity'getOgImage']);
  74.             if ($data) {
  75.                 $metaDataArray['ogImage'] = $data;
  76.             }
  77.         }
  78.         if (method_exists($componentEnity'getOgImageAlt')) {
  79.             $data call_user_func([$componentEnity'getOgImageAlt']);
  80.             if ('' != $data) {
  81.                 $metaDataArray['ogImageAlt'] = $data;
  82.             }
  83.         }
  84.         if (array_key_exists('title'$metaDataArray)) {
  85.             $page->setMetatitle($metaDataArray['title'].' | '.$page->getMetatitle());
  86.         }
  87.         if (array_key_exists('description'$metaDataArray)) {
  88.             $page->setMetadescription(strip_tags((string) $metaDataArray['description']));
  89.         }
  90.         if (array_key_exists('ogImage'$metaDataArray)) {
  91.             $page->setOgImage($metaDataArray['ogImage']);
  92.         }
  93.         if (array_key_exists('ogImageAlt'$metaDataArray)) {
  94.             $page->setOgImageAlt(strip_tags((string) $metaDataArray['ogImageAlt']));
  95.         }
  96.         return $page;
  97.     }
  98.     public function routeToControllerName($routename)
  99.     {
  100.         $routes $this->router->getRouteCollection();
  101.         return $routes->get($routename)->getDefaults();
  102.     }
  103.     public function findPageSlugParameters($slug)
  104.     {
  105.         $matches = [];
  106.         $regex '/{(\w*)}/';
  107.         preg_match_all($regex, (string) $slug$matches);
  108.         return $matches[1];
  109.     }
  110.     public function pageChecks($page)
  111.     {
  112.         if (== $page->isActive()) {
  113.             return false;
  114.         }
  115.         return new \DateTime() >= $page->getViewableFrom();
  116.     }
  117.     #[Route(path'/switch-locale/{_locale}'name'switch_locale')]
  118.     public function switchLocale(mixed $_locale): \Symfony\Component\HttpFoundation\RedirectResponse
  119.     {
  120.         return $this->redirect('/');
  121.         // return $this->redirect($request->headers->get('referer'));
  122.     }
  123.     // public function changeLocale(Request $request, $_locale, $slug){
  124.     //  $pageData = $this->routeMatcher($request, $slug);
  125.     //  return $pageData;
  126.     // }
  127.     #[Route(path'/page.php'name'page_php_home')]
  128.     public function getMethodRouter(SimpleCache $cacheRequest $request)
  129.     {
  130.         $params $request->query->all();
  131.         $debug $request->query->has('_debug');
  132.         $session $request->getSession();
  133.         $cmsComponentArray $this->serviceController->fetchCmsComponents();
  134.         // Using doctrine cache to store dynamic page slugs
  135.         // Used in twig function generatePath (converts id to slug) and assists links with translations
  136.         $slugCache $this->em->getRepository(Page::class)->findByLocale($request->getLocale());
  137.         $cache->set('slugCache'$slugCache);
  138.         if ($request->query->has('_locale')) {
  139.             $this->debug($debug'<p>CHANGING LOCALE</p>');
  140.             if ($request->getLocale() != $request->query->get('_locale')) {
  141.                 $session->set('_locale'$request->query->get('_locale'));
  142.                 $request->setLocale($session->get('_locale'$request->query->get('_locale')));
  143.                 return $this->redirect($this->generateUrl($request->get('_route'), $request->query->all()));
  144.             }
  145.         }
  146.         $structureEntities = [];
  147.         $pageID $request->query->get('page');
  148.         if (!is_numeric($pageID)) {
  149.             throw $this->createNotFoundException('No PageID passed');
  150.         }
  151.         $pageEntity $this->em->getRepository(Page::class)->find($pageID);
  152.         if (null === $pageEntity) {
  153.             throw $this->createNotFoundException('No Page found for id#'.$pageID);
  154.         }
  155.         $pageSlugArray explode('/'$pageEntity->getSlug());
  156.         $fullSegmentOrder = [];
  157.         if (count($pageSlugArray) > 1) {
  158.             $pageSlugArrayCount count($pageSlugArray);
  159.             for ($i 0$i < ($pageSlugArrayCount 1); ++$i) {
  160.                 if (array_key_exists($i$pageSlugArray) && substr_count($pageSlugArray[$i], '{') > 0) {
  161.                     $fullSegmentOrder[] = $pageSlugArray[$i];
  162.                     unset($pageSlugArray[$i]);
  163.                 }
  164.             }
  165.         }
  166.         $this->debug($debug'<p>'.$pageEntity->getSlug().'</p>');
  167.         if (substr_count($pageEntity->getSlug(), '{') > 0) {
  168.             foreach ($params as $key => $id) {
  169.                 $key strtolower($key);
  170.                 if (('_locale' != $key) || ('page' != $key) || ('_debug' != $key)) {
  171.                     $comkey $this->searchArrayKeyVal('slugEntity'$key$cmsComponentArray);
  172.                     $this->debug($debug"<p>Searching for '".$key."' against slugEntity in cmsComponentArray</p>");
  173.                     if (is_numeric($comkey)) {
  174.                         $order array_search($cmsComponentArray[$comkey]['slug'], $fullSegmentOrder);
  175.                         $this->debug($debug'<p>'.$order.' - '.$cmsComponentArray[$comkey]['slugEntity'].'</p>');
  176.                         $bundle str_replace('\\''', (string) $cmsComponentArray[$comkey]['bundle']).':'.$cmsComponentArray[$comkey]['slugEntity'];
  177.                         $structureEntities[$order] = $this->em->getRepository($bundle)->find($id);
  178.                     }
  179.                 }
  180.             }
  181.         }
  182.         $slugfixer implode('/'$pageSlugArray);
  183.         $slug $slugfixer;
  184.         ksort($structureEntities);
  185.         foreach ($structureEntities as $urlelement) {
  186.             $slug .= '/'.$urlelement->getSlug();
  187.         }
  188.         if ($debug) {
  189.             $this->debug($debug'<p>Path re-built to <strong>'.$slug.'</strong></p>');
  190.             $pageData $this->routeMatcherV2($requestltrim($slug'/'));
  191.             if (is_array($pageData)) {
  192.                 $pageAllowed $this->pageChecks($pageData['page']);
  193.                 if (false == $pageAllowed) {
  194.                     throw $this->createNotFoundException('Page view checks for PageID# "'.$pageData['page']->getId().'" has failed (disabled, before viewdate ect...) - so showing 404');
  195.                 }
  196.                 // HTML Blocks
  197.                 $htmlblocks = [];
  198.                 $assignedHtmlblocks $pageData['page']->getHtmlblocks();
  199.                 if ((is_countable($assignedHtmlblocks) ? count($assignedHtmlblocks) : 0) > 0) {
  200.                     $allHtmlBlocks $this->em->getRepository(HtmlBlocks::class)->findBy(['deleted' => false]);
  201.                     foreach ($assignedHtmlblocks as $assignedblock) {
  202.                         foreach ($allHtmlBlocks as $allHtmlBlock) {
  203.                             if ($assignedblock['blockId'] == $allHtmlBlock->getId()) {
  204.                                 $htmlblocks[] = [
  205.                                     'blockId' => $allHtmlBlock->getId(),
  206.                                     'position' => $assignedblock['position'],
  207.                                     'data' => $allHtmlBlock->getHtml(),
  208.                                 ];
  209.                             }
  210.                         }
  211.                     }
  212.                 }
  213.                 $pageMeta $pageData['page'];
  214.                 // replace metatitle if empty
  215.                 if ('' == $pageData['page']->getMetatitle()) {
  216.                     $pageMeta->setMetatitle($pageData['page']->getTitle());
  217.                 }
  218.                 // replace metatitles if exist on components
  219.                 foreach ($pageData['pageComponents'] as $pageComp) {
  220.                     $pageMeta $this->generateAndModifyMetaDataTags($pageData['page'], $pageComp['entity']);
  221.                 }
  222.                 return $this->render('@theme/templates/'.$pageData['page']->getTemplate()->getTemplateFile(), [
  223.                     'page' => $pageMeta,
  224.                     'slug' => $pageData['slug'],
  225.                     'pageComponents' => $pageData['pageComponents'],
  226.                     'pageHtmlBlocks' => $htmlblocks,
  227.                     'longUrl' => strtolower(implode('/'$params)),
  228.                 ]);
  229.             }   // this will be a redirect
  230.             return $pageData;
  231.         }
  232.         return $this->redirect(str_replace('//''/'$slug));
  233.     }
  234.     #[Route(path'/page-preview'name'page_preview_home')]
  235.     public function getPreviewMethodRouter(SimpleCache $cacheRequest $request)
  236.     {
  237.         $params $request->query->all();
  238.         $session $request->getSession();
  239.         $cmsComponentArray $this->serviceController->fetchCmsComponents();
  240.         // Using doctrine cache to store dynamic page slugs
  241.         // Used in twig function generatePath (converts id to slug) and assists links with translations
  242.         $slugCache $this->em->getRepository(Page::class)->findByLocale($request->getLocale());
  243.         $cache->set('slugCache'$slugCache);
  244.         if ($request->query->has('_locale') && $request->getLocale() != $request->query->get('_locale')) {
  245.             $session->set('_locale'$request->query->get('_locale'));
  246.             $request->setLocale($session->get('_locale'$request->query->get('_locale')));
  247.             return $this->redirect($this->generateUrl($request->get('_route'), $request->query->all()));
  248.         }
  249.         $structureEntities = [];
  250.         $pageID $request->query->get('id');
  251.         if (!is_numeric($pageID)) {
  252.             throw $this->createNotFoundException('No PageID passed');
  253.         }
  254.         $pageEntity $this->em->getRepository(Page::class)->find($pageID);
  255.         if (null === $pageEntity) {
  256.             throw $this->createNotFoundException('No Page found for id#'.$pageID);
  257.         }
  258.         if ($request->query->has('preview')) {
  259.             $previewId $request->query->get('preview');
  260.             $previewEntity $this->em->getRepository(PagePreview::class)->find($previewId);
  261.             if (null === $previewEntity) {
  262.                 throw $this->createNotFoundException('No PagePreview found for id#'.$previewId);
  263.             }
  264.             if ($previewEntity->getPage()->getId() != $pageEntity->getId()) {
  265.                 throw $this->createNotFoundException('PagePreview->pageID#'.$previewEntity->getPage()->getId().' does not match PageID#'.$pageID);
  266.             }
  267.             // get nessacary getters (dup content)
  268.             $validSetters $this->getSetters($previewEntity$pageEntity);
  269.             foreach ($validSetters as $validSetter) {
  270.                 if (in_array($validSetter$this->invalidSetters)) {
  271.                     continue;
  272.                 }
  273.                 $validGetter str_replace('set''get', (string) $validSetter);
  274.                 $pageEntity->{$validSetter}($previewEntity->{$validGetter}());
  275.             }
  276.         }
  277.         $pageSlugArray explode('/'$pageEntity->getSlug());
  278.         $fullSegmentOrder = [];
  279.         if (count($pageSlugArray) > 1) {
  280.             $pageSlugArrayCount count($pageSlugArray);
  281.             for ($i 0$i < ($pageSlugArrayCount 1); ++$i) {
  282.                 if (array_key_exists($i$pageSlugArray) && substr_count($pageSlugArray[$i], '{') > 0) {
  283.                     $fullSegmentOrder[] = $pageSlugArray[$i];
  284.                     unset($pageSlugArray[$i]);
  285.                 }
  286.             }
  287.         }
  288.         if (substr_count($pageEntity->getSlug(), '{') > 0) {
  289.             foreach ($params as $key => $id) {
  290.                 $key strtolower($key);
  291.                 if (('_locale' != $key) || ('page' != $key) || ('_debug' != $key)) {
  292.                     $comkey $this->searchArrayKeyVal('slugEntity'$key$cmsComponentArray);
  293.                     if (is_numeric($comkey)) {
  294.                         $order array_search($cmsComponentArray[$comkey]['slug'], $fullSegmentOrder);
  295.                         $bundle str_replace('\\''', (string) $cmsComponentArray[$comkey]['bundle']).':'.$cmsComponentArray[$comkey]['slugEntity'];
  296.                         $structureEntities[$order] = $this->em->getRepository($bundle)->find($id);
  297.                     }
  298.                 }
  299.             }
  300.         }
  301.         $slugfixer implode('/'$pageSlugArray);
  302.         $slug $slugfixer;
  303.         ksort($structureEntities);
  304.         foreach ($structureEntities as $urlelement) {
  305.             $slug .= '/'.$urlelement->getSlug();
  306.         }
  307.         $pageData $this->routeMatcherV2($requestltrim($slug'/'));
  308.         $pageData['page'] = $pageEntity;
  309.         if (is_array($pageData)) {
  310.             $pageAllowed $this->pageChecks($pageData['page']);
  311.             if (false == $pageAllowed) {
  312.                 throw $this->createNotFoundException('Page view checks for PageID# "'.$pageData['page']->getId().'" has failed (disabled, before viewdate ect...) - so showing 404');
  313.             }
  314.             // HTML Blocks
  315.             $htmlblocks = [];
  316.             $assignedHtmlblocks $pageData['page']->getHtmlblocks();
  317.             if ((is_countable($assignedHtmlblocks) ? count($assignedHtmlblocks) : 0) > 0) {
  318.                 $allHtmlBlocks $this->em->getRepository(HtmlBlocks::class)->findBy(['deleted' => false]);
  319.                 foreach ($assignedHtmlblocks as $assignedblock) {
  320.                     foreach ($allHtmlBlocks as $allHtmlBlock) {
  321.                         if ($assignedblock['blockId'] == $allHtmlBlock->getId()) {
  322.                             $htmlblocks[] = [
  323.                                 'blockId' => $allHtmlBlock->getId(),
  324.                                 'position' => $assignedblock['position'],
  325.                                 'data' => $allHtmlBlock->getHtml(),
  326.                             ];
  327.                         }
  328.                     }
  329.                 }
  330.             }
  331.             $pageMeta $pageData['page'];
  332.             // replace metatitle if empty
  333.             if ('' == $pageData['page']->getMetatitle()) {
  334.                 $pageMeta->setMetatitle($pageData['page']->getTitle());
  335.             }
  336.             // replace metatitles if exist on components
  337.             foreach ($pageData['pageComponents'] as $pageComp) {
  338.                 $pageMeta $this->generateAndModifyMetaDataTags($pageData['page'], $pageComp['entity']);
  339.             }
  340.             return $this->render('@theme/templates/'.$pageData['page']->getTemplate()->getTemplateFile(), [
  341.                 'page' => $pageMeta,
  342.                 'slug' => $pageData['slug'],
  343.                 'pageComponents' => $pageData['pageComponents'],
  344.                 'pageHtmlBlocks' => $htmlblocks,
  345.                 'longUrl' => strtolower(implode('/'$params)),
  346.                 'preview' => true,
  347.             ]);
  348.         }   // this will be a redirect
  349.         return $pageData;
  350.         return new Response('EOF');
  351.     }
  352.     public function routeMatcherV2($request$slug)
  353.     {
  354.         $multilingual $this->getParameter('multilingual');
  355.         $locale $request->getLocale();
  356.         $cmsComponentArray $this->serviceController->fetchCmsComponents();
  357.         $pageComponents = [];
  358.         $debug = (bool) $request->query->has('_debug');
  359.         $this->debug($debug'<p>ROUTER DEBUG<br/>This will show you feedback during the route match process</p>');
  360.         $this->debug($debug'<br/>Current Locale ['.$request->getLocale().']');
  361.         $this->debug($debug'<br/>Looking for: <strong>'.$slug.'</strong>');
  362.         // ////////////////////////
  363.         // SIMPLE MATCHES
  364.         // ////////////////////////
  365.         // simple direct match
  366.         // this will match the home page in any locale and any default 'en' page
  367.         $page $this->em->getRepository(Page::class)->findOneBy(['slug' => $slug'deleted' => false'active' => true]);
  368.         if (null !== $page) {
  369.             $pageComponents $this->getComponentData($debug$cmsComponentArray$page->getComponents(), $request$page->getId());
  370.             $this->debug($debug"<br/><span style='color:green' >(STEP1) Found - ".$page->getTitle().' (ID#'.$page->getId().')<br/>Will render page out of debug mode</span>');
  371.             return [
  372.                 'page' => $page,
  373.                 'slug' => $slug,
  374.                 'pageComponents' => $pageComponents,
  375.             ];
  376.         }
  377.         // simple direct match for SELECTED TRANSLATION
  378.         // this route will match translations - locales matched after query
  379.         $pageAll $this->em->getRepository(Page::class)->findAll();
  380.         foreach ($pageAll as $page) {
  381.             if ($page->getSlug() == $slug) {
  382.                 if (false == $request->query->has('preview') && ($page->isDeleted() || !$page->isActive())) {
  383.                     throw $this->createNotFoundException('Page Route for "'.$slug.'" has been deactived or deleted');
  384.                 }
  385.                 $pageComponents $this->getComponentData($debug$cmsComponentArray$page->getComponents(), $request$page->getId());
  386.                 $this->debug($debug"<br/><span style='color:green' >(STEP2- transaltion) Found - ".$page->getTitle().' (ID#'.$page->getId().')<br/>Will render page out of debug mode</span>');
  387.                 return [
  388.                     'page' => $page,
  389.                     'slug' => $slug,
  390.                     'pageComponents' => $pageComponents,
  391.                 ];
  392.             }
  393.         }
  394.         $this->debug($debug'<p>No direct matches found - looking for complex matches  (has a url component was used?)<br/>Checking All Pages:</p>');
  395.         // if no direct matches found  ( usually means a url component was used )
  396.         // ////////////////////////
  397.         // COMPLEX MATCHES
  398.         // ////////////////////////
  399.         $urlSegments explode('/', (string) $slug);
  400.         // ///////////////////////////////////////
  401.         // this is for debug reasons only ( logic repeated after this loop )
  402.         if ($debug) {
  403.             $this->debug($debug'<pre>');
  404.             $this->debug($debug'<p><strong>COMPLEX ROUTE MATCHING</strong></p>');
  405.             foreach ($pageAll as $page) {
  406.                 $pageSlugParametersArray $this->findPageSlugParameters($page->getSlug());
  407.                 $possiblePageSegments explode('/'$page->getSlug());
  408.                 $slugMatches array_intersect($urlSegments$possiblePageSegments);
  409.                 $count 0;
  410.                 $this->debug($debug'Looking for: <strong>'.$slug.'</strong><br/>');
  411.                 $this->debug($debug'Looking at : <strong>'.$page->getSlug().'</strong> - ID#'.$page->getId().'<br/>');
  412.                 if (count($possiblePageSegments) === count($urlSegments)) {
  413.                     $this->debug($debug"<span style='color:green; font-weight:bold' >Passed phase 1</span>");
  414.                     ++$count;
  415.                 }
  416.                 $this->debug($debug' - '.count($possiblePageSegments).'/'.count($urlSegments).' URL Segment Count');
  417.                 if ((is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0) > 0) {
  418.                     ++$count;
  419.                     $this->debug($debug"<br/><span style='color:green; font-weight:bold' >Passed phase 2</span> - ".(is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0).' URL Parameter Components');
  420.                 } else {
  421.                     $this->debug($debug'<br/>No URL components on this page');
  422.                 }
  423.                 if (count($slugMatches) > 0) {
  424.                     ++$count;
  425.                     $this->debug($debug"<br/><span style='color:green; font-weight:bold' >Passed phase 3</span> - ".count($slugMatches).' URL slug matches');
  426.                 } else {
  427.                     $this->debug($debug'<br/>No URL slug matches on this page');
  428.                 }
  429.                 if ((is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0) + count($slugMatches) == count($urlSegments)) {
  430.                     ++$count;
  431.                     $this->debug($debug"<br/><span style='color:green; font-weight:bold' >Passed phase 4</span> - slugParameters + slugMatches = urlSegments");
  432.                 } else {
  433.                     $this->debug($debug'<br/>slugParameters + slugMatches dont add up to '.count($urlSegments));
  434.                 }
  435.                 if (== $count) {
  436.                     $this->debug($debug"<br/><span style='color:green; font-weight:bold' >SUCCESS!! - full match</span>");
  437.                     $confirmedDebugPage $page;
  438.                     $this->debug($debug"<br/><span style='color:green' >(STEP3- complex) Found - ".$confirmedDebugPage->getTitle().' (ID#'.$confirmedDebugPage->getId().')<br/>Will render page out of debug mode</span>');
  439.                 } else {
  440.                     $this->debug($debug'<br/>Not this page');
  441.                 }
  442.                 $this->debug($debug'<p>-----------------------------------</p>');
  443.             }// end of pages loop
  444.             if (!$confirmedDebugPage) {
  445.                 $this->debug($debug'<br/>Doh! - Route Not Matched ');
  446.             }
  447.             $this->debug($debug'</pre>');
  448.         }// end of debug
  449.         // /////////////////////////////////////
  450.         foreach ($pageAll as $page) {
  451.             $pageSlugParametersArray $this->findPageSlugParameters($page->getSlug());
  452.             $possiblePageSegments explode('/'$page->getSlug());
  453.             $slugMatches array_intersect($urlSegments$possiblePageSegments);
  454.             $count 0;
  455.             if (count($possiblePageSegments) === count($urlSegments)) {
  456.                 ++$count;
  457.             }
  458.             if ((is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0) > 0) {
  459.                 ++$count;
  460.             }
  461.             if (count($slugMatches) > 0) {
  462.                 ++$count;
  463.             }
  464.             if ((is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0) + count($slugMatches) == count($urlSegments)) {
  465.                 ++$count;
  466.             }
  467.             // Passed all 4 checks
  468.             if (== $count) {
  469.                 $confirmedPage $page;
  470.             }
  471.         }// end of pages loop
  472.         if (isset($confirmedPage)) {
  473.             $this->debug($debug'<p>Calling renderPageWithURLComponents</p>');
  474.             return $this->renderPageWithURLComponents($request$confirmedPage$slug$cmsComponentArray);
  475.         }
  476.         $this->debug($debug'<p><strong>STILL NO MATCH</strong> - START CHECKING TRANSLATIONS - with seperate indervidual url segments</p>');
  477.         // exit;
  478.         // //////////////////////////
  479.         // Lacale auto switcher
  480.         // //////////////////////////
  481.         // if page still not found check translations then change locale to match
  482.         // Note: for the switcher to work you have to refresh the page
  483.         if ($multilingual) {
  484.             $repository $this->em->getRepository(\Gedmo\Translatable\Entity\Translation::class);
  485.             foreach ($pageAll as $page) {
  486.                 $translations $repository->findTranslations($page);
  487.                 foreach ($translations as $locale => $fields) {
  488.                     foreach ($urlSegments as $segment) {
  489.                         $transSlug explode('/', (string) $fields['slug']);
  490.                         foreach ($transSlug as $transSlugSegment) {
  491.                             $this->debug($debug'<br/>['.$locale.']'.$segment.':'.$transSlugSegment);
  492.                             if ($segment === $transSlugSegment) {
  493.                                 $this->debug($debug' <strong> - Match ***</strong>');
  494.                                 $diffrentLanguagesWithSameSlug[$locale] = 0;
  495.                                 $setLocale $locale;
  496.                                 // wasnt sure which was the correct method - keeps changing!
  497.                                 $request->getSession()->set('_locale'$setLocale);
  498.                                 $request->setLocale($setLocale);
  499.                                 if ($debug) {
  500.                                     $this->debug($debug'<p><strong>*** REFRESHING PAGE IN ['.$setLocale.'] - autoswitching ***</strong></p>');
  501.                                 } elseif ($request->query->has('_locale')) {
  502.                                     $this->debug($debug'<br/>Already Redirected - preventing loop');
  503.                                 } else {
  504.                                     return $this->redirect('/'.$slug.'?_locale='.$setLocale);
  505.                                 }
  506.                             }
  507.                         }
  508.                     }
  509.                 }
  510.             }
  511.             // check if en from different locale
  512.             foreach ($pageAll as $page) {
  513.                 $page->setTranslatableLocale('en');
  514.                 $this->em->refresh($page);
  515.                 foreach ($urlSegments as $segment) {
  516.                     $locale 'en';
  517.                     $transSlug explode('/'$page->getSlug());
  518.                     foreach ($transSlug as $transSlugSegment) {
  519.                         $this->debug($debug'<br/>['.$locale.']'.$segment.':'.$transSlugSegment);
  520.                         if ($segment === $transSlugSegment) {
  521.                             $this->debug($debug' <strong> - Match ***</strong>');
  522.                             $diffrentLanguagesWithSameSlug[$locale] = 0;
  523.                             $setLocale $locale;
  524.                             // wasnt sure which was the correct method - keeps changing!
  525.                             $request->getSession()->set('_locale'$setLocale);
  526.                             $request->setLocale($setLocale);
  527.                             if ($debug) {
  528.                                 $this->debug($debug'<p><strong>*** REFRESHING PAGE IN ['.$setLocale.'] - autoswitching ***</strong></p>');
  529.                             } elseif ($request->query->has('_locale')) {
  530.                                 $this->debug($debug'<br/>Already Redirected - preventing loop');
  531.                             } else {
  532.                                 return $this->redirect('/'.$slug.'?_locale='.$setLocale);
  533.                             }
  534.                         }
  535.                     }
  536.                 }
  537.             }
  538.         } // end if($multilingual)
  539.         // return new Response('<p>End - showing 404 page</p>');
  540.         throw $this->createNotFoundException('Route not matched: showing 404 page');
  541.     }
  542.     public function renderPageWithURLComponents($request$confirmedPage$slug$cmsComponentArray)
  543.     {
  544.         $debug = (bool) $request->query->has('_debug');
  545.         $this->debug($debug'<br/>looking for components:<br/>');
  546.         $pageSlugParametersArray $this->findPageSlugParameters($confirmedPage->getSlug());
  547.         if ($debug) {
  548.             $this->debug($debug'Current URL components to match<br/>');
  549.             print_r($pageSlugParametersArray);
  550.             $this->debug($debug'<p>If more than one URL component then the last one will be checked by default ('.(is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0).' Found)</p>');
  551.         }
  552.         // extra check
  553.         $slugPieces explode('/', (string) $slug);
  554.         $confirmedPagePieces explode('/', (string) $confirmedPage->getSlug());
  555.         foreach ($cmsComponentArray as $cmsComponent) {
  556.             if ('' != $cmsComponent['slug']) {
  557.                 $slugCheck str_replace(' ''', (string) $cmsComponent['slug']);
  558.                 $this->debug($debug'<br/>Lookin at: '.$slugCheck);
  559.                 if ($slugCheck == '{'.end($pageSlugParametersArray).'}') {
  560.                     if ($debug) {
  561.                         $this->debug($debug' - Matched<br/>');
  562.                         print_r($cmsComponent);
  563.                     }
  564.                     $slugKey array_search('{'.end($pageSlugParametersArray).'}'$confirmedPagePieces);
  565.                     if (!is_numeric($slugKey)) {
  566.                         $this->debug($debug'<p>Oh No! -Key not found for "{'.end($pageSlugParametersArray).'}" in '.$confirmedPage->getSlug().'</p>');
  567.                     } else {
  568.                         $this->debug($debug"<p>Using the slug '".$slugPieces[$slugKey]."' on ".stripslashes((string) $cmsComponent['bundle']).':'.$cmsComponent['slugEntity'].' </p>');
  569.                     }
  570.                     $component_find_slug $slugPieces[$slugKey];
  571.                     $pageComponents $this->getComponentData($debug$cmsComponentArray$confirmedPage->getComponents(), $request$confirmedPage->getId(), $component_find_slug$slugPieces$pageSlugParametersArray);
  572.                     return [
  573.                         'page' => $confirmedPage,
  574.                         'slug' => $slug,
  575.                         'pageComponents' => $pageComponents,
  576.                     ];
  577.                 }
  578.             }
  579.         }
  580.     }
  581.     public function getComponentData($debug$cmsComponentArray$pageComponents$request$confirmedPageId$component_find_slug null$slugPieces = [], $pageSlugParametersArray = [])
  582.     {
  583.         if ($debug) {
  584.             $this->debug($debug'<pre>');
  585.             $this->debug($debug'<strong>AVAILABLE COMPONENTS:</strong><br/>');
  586.             $this->debug($debug"<table cellpadding='10' width='100%'>");
  587.             $this->debug($debug"<tr style='border-bottom:1px solid #666; font-size:12px'><th>Name</th><th>Slug</th><th>SlugEntity</th><th>Route</th><th>Type</th><th>Bundle</th><tr>");
  588.             foreach ($cmsComponentArray as $com) {
  589.                 $this->debug($debug"<tr style='border-top:1px dashed #666; font-size:12px'>");
  590.                 $this->debug($debug"<td style='white-space:nowrap; padding-top:5px; padding-bottom:5px'>".$com['name'].'</td>');
  591.                 $this->debug($debug"<td style='white-space:nowrap'>".$com['slug'].'</td>');
  592.                 $this->debug($debug"<td style='white-space:nowrap'>".$com['slugEntity'].'</td>');
  593.                 $this->debug($debug"<td style='white-space:nowrap'>".$com['route'].'</td>');
  594.                 $this->debug($debug"<td style='white-space:nowrap'>".$com['componentType'].'</td>');
  595.                 $this->debug($debug"<td style='white-space:nowrap'>".$com['bundle'].'</td>');
  596.                 $this->debug($debug'<tr>');
  597.             }
  598.             $this->debug($debug'</table>');
  599.             $this->debug($debug'</pre>');
  600.             $this->debug($debug'<pre>');
  601.             $this->debug($debug'<strong>ACTIVE PAGE COMPONENTS:</strong><br/>');
  602.             $this->debug($debug"<table cellpadding='10' width='100%'>");
  603.             $this->debug($debug"<tr style='border-bottom:1px solid #666; font-size:12px'><th>Position</th><th>Route</th><tr>");
  604.             foreach ($pageComponents as $com) {
  605.                 $this->debug($debug"<tr style='border-top:1px dashed #666;  font-size:12px'>");
  606.                 $this->debug($debug"<td style='white-space:nowrap; padding-top:5px; padding-bottom:5px'>".$com['position'].'</td>');
  607.                 $this->debug($debug"<td style='white-space:nowrap'>".$com['route'].'</td>');
  608.             }
  609.             $this->debug($debug'</table>');
  610.             $this->debug($debug'</pre>');
  611.         }
  612.         $pageComponentsReturn = [];
  613.         // Find out which URL segments are dynamic by removing
  614.         // preceeding segments (parent and page)
  615.         $totalSlug is_countable($slugPieces) ? count($slugPieces) : 0;
  616.         $totalPara is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0;
  617.         $diff $totalSlug $totalPara;
  618.         for ($i 0$i $diff; ++$i) {
  619.             unset($slugPieces[$i]);
  620.         }
  621.         $slugPieces array_values($slugPieces);
  622.         $this->debug($debug'<pre>');
  623.         $this->debug($debug'<p><strong>COMPONENT LINKING</strong></p>');
  624.         // Workout extra segments - these will have no route
  625.         // and componentType = 'segment'
  626.         $extraUrlSegments $pageSlugParametersArray;
  627.         if ((is_countable($pageSlugParametersArray) ? count($pageSlugParametersArray) : 0) > 1) {
  628.             unset($extraUrlSegments[(is_countable($extraUrlSegments) ? count($extraUrlSegments) : 0) - 1], $slugPieces[count($slugPieces) - 1]);
  629.             $extraUrlSegments array_values($extraUrlSegments);
  630.             $slugPieces array_values($slugPieces);
  631.             $this->debug($debug'<p>SEGMENT ONLY ('.count($extraUrlSegments).' found)</p>');
  632.             // $this->debug($debug, "<br/>The next 2 array keys and values should match up");
  633.             // $this->debug($debug, "<br/>".print_r($extraUrlSegments, true));
  634.             // $this->debug($debug, "<br/>".print_r($slugPieces, true));
  635.             foreach ($extraUrlSegments as $index => $segment) {
  636.                 $comkey $this->searchArrayKeyVal('slug''{'.$segment.'}'$cmsComponentArray);
  637.                 if (is_numeric($comkey)) {
  638.                     $entity $this->getEntityData(['component' => $cmsComponentArray[$comkey], 'slug' => $slugPieces[$index]], $request$debug);
  639.                     $entityId $entity->getId();
  640.                     if ($entityId) {
  641.                         $pageComponentsReturn[] = [
  642.                             'position' => null,
  643.                             'urlKey' => $cmsComponentArray[$comkey]['slugEntity'],
  644.                             'urlValue' => $entityId,
  645.                             'data' => null,
  646.                             'entity' => $entity,
  647.                         ];
  648.                     }
  649.                 } else {
  650.                     $this->debug($debug"<p>Dynamic Slug '".$slugPieces[$index]."' for URL Annotation '".$segment."' NOT FOUND - but can continue, you should check your routes/link</p>");
  651.                 }
  652.             }
  653.         }
  654.         // Check all page components
  655.         $comCount 0;
  656.         foreach ($pageComponents as $pageComponent) {
  657.             if (null != $pageComponent['route']) {
  658.                 ++$comCount;
  659.                 $this->debug($debug'<p>------------------------------</p>');
  660.                 $this->debug($debug'<p>COMPONENT '.$comCount.'</p>');
  661.                 // found pagecomponent
  662.                 $comkey $this->searchArrayKeyVal('route'$pageComponent['route'], $cmsComponentArray);
  663.                 if (!is_numeric($comkey)) {
  664.                     $this->debug($debug'<p>The component <strong>'.$pageComponent['route'].'</strong> not found - has it been deleted?</p>');
  665.                     $pageComponentsReturn[] = [
  666.                         'position' => $pageComponent['position'],
  667.                         'urlKey' => null,
  668.                         'urlValue' => null,
  669.                         'data' => '',
  670.                         'entity' => null,
  671.                     ];
  672.                 } else {
  673.                     $this->debug($debug'<p>Comkey (#'.$comkey.') found for = '.$pageComponent['route']);
  674.                     $action $this->routeToControllerName($cmsComponentArray[$comkey]['route']);
  675.                     $this->debug($debug'<br/>Controller = '.$cmsComponentArray[$comkey]['route'].'</p>');
  676.                     // Non-URL reliant (slugless) component
  677.                     if (null == $cmsComponentArray[$comkey]['slug']) {
  678.                         $this->debug($debug'<p>SLUGLESS:<br/>RENDERING CONTROLLER into  = <strong>'.$action['_controller'].'</strong></p>');
  679.                         // fetch component data
  680.                         $response $this->forward($action['_controller'], ['request' => $request'pageId' => $confirmedPageId]);
  681.                         $pageComponentsReturn[] = [
  682.                             'position' => $pageComponent['position'],
  683.                             'urlKey' => null,
  684.                             'urlValue' => null,
  685.                             'data' => $response->getContent(),
  686.                             'entity' => null,
  687.                         ];
  688.                     } else {
  689.                         // URL Component found
  690.                         $removal = ['{''}']; // used for str_replace
  691.                         $controllerSlug str_replace($removal'', (string) $cmsComponentArray[$comkey]['slug']);
  692.                         // Get entityID for getMethodRouterAction - used to assist with locale/translation switching
  693.                         $entity $this->getEntityData(['component' => $cmsComponentArray[$comkey], 'slug' => $component_find_slug], $request$debug);
  694.                         // dd(['component' => $cmsComponentArray[$comkey], 'slug' => $component_find_slug], $request, $debug);
  695.                         $entityId $entity->getId();
  696.                         // fetch component data
  697.                         $this->debug($debug'<p>SLUG REQUIRED:<br/>RENDERING CONTROLLER = <strong>'.$action['_controller'].'</strong></p>');
  698.                         $response $this->forward($action['_controller'], ['request' => $request'pageId' => $confirmedPageId$controllerSlug => $component_find_slug]);
  699.                         $pageComponentsReturn[] = [
  700.                             'position' => $pageComponent['position'],
  701.                             'urlKey' => $cmsComponentArray[$comkey]['slugEntity'],
  702.                             'urlValue' => $entityId,
  703.                             'data' => $response->getContent(),
  704.                             'entity' => $entity,
  705.                         ];
  706.                     }
  707.                 } // end if(!is_numeric($comkey)
  708.             }
  709.         }
  710.         $this->debug($debug'</pre>');
  711.         return $pageComponentsReturn;
  712.     }
  713.     public function getEntityData($data$request$debug)
  714.     {
  715.         $locale $request->getLocale();
  716.         // $queryEntity = str_replace('\\', '', $data['component']['bundle'].':'.$data['component']['slugEntity']);
  717.         // $queryEntity = str_replace('/', '', $queryEntity);
  718.         $queryEntity '\\'.$data['component']['bundle'].'\Entity\\'.$data['component']['slugEntity'];
  719.         $this->debug($debug'<p>ENTITY QUERY - '.$queryEntity);
  720.         if ('en' != $locale) {
  721.             $entity $this->em->getRepository($queryEntity)->findSlugWithLocale($data['slug'], $locale);
  722.             $this->debug($debug'->findSlugWithLocale(<strong>'.$data['slug'].'</strong>, <strong>'.$locale.'</strong>)');
  723.         } else {
  724.             $entity $this->em->getRepository($queryEntity)->findOneBySlug($data['slug']);
  725.             $this->debug($debug'->findOneBySlug(<strong>'.$data['slug'].'</strong>)');
  726.         }
  727.         if ($entity) {
  728.             $this->debug($debug'<br/>RESULT: EntityId =<strong>'.$entity->getId().'</strong></p>');
  729.             return $entity;
  730.         }
  731.         return false;
  732.     }
  733.     public function searchArrayKeyVal($sKey$id$array)
  734.     {
  735.         foreach ($array as $key => $val) {
  736.             if ($val[$sKey] == $id) {
  737.                 return $key;
  738.             }
  739.         }
  740.         foreach ($array as $key => $val) {
  741.             if (strtolower((string) $val[$sKey]) === strtolower((string) $id)) {
  742.                 return $key;
  743.             }
  744.         }
  745.         return false;
  746.     }
  747.     public function isJson($string)
  748.     {
  749.         try {
  750.             json_decode((string) $stringfalse512JSON_THROW_ON_ERROR);
  751.             return true;
  752.         } catch (\JsonException) {
  753.             return false;
  754.         }
  755.     }
  756.     // function to compare entities and returns common setters
  757.     public function getSetters($entity$entity2)
  758.     {
  759.         $classMethods get_class_methods($entity);
  760.         $classMethods2 get_class_methods($entity2);
  761.         $settersArray = [];
  762.         foreach ($classMethods as $classMethod) {
  763.             if (str_starts_with($classMethod'set')) {
  764.                 foreach ($classMethods2 as $classMethod2) {
  765.                     if (str_starts_with($classMethod2'set') && $classMethod == $classMethod2) {
  766.                         $settersArray[] = $classMethod2;
  767.                     }
  768.                 }
  769.             }
  770.         }
  771.         return $settersArray;
  772.     }
  773.     #[Route('/sitemap.xml'name'sitemap'methods: ['GET'])]
  774.     public function sitemap(): Response
  775.     {
  776.         $xml $this->cache->get('sitemap'SimpleCache::ONE_DAY);
  777.         if (!$xml) {
  778.             $xml $this->sitemapService->generateSitemap();
  779.             $this->cache->set('sitemap'$xml);
  780.         }
  781.         $response = new Response($xml);
  782.         $response->headers->set('Content-Type''application/xml');
  783.         // Browser Cache for 24 hours
  784.         $response->setMaxAge(86400);
  785.         $response->setSharedMaxAge(86400);
  786.         return $response;
  787.     }
  788.     // THIS ROUTE MUST BE THE VERY LAST ROUTE LOADED
  789.     #[Route(path'/'name'home'defaults: ['slug' => 'home'])]
  790.     #[Route(path'/{slug}'name'router'requirements: ['slug' => '.+'], priority: -10)]
  791.     public function router(SimpleCache $cacheRequest $requestmixed $slug)
  792.     {
  793.         $session $request->getSession();
  794.         $slugCache $this->em->getRepository(Page::class)->findByLocale($request->getLocale());
  795.         $cache->set('slugCache'$slugCache);
  796.         $debug $request->query->has('_debug');
  797.         $this->debug($debug'Current Locale -'.$request->getLocale().' | request Locale -'.$request->query->get('_locale'));
  798.         if ($request->query->has('_locale')) {
  799.             $this->debug($debug'<p>CHANGING LOCALE</p>');
  800.             if ($request->getLocale() != $request->query->get('_locale')) {
  801.                 $session->set('_locale'$request->query->get('_locale'));
  802.                 $request->setLocale($session->get('_locale'$request->query->get('_locale')));
  803.                 return $this->redirect('/'.$slug);
  804.             }
  805.         }
  806.         $pageData $this->routeMatcherV2($request$slug);
  807.         // REDIRECT CHECKER
  808.         $this->debug($debug'Checking for redirects...');
  809.         foreach ($pageData['pageComponents'] as $pageComponent) {
  810.             $redirectCheck $pageComponent['data'];
  811.             if ($this->isJson($redirectCheck)) {
  812.                 $decoded json_decode((string) $redirectCheckfalse512JSON_THROW_ON_ERROR);
  813.                 if (property_exists($decoded'componentRedirect') && null !== $decoded->componentRedirect) {
  814.                     $this->debug($debug'Redirect found ... will goto '.$decoded->componentRedirect);
  815.                     if (!$debug) {
  816.                         return $this->redirect($decoded->componentRedirect);
  817.                     }
  818.                 }
  819.             }
  820.         }
  821.         if (is_array($pageData)) {
  822.             $longUrl 'page.php?Page='.$pageData['page']->getId();
  823.             if (array_key_exists('pageComponents'$pageData) && null != $pageData['pageComponents']) {
  824.                 foreach ($pageData['pageComponents'] as $component) {
  825.                     if (array_key_exists('urlKey'$component) && null != $component['urlKey']) {
  826.                         $longUrl .= '&'.$component['urlKey'].'='.$component['urlValue'];
  827.                     }
  828.                 }
  829.             }
  830.             $pageAllowed $this->pageChecks($pageData['page']);
  831.             if (false == $pageAllowed) {
  832.                 throw $this->createNotFoundException('Page Checks for pageId "'.$pageData['page']->getId().'" has failed (disabled, before viewdate ect...) - showing 404');
  833.             }
  834.             // HTML Blocks
  835.             $htmlblocks = [];
  836.             $assignedHtmlblocks $pageData['page']->getHtmlblocks();
  837.             if ((is_countable($assignedHtmlblocks) ? count($assignedHtmlblocks) : 0) > 0) {
  838.                 $allHtmlBlocks $this->em->getRepository(HtmlBlocks::class)->findBy(['deleted' => false]);
  839.                 foreach ($assignedHtmlblocks as $assignedblock) {
  840.                     foreach ($allHtmlBlocks as $allHtmlBlock) {
  841.                         if ($assignedblock['blockId'] == $allHtmlBlock->getId()) {
  842.                             $htmlblocks[] = [
  843.                                 'blockId' => $allHtmlBlock->getId(),
  844.                                 'position' => $assignedblock['position'],
  845.                                 'data' => $allHtmlBlock->getHtml(),
  846.                             ];
  847.                         }
  848.                     }
  849.                 }
  850.             }
  851.             $pageMeta $pageData['page'];
  852.             // replace metatitle if empty
  853.             if ('' == $pageData['page']->getMetatitle()) {
  854.                 $pageMeta->setMetatitle($pageData['page']->getTitle());
  855.             }
  856.             // replace metatitles if exist on components
  857.             foreach ($pageData['pageComponents'] as $pageComp) {
  858.                 $pageMeta $this->generateAndModifyMetaDataTags($pageData['page'], $pageComp['entity']);
  859.             }
  860.             return $this->render('@theme/templates/'.$pageData['page']->getTemplate()->getTemplateFile(), [
  861.                 'page' => $pageMeta,
  862.                 'slug' => $pageData['slug'],
  863.                 'pageComponents' => $pageData['pageComponents'],
  864.                 'pageHtmlBlocks' => $htmlblocks,
  865.                 'longUrl' => strtolower($longUrl),
  866.             ]);
  867.         }   // this will be a redirect
  868.         return $pageData;
  869.     }
  870.     private function debug(bool $debug$message): void
  871.     {
  872.         if ($debug) {
  873.             echo $message;
  874.         }
  875.     }
  876.     #[Route(path'/open-ai'name'members_dash')]
  877.     public function testAi(OpenAiService $ai): void
  878.     {
  879.         $ai->test('Please write me a blog post about the future of AI in web development');
  880.     }
  881. }