src/Controller/SearchController.php line 21

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Annotation\CmsComponent;
  4. use App\Entity\Page;
  5. use App\Service\ServiceController;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use Knp\Component\Pager\PaginatorInterface;
  8. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\Response;
  11. use Symfony\Component\Routing\Annotation\Route;
  12. class SearchController extends AbstractController
  13. {
  14. /**
  15. * @CmsComponent("Search Results", active=true, routeName="process_search")
  16. */
  17. #[Route(path: '/pcgc-search', name: 'process_search')]
  18. public function processSearch(Request $request, EntityManagerInterface $em, ServiceController $serviceController, PaginatorInterface $paginator)
  19. {
  20. $resultsPerPage = 20;
  21. $titleFields = array_reverse(['title', 'subtitle', 'headline', 'name']);
  22. $descriptionFields = array_reverse(['content', 'content2', 'content3', 'description', 'information', 'taggedin']);
  23. $searchableFields = array_merge($titleFields, $descriptionFields);
  24. $criteria = $request->get('criteria');
  25. $string = $request->get('criteria');
  26. $totalResults = 0;
  27. if ($criteria) {
  28. $criteriaArray = explode(' ', (string) $criteria);
  29. // print_r($criteriaArray);
  30. foreach ($criteriaArray as $key => $criteriaCheck) {
  31. if (strlen($criteriaCheck) < 3) {
  32. unset($criteriaArray[$key]);
  33. }
  34. if ('' == $criteriaCheck) {
  35. unset($criteriaArray[$key]);
  36. }
  37. }
  38. $cmsComponentArray = $serviceController->fetchCmsComponents();
  39. $pages = $em->getRepository(Page::class)->findBy(['deleted' => false, 'active' => true]);
  40. // get only active pages with componets - to prevent fetching routes without any possible links
  41. // 2 arrays - one for quick searching(activePageRoutes) and sluggedPages for full details - just ensure they have both have the same key
  42. $activePageRoutes = [];
  43. $sluggedPages = [];
  44. foreach ($pages as $page) {
  45. $pageComps = $page->getComponents();
  46. foreach ($pageComps as $pageComp) {
  47. if ('' != $pageComp['route']) {
  48. $sluggedPages[] = $page;
  49. $activePageRoutes[] = $pageComp['route'];
  50. }
  51. }
  52. }
  53. // echo "<pre>".print_r($activePageRoutes, true)."</pre>";
  54. // get only componets which have the 'slugEntity' annotation
  55. $activeRoutes = [];
  56. $sluggedComponents = [];
  57. foreach ($cmsComponentArray as $cmsComponent) {
  58. if ('' != $cmsComponent['slugEntity']) {
  59. $sluggedComponents[] = $cmsComponent;
  60. $activeRoutes[] = $cmsComponent['route'];
  61. }
  62. }
  63. // echo "<pre>".print_r($sluggedComponents, true)."</pre>";
  64. $hits = [];
  65. // loop through all criteria
  66. foreach ($criteriaArray as $criteria) {
  67. // search page content first - as its easier ;)
  68. foreach ($pages as $page) {
  69. // loop through all searchable fields
  70. foreach ($searchableFields as $searchableField) {
  71. $getter = 'get'.ucwords($searchableField);
  72. // check that the field exists
  73. // search content - convert to lowercase
  74. if (method_exists($page, $getter) && strstr(strtolower((string) $page->{$getter}()), strtolower($criteria))) {
  75. // we have a hit - added a field called hits - if a entity gets more than 1 hit
  76. // increase the hits, i'll use this to calculate weighting
  77. $key = 'page'.$page->getId();
  78. if (!array_key_exists($key, $hits)) {
  79. $hits[$key] = [
  80. 'hits' => 1,
  81. 'title' => $page->getTitle(),
  82. 'description' => $page->getContent(),
  83. 'link' => $page->getSlug(),
  84. 'image' => $page->getFullImagePath(),
  85. ];
  86. } else {
  87. // same entity hit - so increase hit count
  88. ++$hits[$key]['hits'];
  89. }
  90. ++$totalResults;
  91. }
  92. }
  93. }
  94. }
  95. foreach ($criteriaArray as $criteria) {
  96. // search other bundles
  97. // find entites to check - make sure they have a page to link to
  98. foreach ($sluggedComponents as $key => $sluggedComponent) {
  99. if (in_array($sluggedComponent['route'], $activePageRoutes)) {
  100. // its an active page so search it
  101. $checkComponent = $sluggedComponents[$key];
  102. // get page info - so i know where to link the result
  103. $pageKey = array_search($sluggedComponent['route'], $activePageRoutes);
  104. $pageEntity = $sluggedPages[$pageKey];
  105. // $queryEntity = str_replace('\\', '', $checkComponent['bundle'].':'.$checkComponent['slugEntity']);
  106. // $queryEntity = str_replace('/', '', $queryEntity);
  107. // dd($checkComponent);
  108. $queryEntity = '\\'.$checkComponent['bundle'].'\\Entity\\'.$checkComponent['slugEntity'];
  109. $entities = $em->getRepository($queryEntity)->findBy(['deleted' => 0, 'active' => 1]);
  110. foreach ($entities as $entity) {
  111. // loop through all searchable fields
  112. foreach ($searchableFields as $searchableField) {
  113. $getter = 'get'.ucwords($searchableField);
  114. // check that the field exists
  115. // search content - convert to lowercase
  116. if (method_exists($entity, $getter) && strstr(strtolower((string) $entity->{$getter}()), strtolower($criteria))) {
  117. // we have a hit - added a field called hits - if a entity gets more than 1 hit
  118. // increase the hits, i'll use this to calculate weighting
  119. // used key as a way to uniquly reference to increase hits
  120. $key = $checkComponent['slugEntity'].$entity->getId();
  121. if (!array_key_exists($key, $hits)) {
  122. // as all entities are different - we need to homogenise
  123. $title = '';
  124. $description = '';
  125. $link = '';
  126. $image = '';
  127. // get title field
  128. foreach ($titleFields as $titleField) {
  129. $getter = 'get'.ucwords($titleField);
  130. if (method_exists($entity, $getter)) {
  131. $newTitle = $entity->{$getter}();
  132. if (strlen($newTitle) > 0) {
  133. $title = $newTitle;
  134. }
  135. }
  136. }
  137. // get description field
  138. foreach ($descriptionFields as $descriptionField) {
  139. $getter = 'get'.ucwords($descriptionField);
  140. if (method_exists($entity, $getter)) {
  141. $newDescription = $entity->{$getter}();
  142. if (strlen($newDescription) > 0) {
  143. $description = $newDescription;
  144. }
  145. }
  146. }
  147. // use excerpt if exists
  148. if (method_exists($entity, 'getExcerpt')) {
  149. $description = $entity->getExcerpt();
  150. }
  151. // check if image exists
  152. if (method_exists($entity, 'getFullImagePath')) {
  153. $image = $entity->getFullImagePath();
  154. }
  155. // echo "<p>";
  156. // echo $checkComponent['slug']."<br/>";
  157. // echo $entity->getSlug()."<br/>";
  158. // echo $pageEntity->getSlug()."<br/>";
  159. // echo "</p>";
  160. // get link
  161. $link = str_replace(
  162. $checkComponent['slug'],
  163. $entity->getSlug(),
  164. $pageEntity->getSlug()
  165. );
  166. $hits[$key] = [
  167. 'hits' => 1,
  168. 'title' => $title,
  169. 'description' => $description,
  170. 'link' => $link,
  171. 'image' => $image,
  172. ];
  173. } else {
  174. // same entity hit - so increase hit count
  175. ++$hits[$key]['hits'];
  176. }
  177. ++$totalResults;
  178. }
  179. }
  180. }
  181. }
  182. }
  183. }
  184. // echo "<pre>".print_r($hits, true)."</pre>";
  185. $sortedHits = $this->subvalSort($hits, 'hits');
  186. // dump($sortedHits);
  187. $pageHits = $paginator->paginate(
  188. array_reverse($sortedHits),
  189. $request->query->getInt('page', 1),
  190. $resultsPerPage
  191. );
  192. return $this->render('@theme/common/search-results.html.twig', [
  193. 'pageHits' => $pageHits,
  194. 'criteriaArray' => $criteriaArray,
  195. 'criteria' => $string,
  196. 'totalResults' => count($sortedHits),
  197. ]);
  198. }
  199. return new Response('The search criteria is invalid');
  200. }
  201. public function subvalSort($a, $subkey)
  202. {
  203. $c = [];
  204. $b = [];
  205. foreach ($a as $k => $v) {
  206. $b[$k] = strtolower((string) $v[$subkey]);
  207. }
  208. if (isset($b) && is_array($b)) {
  209. asort($b);
  210. foreach (array_keys($b) as $key) {
  211. $c[] = $a[$key];
  212. }
  213. return $c;
  214. }
  215. return [];
  216. }
  217. }