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

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