src/Aqarmap/Bundle/SearchBundle/Controller/Api/SearchResultsController.php line 23

  1. <?php
  2. namespace Aqarmap\Bundle\SearchBundle\Controller\Api;
  3. use Aqarmap\Bundle\ListingBundle\Builder\BuilderInterface;
  4. use Aqarmap\Bundle\ListingBundle\Entity\Location;
  5. use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;
  6. use Aqarmap\Bundle\ListingBundle\Entity\Section;
  7. use Aqarmap\Bundle\ListingBundle\Repository\LocationRepository;
  8. use Aqarmap\Bundle\ListingBundle\Repository\PropertyTypeRepository;
  9. use Aqarmap\Bundle\ListingBundle\Repository\SectionRepository;
  10. use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
  11. use Aqarmap\Bundle\MainBundle\Constant\CustomParagraphPlaceTypes;
  12. use Aqarmap\Bundle\MainBundle\Controller\Api\BaseController;
  13. use Aqarmap\Bundle\MainBundle\Repository\CustomParagraphRepository;
  14. use Aqarmap\Bundle\MainBundle\Service\MenuBuilderService;
  15. use Aqarmap\Bundle\SearchBundle\Services\SEOListingSearchService;
  16. use FOS\RestBundle\Controller\Annotations as Rest;
  17. use Symfony\Bridge\Doctrine\Attribute\MapEntity;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\HttpKernel\Attribute\Cache;
  20. class SearchResultsController extends BaseController
  21. {
  22. #[Rest\Get('/api/v2/search/slug-resolver', name: 'aqarmap_api_search_slug_resolver', options: ['i18n' => false])]
  23. #[Rest\View(serializerGroups: ['SlugResolver'])]
  24. #[Rest\QueryParam(name: 'section', default: null, description: 'Section slug')]
  25. #[Rest\QueryParam(name: 'propertyType', default: null, description: 'Property Type slug')]
  26. #[Rest\QueryParam(name: 'locations', default: null, description: 'Locations slugs. As array.')]
  27. #[Cache(expires: '+7 days', maxage: '+7 days', smaxage: '+7 days', public: true, vary: ['Accept-Language', 'X-Accept-Version', 'Accept'])]
  28. public function resolveSearchPageSlugs(Request $request, SectionRepository $sectionRepo, PropertyTypeRepository $propertyTypeRepo, LocationRepository $locationRepo): array
  29. {
  30. $locationsSlugs = $request->query->all('locations');
  31. $data = [
  32. 'section' => $sectionRepo->findOneBy(['slug' => $request->query->get('section')]),
  33. 'propertyType' => $propertyTypeRepo->findOneBy(['slug' => $request->query->get('propertyType')]),
  34. 'locations' => [],
  35. ];
  36. if (!empty($locationsSlugs) && $this->validLocationSlugArray($locationsSlugs)) {
  37. $data['locations'] = $locationRepo->getLocationsBySlugs($locationsSlugs);
  38. }
  39. return $data;
  40. }
  41. /**
  42. * Legazy.
  43. */
  44. #[Rest\Get('/api/v2/search/properties-chips-legazy', options: ['i18n' => false], name: 'aqarmap_api_properties_chips_legazy')]
  45. #[Rest\View]
  46. #[Cache(expires: '+1 days', maxage: '+1 days', smaxage: '+1 days', public: true, vary: ['Accept-Language', 'X-Accept-Version', 'Accept'])]
  47. public function getPropertiesChipsLegazy(
  48. Request $request,
  49. #[MapEntity(id: 'location')]
  50. ?Location $location,
  51. #[MapEntity(id: 'propertyType')]
  52. ?PropertyType $propertyType,
  53. #[MapEntity(id: 'section')]
  54. ?Section $section,
  55. MenuBuilderService $menuBuilderService,
  56. ) {
  57. $locale = $request->getLocale();
  58. $data = [];
  59. if ($section && $propertyType) {
  60. $criteria = [
  61. 'location' => $location,
  62. 'propertyType' => $propertyType,
  63. 'section' => $section,
  64. 'locale' => $locale,
  65. ];
  66. $data = $menuBuilderService->getSearchResultPropertyChips($criteria);
  67. }
  68. return $data;
  69. }
  70. #[Rest\Get('/api/v2/search/properties-chips', options: ['i18n' => false], name: 'aqarmap_api_properties_chips')]
  71. #[Rest\View]
  72. #[Cache(expires: '+1 days', maxage: '+1 days', smaxage: '+1 days', public: true, vary: ['Accept-Language', 'X-Accept-Version', 'Accept'])]
  73. public function getPropertiesChips(Request $request, ListingManager $listingManager, PropertyTypeRepository $propertyTypeRepository)
  74. {
  75. $result = [];
  76. $types = $listingManager->getPropertiesChipsElasticResponse($request);
  77. $typesArray = [];
  78. foreach ($types as $id => $doc_count) {
  79. $typesArray[$id] = $doc_count;
  80. }
  81. arsort($typesArray);
  82. $propertyTypes = $propertyTypeRepository->findPropertyTypes(array_keys($typesArray));
  83. foreach ($propertyTypes as $propertyType) {
  84. $id = $propertyType->getId();
  85. $result[] = [
  86. 'id' => $id,
  87. 'title' => $propertyType->getTitle(),
  88. 'slug' => $propertyType->getSlug(),
  89. 'searchResultCount' => $typesArray[$id] ?? 0,
  90. 'level' => $propertyType->getLevel(),
  91. ];
  92. }
  93. return $result;
  94. }
  95. #[Rest\Get('/api/v2/search/{section}/{propertyType}/{location}/page-metadata', options: ['i18n' => false], name: 'aqarmap_api_search_page_metadata')]
  96. #[Rest\View(serializerGroups: ['Default'])]
  97. public function getSeoData(
  98. Section $section,
  99. PropertyType $propertyType,
  100. Location $location,
  101. CustomParagraphRepository $customParagraphRepository,
  102. SEOListingSearchService $seoListingSearchService,
  103. ) {
  104. $data['customParagraph'] = $customParagraphRepository->get([
  105. 'location' => $location->getId(),
  106. 'propertyType' => $propertyType->getId(),
  107. 'section' => $section->getId(),
  108. 'place' => CustomParagraphPlaceTypes::SEARCH_RESULTS,
  109. ])->getQuery()->setMaxResults(1)->getOneOrNullResult();
  110. $data['longTail'] = $seoListingSearchService->retrieveLongTail($location, $section, $propertyType);
  111. return [
  112. 'data' => $data,
  113. ];
  114. }
  115. #[Rest\Get('/api/v2/custom-paragraph', options: ['i18n' => false], name: 'aqarmap_api_custom_paragraph')]
  116. #[Rest\View(serializerGroups: ['Default'])]
  117. public function getCustomParagraph(
  118. Request $request,
  119. #[MapEntity(id: 'location')]
  120. ?Location $location,
  121. #[MapEntity(id: 'section')]
  122. ?Section $section,
  123. #[MapEntity(id: 'propertyType')]
  124. ?PropertyType $propertyType,
  125. CustomParagraphRepository $customParagraphRepository,
  126. ) {
  127. return $customParagraphRepository->get([
  128. 'location' => $location ? $location->getId() : null,
  129. 'propertyType' => $propertyType ? $propertyType->getId() : null,
  130. 'section' => $section->getId(),
  131. 'place' => $request->query->get('place') ?: CustomParagraphPlaceTypes::SEARCH_RESULTS,
  132. ])->getQuery()->setMaxResults(1)->getOneOrNullResult();
  133. }
  134. #[Rest\Get('/api/v2/location/{location}/listing', options: ['i18n' => false], name: 'aqarmap_api_location_listing_v2')]
  135. #[Rest\QueryParam(name: 'id', default: null, description: 'Location id')]
  136. #[Rest\View(serializerGroups: ['locationListingV2'])]
  137. public function getLocationListing(Location $location)
  138. {
  139. return $location;
  140. }
  141. private function validLocationSlugArray($array): bool
  142. {
  143. return \count($array) > 0 && array_reduce($array, fn ($carry, $item) => $carry && \is_string($item) && '' !== $item, true);
  144. }
  145. #[Rest\Get('/api/v4/search/ssr-data', name: 'aqarmap_search_results_ssr_data', options: ['i18n' => false, 'expose' => false])]
  146. #[Rest\QueryParam(name: 'section', default: null, description: 'Section slug')]
  147. #[Rest\QueryParam(name: 'propertyType', default: null, description: 'Property Type slug')]
  148. #[Rest\QueryParam(name: 'locations', default: null, description: 'Array of Locations slugs.')]
  149. #[Rest\View(serializerGroups: ['SlugResolver'])]
  150. public function singlePageSSRData(Request $request, SectionRepository $sectionRepository, PropertyTypeRepository $propertyTypeRepository, LocationRepository $locationRepository, BuilderInterface $searchDescriptionBuilder): array
  151. {
  152. $sectionSlug = $request->get('section');
  153. if (!$sectionSlug) {
  154. throw new \InvalidArgumentException('Section is required');
  155. }
  156. $section = $sectionRepository->findOneBy(['slug' => $sectionSlug]);
  157. $propertyTypeSlug = $request->get('propertyType');
  158. if (!$propertyTypeSlug) {
  159. throw new \InvalidArgumentException('propertyType is required');
  160. }
  161. $propertyType = $propertyTypeRepository->findOneBy(['slug' => $propertyTypeSlug]);
  162. $locationsSlugs = $request->query->all('locations');
  163. if (!$locationsSlugs) {
  164. throw new \InvalidArgumentException('locations is required');
  165. }
  166. $locations = $locationRepository->getLocationsBySlugs($locationsSlugs);
  167. // Page Description
  168. $searchDescriptionBuilder
  169. ->setSection($section)
  170. ->setPropertyType($propertyType)
  171. ->setLocation(reset($locations))
  172. ;
  173. return [
  174. 'section' => $section,
  175. 'propertyType' => $propertyType,
  176. 'locations' => $locations,
  177. 'pageTitle' => '',
  178. 'metaDescription' => $searchDescriptionBuilder->format()->get(),
  179. 'metaKeywords' => '',
  180. 'canonicalUrl' => '',
  181. 'breadcrumbs' => [
  182. [
  183. 'title' => '',
  184. 'url' => '',
  185. ],
  186. ],
  187. 'propertyTypesChips' => [
  188. [
  189. 'title' => '',
  190. 'url' => '',
  191. ],
  192. ],
  193. ];
  194. }
  195. }