src/Controller/PageDefaultController.php line 918

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