src/Aqarmap/Bundle/SearchBundle/Controller/Api/V4/ListingSearchController.php line 592

Open in your IDE?
  1. <?php
  2. namespace Aqarmap\Bundle\SearchBundle\Controller\Api\V4;
  3. use App\Exception\UnauthorizedHttpException;
  4. use Aqarmap\Bundle\ListingBundle\Constant\ListingStatus;
  5. use Aqarmap\Bundle\ListingBundle\Entity\Location;
  6. use Aqarmap\Bundle\ListingBundle\Entity\Section;
  7. use Aqarmap\Bundle\ListingBundle\Event\SearchTriggerEvent;
  8. use Aqarmap\Bundle\ListingBundle\Message\Search;
  9. use Aqarmap\Bundle\ListingBundle\Repository\ListingRepository;
  10. use Aqarmap\Bundle\ListingBundle\Repository\LocationRepository;
  11. use Aqarmap\Bundle\ListingBundle\Repository\PropertyTypeRepository;
  12. use Aqarmap\Bundle\ListingBundle\Repository\SectionRepository;
  13. use Aqarmap\Bundle\ListingBundle\Service\ListingManager;
  14. use Aqarmap\Bundle\ListingBundle\Service\RelatedResultService;
  15. use Aqarmap\Bundle\ListingBundle\Service\SectionService;
  16. use Aqarmap\Bundle\MainBundle\Controller\Api\V4\BaseController;
  17. use Aqarmap\Bundle\MainBundle\Model\Listing\V4\ListingDataMapper;
  18. use Aqarmap\Bundle\MainBundle\Repository\CustomParagraphRepository;
  19. use Aqarmap\Bundle\SearchBundle\CriteriaBuilders\BuilderDirector;
  20. use Aqarmap\Bundle\SearchBundle\CriteriaMediator\Contracts\MediatorInterface;
  21. use Aqarmap\Bundle\SearchBundle\Services\ListingFaqService;
  22. use Aqarmap\Bundle\SearchBundle\Services\SEOListingSearchService;
  23. use FOS\RestBundle\Controller\Annotations as Rest;
  24. use FOS\RestBundle\View\View;
  25. use JMS\Serializer\SerializationContext;
  26. use JMS\Serializer\SerializerInterface;
  27. use Nelmio\ApiDocBundle\Annotation\Operation;
  28. use OpenApi\Annotations as OA;
  29. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
  30. use Symfony\Component\Cache\Adapter\AdapterInterface;
  31. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  32. use Symfony\Component\HttpFoundation\JsonResponse;
  33. use Symfony\Component\HttpFoundation\Request;
  34. use Symfony\Component\HttpFoundation\Response;
  35. use Symfony\Component\Messenger\MessageBusInterface;
  36. class ListingSearchController extends BaseController
  37. {
  38.     /**
  39.      * @var BuilderDirector
  40.      */
  41.     private $builderDirector;
  42.     /**
  43.      * @var MediatorInterface
  44.      */
  45.     private $mediator;
  46.     /**
  47.      * @var EventDispatcherInterface
  48.      */
  49.     private $eventDispatcher;
  50.     /**
  51.      * @var SerializerInterface
  52.      */
  53.     private $serializer;
  54.     /**
  55.      * @var RelatedResultService
  56.      */
  57.     private $relatedResultService;
  58.     /**
  59.      * @var CustomParagraphRepository
  60.      */
  61.     private $customParagraphRepository;
  62.     /**
  63.      * @var SEOListingSearchService
  64.      */
  65.     private $seoListingSearchService;
  66.     /**
  67.      * @var LocationRepository
  68.      */
  69.     private $locationRepository;
  70.     /**
  71.      * @var SectionRepository
  72.      */
  73.     private $sectionRepository;
  74.     /**
  75.      * @var PropertyTypeRepository
  76.      */
  77.     private $propertyTypeRepository;
  78.     /**
  79.      * @var ListingFaqService
  80.      */
  81.     private $listingFaqService;
  82.     public function __construct(
  83.         BuilderDirector $builderDirector,
  84.         MediatorInterface $mediator,
  85.         EventDispatcherInterface $eventDispatcher,
  86.         SerializerInterface $serializer,
  87.         RelatedResultService $relatedResultService,
  88.         LocationRepository $locationRepository,
  89.         CustomParagraphRepository $customParagraphRepository,
  90.         SEOListingSearchService $seoListingSearchService,
  91.         SectionRepository $sectionRepository,
  92.         PropertyTypeRepository $propertyTypeRepository,
  93.         ListingFaqService $listingFaqService
  94.     ) {
  95.         $this->builderDirector $builderDirector;
  96.         $this->mediator $mediator;
  97.         $this->eventDispatcher $eventDispatcher;
  98.         $this->serializer $serializer;
  99.         $this->relatedResultService $relatedResultService;
  100.         $this->customParagraphRepository $customParagraphRepository;
  101.         $this->seoListingSearchService $seoListingSearchService;
  102.         $this->locationRepository $locationRepository;
  103.         $this->sectionRepository $sectionRepository;
  104.         $this->propertyTypeRepository $propertyTypeRepository;
  105.         $this->listingFaqService $listingFaqService;
  106.     }
  107.     /**
  108.      * Listings Search V4 ( Legacy code ).
  109.      *
  110.      * @Operation(
  111.      *     tags={"Listing"},
  112.      *     summary="Search",
  113.      *
  114.      *     @OA\Parameter(
  115.      *         name="propertyType",
  116.      *         in="query",
  117.      *         description="Property Type ID",
  118.      *         required=false,
  119.      *     ),
  120.      *     @OA\Parameter(
  121.      *         name="location",
  122.      *         in="query",
  123.      *         description="Location ID comma spereted",
  124.      *         required=false,
  125.      *     ),
  126.      *     @OA\Parameter(
  127.      *         name="section",
  128.      *         in="query",
  129.      *         description="Section ID",
  130.      *         required=false,
  131.      *     ),
  132.      *     @OA\Parameter(
  133.      *         name="bounds",
  134.      *         in="query",
  135.      *         description="Map bounds (example: 24.6275450,46.6363017,24.6977461,46.817232)",
  136.      *         required=false,
  137.      *     ),
  138.      *     @OA\Parameter(
  139.      *         name="minPrice",
  140.      *         in="query",
  141.      *         description="Minimum Prices",
  142.      *         required=false,
  143.      *     ),
  144.      *     @OA\Parameter(
  145.      *         name="maxPrice",
  146.      *         in="query",
  147.      *         description="Maximum Prices",
  148.      *         required=false,
  149.      *     ),
  150.      *     @OA\Parameter(
  151.      *         name="minArea",
  152.      *         in="query",
  153.      *         description="Minimum Area",
  154.      *         required=false,
  155.      *     ),
  156.      *     @OA\Parameter(
  157.      *         name="maxArea",
  158.      *         in="query",
  159.      *         description="Maximum Area",
  160.      *         required=false,
  161.      *     ),
  162.      *     @OA\Parameter(
  163.      *         name="minFloor",
  164.      *         in="query",
  165.      *         description="Minimum Floor",
  166.      *         required=false,
  167.      *     ),
  168.      *     @OA\Parameter(
  169.      *         name="minRoom",
  170.      *         in="query",
  171.      *         description="Minimum Room",
  172.      *         required=false,
  173.      *     ),
  174.      *     @OA\Parameter(
  175.      *         name="floor",
  176.      *         in="query",
  177.      *         description="Floor Number",
  178.      *         required=false,
  179.      *     ),
  180.      *     @OA\Parameter(
  181.      *         name="room",
  182.      *         in="query",
  183.      *         description="Number of Rooms",
  184.      *         required=false,
  185.      *     ),
  186.      *     @OA\Parameter(
  187.      *         name="baths",
  188.      *         in="query",
  189.      *         description="Number of Baths",
  190.      *         required=false,
  191.      *     ),
  192.      *     @OA\Parameter(
  193.      *         name="finishType",
  194.      *         in="query",
  195.      *         description="finish Type",
  196.      *         required=false,
  197.      *     ),
  198.      *     @OA\Parameter(
  199.      *         name="sellerRole",
  200.      *         in="query",
  201.      *         description="sellerRole",
  202.      *         required=false,
  203.      *     ),
  204.      *     @OA\Parameter(
  205.      *         name="paymentMethod",
  206.      *         in="query",
  207.      *         description="paymentMethod",
  208.      *         required=false,
  209.      *     ),
  210.      *     @OA\Parameter(
  211.      *         name="deliveryYear",
  212.      *         in="query",
  213.      *         description="deliveryYear",
  214.      *         required=false,
  215.      *     ),
  216.      *     @OA\Parameter(
  217.      *         name="bath",
  218.      *         in="query",
  219.      *         description="Number of Baths",
  220.      *         required=false,
  221.      *     ),
  222.      *     @OA\Parameter(
  223.      *         name="photos",
  224.      *         in="query",
  225.      *         description="Get only listings with photos",
  226.      *         required=false,
  227.      *     ),
  228.      *     @OA\Parameter(
  229.      *         name="isMortgage",
  230.      *         in="query",
  231.      *         description="Get only listings that support mortgage",
  232.      *         required=false,
  233.      *     ),
  234.      *     @OA\Parameter(
  235.      *         name="eligibleForMortgage",
  236.      *         in="query",
  237.      *         description="Get listings that has mortgage Percentage",
  238.      *         required=false,
  239.      *     ),
  240.      *     @OA\Parameter(
  241.      *         name="page",
  242.      *         in="query",
  243.      *         description="Page number, starting from 1.",
  244.      *         required=false,
  245.      *     ),
  246.      *     @OA\Parameter(
  247.      *         name="limit",
  248.      *         in="query",
  249.      *         description="Number of items per page.",
  250.      *         required=false,
  251.      *     ),
  252.      *     @OA\Parameter(
  253.      *         name="sort",
  254.      *         in="query",
  255.      *         description="Sort search results by price or area.",
  256.      *         required=false,
  257.      *     ),
  258.      *     @OA\Parameter(
  259.      *         name="direction",
  260.      *         in="query",
  261.      *         description="Ascending (A to Z, 0 to 9), Descending (Z to A, 9 to 0)",
  262.      *         required=false,
  263.      *     ),
  264.      *     @OA\Parameter(
  265.      *         name="keywordSearch",
  266.      *         in="query",
  267.      *         description="Search by keyword in listing's title, description and address",
  268.      *         required=false,
  269.      *     ),
  270.      *     @OA\Parameter(
  271.      *         name="unitOnly",
  272.      *         in="query",
  273.      *         description="Get compound units only",
  274.      *         required=false,
  275.      *     ),
  276.      *
  277.      *     @OA\Response(
  278.      *         response="500",
  279.      *         description="Returned when something went wrong, for example if you entered non existing propertyType ID"
  280.      *     )
  281.      * )
  282.      *
  283.      * @Rest\Get("/api/v4/listings/search-legacy", options={"i18n" = false}, name="legacy_aqarmap_api_listings_search_v4")
  284.      *
  285.      * @Rest\QueryParam(name="propertyType", requirements="\d+", default=null, description="Property Type ID")
  286.      * @Rest\QueryParam(name="location", requirements="\d+", default=null, description="Location ID comma spereted")
  287.      * @Rest\QueryParam(name="section", requirements="\d+", default=null, description="Section ID")
  288.      * @Rest\QueryParam(
  289.      *      name="bounds", requirements="South-West Latitude,
  290.      *      Longitude, North-East Latitude, Longitude", default=null,
  291.      *      description="Map bounds (example: 24.6275450,46.6363017,24.6977461,46.817232)"
  292.      * )
  293.      * @Rest\QueryParam(name="minPrice", requirements="\d+", default=null, description="Minimum Prices")
  294.      * @Rest\QueryParam(name="maxPrice", requirements="\d+", default=null, description="Maximum Prices")
  295.      * @Rest\QueryParam(name="minArea", requirements="\d+", default=null, description="Minimum Area")
  296.      * @Rest\QueryParam(name="maxArea", requirements="\d+", default=null, description="Maximum Area")
  297.      * @Rest\QueryParam(name="minFloor", requirements="\d+", default=null, description="Minimum Floor")
  298.      * @Rest\QueryParam(name="minRoom", requirements="\d+", default=null, description="Minimum Room")
  299.      * @Rest\QueryParam(name="floor", requirements="\d+", default=null, description="Floor Number")
  300.      * @Rest\QueryParam(name="room", requirements="\d+", default=null, description="Number of Rooms")
  301.      * @Rest\QueryParam(name="baths", requirements="\d+", default=null, description="Number of Baths")
  302.      * @Rest\QueryParam(name="finishType", default=null, description="finish Type")
  303.      * @Rest\QueryParam(name="sellerRole", requirements="\d+", default=null, description="sellerRole")
  304.      * @Rest\QueryParam(name="paymentMethod", requirements="\d+", default=null, description="paymentMethod")
  305.      * @Rest\QueryParam(name="deliveryYear", requirements="\d+", default=null, description="deliveryYear")
  306.      * @Rest\QueryParam(name="bath", default=null, default=null, description="Number of Baths")
  307.      * @Rest\QueryParam(
  308.      *     name="photos", requirements="(1)|(0)",
  309.      *     nullable=true, strict=true, default="0",
  310.      *     description="Get only listings with photos"
  311.      * )
  312.      * @Rest\QueryParam(
  313.      *     name="isMortgage", requirements="(1)|(0)",
  314.      *     nullable=true, strict=true, default="0",
  315.      *     description="Get only listings that support mortgage"
  316.      * )
  317.      * @Rest\QueryParam(name="eligibleForMortgage", nullable=true, strict=true, description="Get listings that has mortgage Percentage")
  318.      * @Rest\QueryParam(
  319.      *     name="page", requirements="\d+", nullable=true, default=1,
  320.      *     description="Page number, starting from 1."
  321.      * )
  322.      * @Rest\QueryParam(
  323.      *     name="limit", requirements="\d+", nullable=true,
  324.      *     default=10, description="Number of items per page."
  325.      * )
  326.      * @Rest\QueryParam(
  327.      *     name="sort", requirements="price|area", nullable=true,
  328.      *     default=null, description="Sort search results by price or area."
  329.      * )
  330.      * @Rest\QueryParam(
  331.      *     name="direction", requirements="asc|desc", nullable=true,
  332.      *     default="asc", description="Ascending (A to Z, 0 to 9), Descending (Z to A, 9 to 0)"
  333.      * )
  334.      * @Rest\QueryParam(
  335.      *     name="keywordSearch",
  336.      *     description="Search by keyword in listing's title, description and address"
  337.      * )
  338.      * @Rest\QueryParam(
  339.      *     name="unitOnly",
  340.      *     description="Get compound units only",
  341.      *     requirements="(1)|(0)",
  342.      *     nullable=true,
  343.      * )
  344.      *
  345.      * @Rest\View()
  346.      *
  347.      * @Cache(
  348.      *  expires="+2 hours", maxage="+2 hours", smaxage="+2 hours",
  349.      *  public=true, vary={"Accept-Language", "X-Accept-Version", "Accept"}
  350.      * )
  351.      */
  352.     public function getSearchListings(Request $requestAdapterInterface $cache): Response
  353.     {
  354.         $criteria $this->builderDirector->build($request)->getResult();
  355.         $locations explode(','$request->query->get('location'''));
  356.         $request->query->set('locations'$locations);
  357.         if (!empty($criteria['keywordSearch'])) {
  358.             $this->eventDispatcher->dispatch(new SearchTriggerEvent($request));
  359.         }
  360.         if ($this->getUser()) {
  361.             $this->dispatchMessage(new Search($request->query$this->getUser()));
  362.         }
  363.         $criteria['status'] = ListingStatus::LIVE;
  364.         $cacheKey sprintf('api_v4_listings_search_%s_%s'$request->getLocale(), md5(http_build_query($request->query->all())));
  365.         $cachedSerialize $cache->getItem($cacheKey);
  366.         if (!$cachedSerialize->isHit() || empty($cachedSerialize->get())) {
  367.             $result $this->mediator->start($criteria)->getResults();
  368.             $mapped = new ListingDataMapper();
  369.             $mapped->setMapListingAttributes(true);
  370.             $mapped->setMapListingMainPhoto(true);
  371.             $mapped->setMapListingPhotos(true);
  372.             $data = [
  373.                 'default' => $this->makeMappedPaginatedBody($result['searchResults'], $mapped),
  374.                 'related' => [],
  375.             ];
  376.             $data $this->serializer->serialize(
  377.                 $data,
  378.                 'json',
  379.                 SerializationContext::create()
  380.                     ->setGroups('SearchV4')
  381.                     ->enableMaxDepthChecks()
  382.             );
  383.             $cachedSerialize->set($data);
  384.             $cachedSerialize->expiresAfter(3600 3);
  385.             $cache->save($cachedSerialize);
  386.         }
  387.         return new Response($cachedSerialize->get());
  388.     }
  389.     /**
  390.      * Related Listings Search V4.
  391.      *
  392.      * @Operation(
  393.      *     tags={"Listing"},
  394.      *     summary="Search",
  395.      *
  396.      *     @OA\Parameter(
  397.      *         name="propertyType",
  398.      *         in="query",
  399.      *         description="Property Type ID",
  400.      *         required=false,
  401.      *     ),
  402.      *     @OA\Parameter(
  403.      *         name="location",
  404.      *         in="query",
  405.      *         description="Location ID comma spereted",
  406.      *         required=false,
  407.      *     ),
  408.      *     @OA\Parameter(
  409.      *         name="section",
  410.      *         in="query",
  411.      *         description="Section ID",
  412.      *         required=false,
  413.      *     ),
  414.      *     @OA\Parameter(
  415.      *         name="page",
  416.      *         in="query",
  417.      *         description="Page number, starting from 1.",
  418.      *         required=false,
  419.      *     ),
  420.      *     @OA\Parameter(
  421.      *         name="limit",
  422.      *         in="query",
  423.      *         description="Number of items per page.",
  424.      *         required=false,
  425.      *     ),
  426.      *     @OA\Parameter(
  427.      *         name="sort",
  428.      *         in="query",
  429.      *         description="Sort search results by price or area.",
  430.      *         required=false,
  431.      *     ),
  432.      *     @OA\Parameter(
  433.      *         name="direction",
  434.      *         in="query",
  435.      *         description="Ascending (A to Z, 0 to 9), Descending (Z to A, 9 to 0)",
  436.      *         required=false,
  437.      *     ),
  438.      *
  439.      *     @OA\Response(
  440.      *         response="500",
  441.      *         description="Returned when something went wrong, for example if you entered non existing propertyType ID"
  442.      *     )
  443.      * )
  444.      *
  445.      * @Rest\Get("/api/v4/listings/search/related", options={"i18n" = false}, name="aqarmap_api_get_related_results_v4")
  446.      *
  447.      * @Rest\QueryParam(name="propertyType", requirements="\d+", default=null, description="Property Type ID")
  448.      * @Rest\QueryParam(name="location", requirements="\d+", default=null, description="Location ID comma spereted")
  449.      * @Rest\QueryParam(name="section", requirements="\d+", default=null, description="Section ID")
  450.      * @Rest\QueryParam(
  451.      *     name="page", requirements="\d+", nullable=true, default=1,
  452.      *     description="Page number, starting from 1."
  453.      * )
  454.      * @Rest\QueryParam(
  455.      *     name="limit", requirements="\d+", nullable=true,
  456.      *     default=10, description="Number of items per page."
  457.      * )
  458.      * @Rest\QueryParam(
  459.      *     name="sort", requirements="price|area", nullable=true,
  460.      *     default=null, description="Sort search results by price or area."
  461.      * )
  462.      * @Rest\QueryParam(
  463.      *     name="direction", requirements="asc|desc", nullable=true,
  464.      *     default="asc", description="Ascending (A to Z, 0 to 9), Descending (Z to A, 9 to 0)"
  465.      * )
  466.      *
  467.      * @Rest\View(serializerGroups={"DefaultV4", "SearchV4"})
  468.      *
  469.      * @return View
  470.      *
  471.      * @throws \Exception
  472.      */
  473.     public function getRelatedSearchListings(Request $request)
  474.     {
  475.         $criteria $this->builderDirector
  476.             ->build($request)
  477.             ->getResult();
  478.         $criteria['page'] = $request->query->get('page'1);
  479.         $criteria['selectedLocation'] = current($criteria['location']);
  480.         return $this->paginatedRespond(
  481.             $this->relatedResultService->joinListingsWithPaginatedLocations($criteria)
  482.         );
  483.     }
  484.     /**
  485.      * @Rest\Get("/api/v4/listings", options={"i18n" = false}, name="aqarmap_api_get_listings")
  486.      * @Rest\Get("/api/v4/listings/search", options={"i18n" = false}, name="aqarmap_api_listings_search_v4")
  487.      */
  488.     public function getListings(Request $requestListingRepository $listingRepositoryListingManager $listingManagerAdapterInterface $cacheMessageBusInterface $messageBus)
  489.     {
  490.         /** @var UserInterface $user */
  491.         $user $this->getUser();
  492.         $hasSearchScoringRole $user && $user->hasRole('ROLE_SEARCH_SCORING');
  493.         if (!$hasSearchScoringRole && ($request->get('esdebug') || $request->get('scoredebug'))) {
  494.             $request->query->remove('esdebug');
  495.             $request->query->remove('scoredebug');
  496.         }
  497.         if ($request->get('location')) {
  498.             $request->query->set('locations'explode(','$request->query->get('location''')));
  499.         }
  500.         $cacheKey sprintf('api_listings_search_v4_%s_%s'$request->getLocale(), md5(http_build_query($request->query->all())));
  501.         $cachedSerialize $cache->getItem($cacheKey);
  502.         if (!$cachedSerialize->isHit() || empty($cachedSerialize->get())) {
  503.             $listingsElasticResponse $listingManager->getListingsElasticResponse($request);
  504.             $listingsQueryBuilder $listingRepository->getListingsByIds(array_column($listingsElasticResponse['items'], 'id'));
  505.             if ('aqarmap_api_listings_search_v4' === $request->attributes->get('_route')) {
  506.                 $listingsElasticResponse['pagination']['totalPages'] = (float) $listingsElasticResponse['pagination']['totalPages'];
  507.             }
  508.             $listings $listingsQueryBuilder->getQuery()->getResult();
  509.             $data = [
  510.                 'default' => $this->mapPaginatedBody($listingsElasticResponse$listings),
  511.                 'related' => [],
  512.             ];
  513.             $data $this->serializer->serialize(
  514.                 $data,
  515.                 'json',
  516.                 SerializationContext::create()
  517.                     ->setGroups('SearchV4')
  518.                     ->enableMaxDepthChecks()
  519.             );
  520.             $cachedSerialize->set($data);
  521.             $cachedSerialize->expiresAfter(3600 3);
  522.             $cache->save($cachedSerialize);
  523.         }
  524.         return new Response($cachedSerialize->get());
  525.     }
  526.     /**
  527.      * @Rest\Get("/api/v4/listings/debug", options={"i18n" = false}, name="aqarmap_api_get_listings_debug")
  528.      */
  529.     public function getListingsEsDebug(Request $requestListingManager $listingManager)
  530.     {
  531.         /** @var UserInterface $user */
  532.         $user $this->getUser();
  533.         if (!($user && $user->hasRole('ROLE_SEARCH_SCORING'))) {
  534.             throw new UnauthorizedHttpException();
  535.         }
  536.         $request->query->set('esdebug'1);
  537.         if ($request->get('location')) {
  538.             $request->query->set('locations'explode(','$request->query->get('location''')));
  539.         }
  540.         $listingsDebugElasticResponse $listingManager->getListingsDebugElasticResponse($request);
  541.         if ('aqarmap_api_listings_search_v4' === $request->attributes->get('_route')) {
  542.             $listingsDebugElasticResponse['pagination']['totalPages'] = (float) $listingsDebugElasticResponse['pagination']['totalPages'];
  543.         }
  544.         $data = [
  545.             'default' => $this->mapPaginatedBody($listingsDebugElasticResponse$listingsDebugElasticResponse['items']),
  546.         ];
  547.         return new JsonResponse($data);
  548.     }
  549.     /**
  550.      * @Rest\Get("/api/v4/listings/search/ssr-data", options={"i18n" = false}, name="aqarmap_api_get_listings_search_ssr-data")
  551.      */
  552.     public function getListingsSearchSSRData(Request $requestListingManager $listingManagerAdapterInterface $cacheSectionService $sectionService)
  553.     {
  554.         $cacheKey sprintf('api_listings_search_ssr_data_%s_%s'$request->getLocale(), md5(http_build_query($request->query->all())));
  555.         $cachedResponse $cache->getItem($cacheKey);
  556.         if (!$cachedResponse->isHit() || empty($cachedResponse->get())) {
  557.             $customParagraph $locationChildren $slugResolver $faqData $locationParents = [];
  558.             if ($request->get('location')) {
  559.                 $request->query->set('locations'explode(','$request->query->get('location''')));
  560.             }
  561.             $location $request->get('locations') ? $request->get('locations')[0] : null;
  562.             $location $this->locationRepository->findOneBy(['slug' => $location]);
  563.             $section $this->sectionRepository->findOneBy(['slug' => $request->query->get('section')]);
  564.             $propertyType $this->propertyTypeRepository->findOneBy(['slug' => $request->query->get('propertyType')]);
  565.             if ($location) {
  566.                 $locationChildren $listingManager->getSerializedLocationChildren($location);
  567.                 $locationParents $listingManager->getLocationParents($location$request->getLocale());
  568.             }
  569.             if ($section && $propertyType && $location) {
  570.                 $longTail $this->seoListingSearchService->getSerializedLongTailData($section$propertyType$location) ?? [];
  571.             }
  572.             if ($section && $propertyType) {
  573.                 $customParagraph $listingManager->getSerializedCustomParagraph($section$propertyType$location) ?? [];
  574.                 $slugResolver $listingManager->getSerializedResolvedSlugs($section$propertyType, (array) $request->query->get('locations', []));
  575.                 $faqData $listingManager->getFaqs($section$propertyType$location$request->getLocale());
  576.             }
  577.             $response = [
  578.                 'locationChildren' => !empty($locationChildren) ? json_decode($locationChildrentrue) : [],
  579.                 'longTail' => !empty($longTail) ? json_decode($longTailtrue) : [],
  580.                 'customParagraph' => !empty($customParagraph) ? json_decode($customParagraphtrue) : [],
  581.                 'slugResolver' => !empty($slugResolver) ? json_decode($slugResolvertrue) : [],
  582.                 'faqData' => $faqData,
  583.                 'locationParents' => $locationParents,
  584.                 'sections' => json_decode($sectionService->getSerializedSections(), true),
  585.                 'propertyTypeChips' => $listingManager->getListingPropertyTypesChips($request$location$section$propertyType),
  586.             ];
  587.             $cachedResponse->set(json_encode($response));
  588.             $cachedResponse->expiresAfter(3600 3);
  589.             $cache->save($cachedResponse);
  590.         }
  591.         return new JsonResponse(json_decode($cachedResponse->get(), true));
  592.     }
  593.     /**
  594.      * @Rest\Get("/api/v4/listings/trigger-search", options={"i18n" = false}, name="aqarmap_api_trigger_search_listings_v4")
  595.      */
  596.     public function triggerSearchListingsAction(Request $requestMessageBusInterface $messageBus)
  597.     {
  598.         $user $this->getUser();
  599.         if ($request->get('location')) {
  600.             $request->query->set('locations'explode(','$request->query->get('location''')));
  601.         }
  602.         if ($request->get('keywordSearch')) {
  603.             $this->eventDispatcher->dispatch(new SearchTriggerEvent($request));
  604.         }
  605.         if ($user) {
  606.             $messageBus->dispatch(new Search($request->query$user));
  607.         }
  608.         return new JsonResponse([
  609.             'statusCode' => Response::HTTP_OK,
  610.             'statusMessage' => 'Search triggered successfully!',
  611.         ]);
  612.     }
  613.     private function mapPaginatedBody(array $result, array $listings): array
  614.     {
  615.         if (!$result['pagination']) {
  616.             return [
  617.                 'statusCode' => $this->getStatusCode(),
  618.                 'statusMessage' => $this->getStatusMessage(),
  619.                 'paginate' => [],
  620.                 'data' => [],
  621.                 'errors' => $this->getErrors(),
  622.             ];
  623.         }
  624.         return [
  625.             'statusCode' => $this->getStatusCode(),
  626.             'statusMessage' => $this->getStatusMessage(),
  627.             'paginate' => $result['pagination'],
  628.             'data' => $listings,
  629.             'errors' => $this->getErrors(),
  630.         ];
  631.     }
  632. }