src/Controller/PageDefaultController.php line 701

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 (0 == $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 $cache, Request $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($request, ltrim($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 $cache, Request $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($request, ltrim($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 (4 == $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 (4 == $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) $string, false, 512, JSON_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 $cache, Request $request, mixed $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) $redirectCheck, false, 512, JSON_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. }