src/Aqarmap/Bundle/SearchBundle/Controller/Api/SearchResultsController.php line 23
<?phpnamespace Aqarmap\Bundle\SearchBundle\Controller\Api;use Aqarmap\Bundle\ListingBundle\Builder\BuilderInterface;use Aqarmap\Bundle\ListingBundle\Entity\Location;use Aqarmap\Bundle\ListingBundle\Entity\PropertyType;use Aqarmap\Bundle\ListingBundle\Entity\Section;use Aqarmap\Bundle\ListingBundle\Repository\LocationRepository;use Aqarmap\Bundle\ListingBundle\Repository\PropertyTypeRepository;use Aqarmap\Bundle\ListingBundle\Repository\SectionRepository;use Aqarmap\Bundle\ListingBundle\Service\ListingManager;use Aqarmap\Bundle\MainBundle\Constant\CustomParagraphPlaceTypes;use Aqarmap\Bundle\MainBundle\Controller\Api\BaseController;use Aqarmap\Bundle\MainBundle\Repository\CustomParagraphRepository;use Aqarmap\Bundle\MainBundle\Service\MenuBuilderService;use Aqarmap\Bundle\SearchBundle\Services\SEOListingSearchService;use FOS\RestBundle\Controller\Annotations as Rest;use OpenApi\Attributes as OA;use Symfony\Bridge\Doctrine\Attribute\MapEntity;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpKernel\Attribute\Cache;class SearchResultsController extends BaseController{#[Rest\Get('/api/v2/search/slug-resolver', name: 'aqarmap_api_search_slug_resolver', options: ['i18n' => false])]#[OA\Get(summary: 'Resolve search page slugs', description: 'Resolves section, property type, and location slugs into their corresponding search page entities.', tags: ['ListingsSearch'])]#[OA\Parameter(name: 'section', description: 'Section slug.', in: 'query', required: false, schema: new OA\Schema(type: 'string'))]#[OA\Parameter(name: 'propertyType', description: 'Property Type slug.', in: 'query', required: false, schema: new OA\Schema(type: 'string'))]#[OA\Parameter(name: 'locations', description: 'Locations slugs. Can be provided as an array.', in: 'query', required: false, schema: new OA\Schema(type: 'array', items: new OA\Items(type: 'string')))]#[Rest\View(serializerGroups: ['SlugResolver'])]#[Rest\QueryParam(name: 'section', default: null, description: 'Section slug')]#[Rest\QueryParam(name: 'propertyType', default: null, description: 'Property Type slug')]#[Rest\QueryParam(name: 'locations', default: null, description: 'Locations slugs. As array.')]#[Cache(expires: '+7 days', maxage: '+7 days', smaxage: '+7 days', public: true, vary: ['Accept-Language', 'X-Accept-Version', 'Accept'])]#[OA\Response(response: 200, description: 'Resolved section, property type, and location entities for the provided slugs.')]public function resolveSearchPageSlugs(Request $request, SectionRepository $sectionRepo, PropertyTypeRepository $propertyTypeRepo, LocationRepository $locationRepo): array{if ($request->get('location')) {$request->query->set('locations', explode(',', $request->query->get('location', '')));}$locationsSlugs = $request->query->all('locations');$data = ['section' => $sectionRepo->findOneBy(['slug' => $request->query->get('section')]),'propertyType' => $propertyTypeRepo->findOneBy(['slug' => $request->query->get('propertyType')]),'locations' => [],];if (!empty($locationsSlugs) && $this->validLocationSlugArray($locationsSlugs)) {$data['locations'] = $locationRepo->getLocationsBySlugs($locationsSlugs);}return $data;}/*** Legazy.*/#[Rest\Get('/api/v2/search/properties-chips-legazy', options: ['i18n' => false], name: 'aqarmap_api_properties_chips_legazy')]#[Rest\View]#[Cache(expires: '+1 days', maxage: '+1 days', smaxage: '+1 days', public: true, vary: ['Accept-Language', 'X-Accept-Version', 'Accept'])]public function getPropertiesChipsLegazy(Request $request,#[MapEntity(id: 'location')]?Location $location,#[MapEntity(id: 'propertyType')]?PropertyType $propertyType,#[MapEntity(id: 'section')]?Section $section,MenuBuilderService $menuBuilderService,) {$locale = $request->getLocale();$data = [];if ($section && $propertyType) {$criteria = ['location' => $location,'propertyType' => $propertyType,'section' => $section,'locale' => $locale,];$data = $menuBuilderService->getSearchResultPropertyChips($criteria);}return $data;}#[Rest\Get('/api/v2/search/properties-chips', options: ['i18n' => false], name: 'aqarmap_api_properties_chips')]#[OA\Get(summary: 'Get search property chips', description: 'Returns property type chips and result counts for the active search filters.', tags: ['ListingsSearch'])]#[Rest\View]#[Cache(expires: '+1 days', maxage: '+1 days', smaxage: '+1 days', public: true, vary: ['Accept-Language', 'X-Accept-Version', 'Accept'])]#[OA\Response(response: 200, description: 'Property type chips ordered by matching listings count.')]public function getPropertiesChips(Request $request, ListingManager $listingManager, PropertyTypeRepository $propertyTypeRepository){$result = [];$types = $listingManager->getPropertiesChipsElasticResponse($request);$typesArray = [];foreach ($types as $id => $doc_count) {$typesArray[$id] = $doc_count;}arsort($typesArray);$propertyTypes = $propertyTypeRepository->findPropertyTypes(array_keys($typesArray));foreach ($propertyTypes as $propertyType) {$id = $propertyType->getId();$result[] = ['id' => $id,'title' => $propertyType->getTitle(),'slug' => $propertyType->getSlug(),'searchResultCount' => $typesArray[$id] ?? 0,'level' => $propertyType->getLevel(),];}return $result;}#[Rest\Get('/api/v2/search/{section}/{propertyType}/{location}/page-metadata', options: ['i18n' => false], name: 'aqarmap_api_search_page_metadata')]#[Rest\View(serializerGroups: ['Default'])]public function getSeoData(Section $section,PropertyType $propertyType,Location $location,CustomParagraphRepository $customParagraphRepository,SEOListingSearchService $seoListingSearchService,) {$data['customParagraph'] = $customParagraphRepository->get(['location' => $location->getId(),'propertyType' => $propertyType->getId(),'section' => $section->getId(),'place' => CustomParagraphPlaceTypes::SEARCH_RESULTS,])->getQuery()->setMaxResults(1)->getOneOrNullResult();$data['longTail'] = $seoListingSearchService->retrieveLongTail($location, $section, $propertyType);return ['data' => $data,];}#[Rest\Get('/api/v2/custom-paragraph', options: ['i18n' => false], name: 'aqarmap_api_custom_paragraph')]#[Rest\View(serializerGroups: ['Default'])]public function getCustomParagraph(Request $request,#[MapEntity(id: 'location')]?Location $location,#[MapEntity(id: 'section')]?Section $section,#[MapEntity(id: 'propertyType')]?PropertyType $propertyType,CustomParagraphRepository $customParagraphRepository,) {return $customParagraphRepository->get(['location' => $location ? $location->getId() : null,'propertyType' => $propertyType ? $propertyType->getId() : null,'section' => $section->getId(),'place' => $request->query->get('place') ?: CustomParagraphPlaceTypes::SEARCH_RESULTS,])->getQuery()->setMaxResults(1)->getOneOrNullResult();}#[Rest\Get('/api/v2/location/{location}/listing', options: ['i18n' => false], name: 'aqarmap_api_location_listing_v2')]#[Rest\QueryParam(name: 'id', default: null, description: 'Location id')]#[Rest\View(serializerGroups: ['locationListingV2'])]public function getLocationListing(Location $location){return $location;}private function validLocationSlugArray($array): bool{return \count($array) > 0 && array_reduce($array, fn ($carry, $item) => $carry && \is_string($item) && '' !== $item, true);}#[Rest\Get('/api/v4/search/ssr-data', name: 'aqarmap_search_results_ssr_data', options: ['i18n' => false, 'expose' => false])]#[OA\Get(summary: 'Get search SSR metadata', description: 'Builds SEO metadata and supporting SSR fields for search pages based on section, property type, and location slugs.', tags: ['ListingsSearch'])]#[OA\Parameter(name: 'section', description: 'Section slug.', in: 'query', required: false, schema: new OA\Schema(type: 'string'))]#[OA\Parameter(name: 'propertyType', description: 'Property Type slug.', in: 'query', required: false, schema: new OA\Schema(type: 'string'))]#[OA\Parameter(name: 'locations', description: 'Array of Locations slugs.', in: 'query', required: false, schema: new OA\Schema(type: 'array', items: new OA\Items(type: 'string')))]#[Rest\QueryParam(name: 'section', default: null, description: 'Section slug')]#[Rest\QueryParam(name: 'propertyType', default: null, description: 'Property Type slug')]#[Rest\QueryParam(name: 'locations', default: null, description: 'Array of Locations slugs.')]#[Rest\View(serializerGroups: ['SlugResolver'])]#[OA\Response(response: 200, description: 'SSR metadata payload for the search page.')]#[OA\Response(response: 400, description: 'Returned when section, property type, or locations are missing from the request.')]public function singlePageSSRData(Request $request, SectionRepository $sectionRepository, PropertyTypeRepository $propertyTypeRepository, LocationRepository $locationRepository, BuilderInterface $searchDescriptionBuilder): array{$sectionSlug = $request->get('section');if (!$sectionSlug) {throw new \InvalidArgumentException('Section is required');}$section = $sectionRepository->findOneBy(['slug' => $sectionSlug]);$propertyTypeSlug = $request->get('propertyType');if (!$propertyTypeSlug) {throw new \InvalidArgumentException('propertyType is required');}$propertyType = $propertyTypeRepository->findOneBy(['slug' => $propertyTypeSlug]);$locationsSlugs = $request->query->all('locations');if (!$locationsSlugs) {throw new \InvalidArgumentException('locations is required');}$locations = $locationRepository->getLocationsBySlugs($locationsSlugs);// Page Description$searchDescriptionBuilder->setSection($section)->setPropertyType($propertyType)->setLocation(reset($locations));return ['section' => $section,'propertyType' => $propertyType,'locations' => $locations,'pageTitle' => '','metaDescription' => $searchDescriptionBuilder->format()->get(),'metaKeywords' => '','canonicalUrl' => '','breadcrumbs' => [['title' => '','url' => '',],],'propertyTypesChips' => [['title' => '','url' => '',],],];}}