src/Controller/ProfileListController.php line 457

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by simpson <simpsonwork@gmail.com>
  4.  * Date: 2019-03-19
  5.  * Time: 22:28
  6.  */
  7. namespace App\Controller;
  8. use App\Bridge\Porpaginas\Doctrine\ORM\FakeORMQueryPage;
  9. use App\Entity\Location\City;
  10. use App\Entity\Location\County;
  11. use App\Entity\Location\District;
  12. use App\Entity\Location\Station;
  13. use App\Entity\Profile\BodyTypes;
  14. use App\Entity\Profile\BreastTypes;
  15. use App\Entity\Profile\Genders;
  16. use App\Entity\Profile\HairColors;
  17. use App\Entity\Profile\Nationalities;
  18. use App\Entity\Profile\PrivateHaircuts;
  19. use App\Entity\Service;
  20. use App\Entity\ServiceGroups;
  21. use App\Entity\TakeOutLocations;
  22. use App\Repository\ServiceRepository;
  23. use App\Repository\StationRepository;
  24. use App\Service\CountryCurrencyResolver;
  25. use App\Service\DefaultCityProvider;
  26. use App\Service\Features;
  27. use App\Service\HomepageCityListingsBlockProvider;
  28. use App\Service\ListingRotationApi;
  29. use App\Service\ListingService;
  30. use App\Service\ProfileList;
  31. use App\Service\ProfileListingDataCreator;
  32. use App\Service\ProfileListSpecificationService;
  33. use App\Service\ProfileFilterService;
  34. use App\Service\ProfileTopBoard;
  35. use App\Service\Top100ProfilesService;
  36. use App\Specification\ElasticSearch\ISpecification;
  37. use App\Specification\Profile\ProfileHasApartments;
  38. use App\Specification\Profile\ProfileHasComments;
  39. use App\Specification\Profile\ProfileHasVideo;
  40. use App\Specification\Profile\ProfileIdIn;
  41. use App\Specification\Profile\ProfileIdINOrderedByINValues;
  42. use App\Specification\Profile\ProfileIdNotIn;
  43. use App\Specification\Profile\ProfileIsApproved;
  44. use App\Specification\Profile\ProfileIsElite;
  45. use App\Specification\Profile\ProfileIsLocated;
  46. use App\Specification\Profile\ProfileIsProvidingOneOfServices;
  47. use App\Specification\Profile\ProfileIsProvidingTakeOut;
  48. use App\Specification\Profile\ProfilePriceThresholds;
  49. use App\Specification\Profile\ProfileWithAge;
  50. use App\Specification\Profile\ProfileWithBodyType;
  51. use App\Specification\Profile\ProfileWithBreastType;
  52. use App\Specification\Profile\ProfileWithHairColor;
  53. use App\Specification\Profile\ProfileWithNationality;
  54. use App\Specification\Profile\ProfileWithApartmentsOneHourPrice;
  55. use App\Specification\Profile\ProfileWithPrivateHaircut;
  56. use Flagception\Bundle\FlagceptionBundle\Annotations\Feature;
  57. use Happyr\DoctrineSpecification\Filter\Filter;
  58. use Happyr\DoctrineSpecification\Logic\OrX;
  59. use OpenApi\Attributes as OA;
  60. use Porpaginas\Doctrine\ORM\ORMQueryResult;
  61. use Porpaginas\Page;
  62. use Psr\Cache\CacheItemPoolInterface;
  63. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
  64. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
  65. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  66. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  67. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  68. use Symfony\Component\HttpFoundation\Request;
  69. use Happyr\DoctrineSpecification\Spec;
  70. use Symfony\Component\HttpFoundation\RequestStack;
  71. use Symfony\Component\HttpFoundation\Response;
  72. use Symfony\Component\Routing\Annotation\Route;
  73. /**
  74.  * @see \App\Console\Export\ExportRotationListingsConfigCommand for listing API endpoints
  75.  */
  76. #[Cache(maxage60, public: true)]
  77. class ProfileListController extends AbstractController
  78. {
  79.     use ExtendedPaginationTrait;
  80.     use SpecTrait;
  81.     use ProfileMinPriceTrait;
  82.     use ResponseTrait;
  83.     const ENTRIES_ON_PAGE 36;
  84.     const RESULT_SOURCE_COUNTY 'county';
  85.     const RESULT_SOURCE_DISTRICT 'district';
  86.     const RESULT_SOURCE_STATION 'station';
  87.     const RESULT_SOURCE_APPROVED 'approved';
  88.     const RESULT_SOURCE_WITH_COMMENTS 'with_comments';
  89.     const RESULT_SOURCE_WITH_VIDEO 'with_video';
  90.     const RESULT_SOURCE_WITH_SELFIE 'with_selfie';
  91.     const RESULT_SOURCE_TOP_100 'top_100';
  92.     const RESULT_SOURCE_ELITE 'elite';
  93.     const RESULT_SOURCE_MASSEURS 'masseurs';
  94.     const RESULT_SOURCE_MASSAGE_SERVICE 'massage_service';
  95.     const RESULT_SOURCE_BY_PARAMS 'by_params';
  96.     const RESULT_SOURCE_SERVICE 'service';
  97.     const RESULT_SOURCE_CITY 'city';
  98.     const RESULT_SOURCE_COUNTRY 'country';
  99.     const CACHE_ITEM_STATION_ADDED_PROFILES 'station_added_profiles_ids_';
  100.     const RESULT_SOURCE_WITH_WHATSAPP 'with_whatsapp';
  101.     const RESULT_SOURCE_WITH_TELEGRAM 'with_telegram';
  102.     const RESULT_SOURCE_EIGHTEEN_YEARS_OLD 'eighteen_years_old';
  103.     const RESULT_SOURCE_BIG_ASS 'big_ass';
  104.     const RESULT_SOURCE_WITH_TATTOO 'with_tattoo';
  105.     const RESULT_SOURCE_WITH_PIERCING 'with_piercing';
  106.     const RESULT_SOURCE_ROUND_THE_CLOCK 'round_the_clock';
  107.     const RESULT_SOURCE_FOR_TWO_HOURS 'for_two_hours';
  108.     const RESULT_SOURCE_FOR_HOUR 'for_hour';
  109.     const RESULT_SOURCE_EXPRESS_PROGRAM 'express_program';
  110.     const RESULT_SOURCE_EROMASSAGE 'eromassage';
  111.     const RESULT_SOURCE_VERIFIED 'verified';
  112.     const RESULT_SOURCE_CHEAP 'cheap';
  113.     const RESULT_SOURCE_MATURE 'mature';
  114.     const RESULT_SOURCE_UZBEK 'uzbek';
  115.     private ?string $source null;
  116.     public function __construct(
  117.         private RequestStack $requestStack,
  118.         private ProfileList                     $profileList,
  119.         private CountryCurrencyResolver         $countryCurrencyResolver,
  120.         private ServiceRepository               $serviceRepository,
  121.         private ListingService                  $listingService,
  122.         private Features                        $features,
  123.         private ProfileFilterService            $profilesFilterService,
  124.         private ProfileListSpecificationService $profileListSpecificationService,
  125.         private ProfileListingDataCreator       $profileListingDataCreator,
  126.         private Top100ProfilesService           $top100ProfilesService,
  127.         private CacheItemPoolInterface          $stationAddedProfilesCache,
  128.         private ParameterBagInterface           $parameterBag,
  129.         private ListingRotationApi              $listingRotationApi,
  130.         private ProfileTopBoard                 $profileTopBoard,
  131.         private HomepageCityListingsBlockProvider $homepageCityListingsBlockProvider,
  132.     ) {}
  133.     /**
  134.      * @Feature("has_masseurs")
  135.      */
  136.     #[ParamConverter("city"converter"city_converter")]
  137.     #[Route("/api/profiles/listing/city/{city}/masseur"name"api.profile_listing.masseur"methods"GET"format"json")]
  138.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  139.     #[OA\Tag(name"ProfileListing")]
  140.     #[OA\Response(
  141.         response200,
  142.         description'',
  143.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  144.     )]
  145.     public function listForMasseur(Request $requestCity $cityServiceRepository $serviceRepository): Response
  146.     {
  147.         $specs $this->profileListSpecificationService->listForMasseur($city);
  148.         $response = new Response();
  149.         $massageGroupServices $serviceRepository->findBy(['group' => ServiceGroups::MASSAGE]);
  150.         $alternativeSpec $this->getORSpecForItemsArray([$massageGroupServices], function($item): ProfileIsProvidingOneOfServices {
  151.             return new ProfileIsProvidingOneOfServices($item);
  152.         });
  153.         $result $this->paginatedListing($city'/city/{city}/masseur', ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_MASSAGE_SERVICE$response);
  154.         if ($this->isApiRequest($request)) {
  155.             return $this->json($result);
  156.         }
  157.         return $this->render('ProfileList/list.html.twig', [
  158.             'profiles' => $result,
  159.             'source' => $this->source,
  160.             'source_default' => self::RESULT_SOURCE_MASSEURS,
  161.             'recommendationSpec' => $specs->recommendationSpec(),
  162.         ], response$response);
  163.     }
  164.     /**
  165.      * @Feature("extra_category_big_ass")
  166.      */
  167.     #[ParamConverter("city"converter"city_converter")]
  168.     #[Route("/api/profiles/listing/city/{city}/category/big_ass"name"api.profile_listing.category.big_ass"methods"GET"format"json")]
  169.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  170.     #[OA\Tag(name"ProfileListing")]
  171.     #[OA\Response(
  172.         response200,
  173.         description'',
  174.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  175.     )]
  176.     public function listBigAss(Request $requestCity $city): Response
  177.     {
  178.         $specs $this->profileListSpecificationService->listBigAss();
  179.         $response = new Response();
  180.         $result $this->paginatedListing($city'/city/{city}/category/big_ass', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  181.         if ($this->isApiRequest($request)) {
  182.             return $this->json($result);
  183.         }
  184.         return $this->render('ProfileList/list.html.twig', [
  185.             'profiles' => $result,
  186.             'source' => $this->source,
  187.             'source_default' => self::RESULT_SOURCE_BIG_ASS,
  188.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  189.                 'city' => $city->getUriIdentity(),
  190.                 'page' => $this->getCurrentPageNumber(),
  191.             ]),
  192.             'recommendationSpec' => $specs->recommendationSpec(),
  193.         ], response$response);
  194.     }
  195.     public function listByDefaultCity(ParameterBagInterface $parameterBagRequest $request): Response
  196.     {
  197.         $controller get_class($this).'::listByCity';
  198.         $path = [
  199.             'city' => $parameterBag->get('default_city'),
  200.             'subRequest' => true,
  201.         ];
  202.         //чтобы в обработчике можно было понять, по какому роуту зашли
  203.         $request->request->set('_route''profile_list.list_by_city');
  204.         return $this->forward($controller$path);
  205.     }
  206.     private function paginatedListing(City $city, ?string $apiEndpoint, array $apiParams, ?Filter $listingSpec null, ?OrX $alternativeSpec null, ?string $alternativeSource null, ?Response $response null): Page
  207.     {
  208.         $topPlacement $this->profileTopBoard->topPlacementSatisfiedBy($city$listingSpec);
  209.         $topPlacement?->setTopCard(); // mark as top card for UI
  210.         $page $this->getCurrentPageNumber();
  211.         $apiParams['city'] = $city->getId();
  212.         try {
  213.             if (null === $apiEndpoint) {
  214.                 throw new \RuntimeException('Empty API endpoint to switch to legacy listing query.');
  215.             }
  216.             $result $this->listingRotationApi->paginate($apiEndpoint$apiParams$page$topPlacement);
  217.             $response?->setMaxAge(10);
  218.         } catch (\Exception) {
  219.             $avoidOrTopPlacement = (null !== $topPlacement && $page 2) ? $topPlacement null;
  220.             $result $this->profileList->list($citynull$listingSpec, [], truenullProfileList::ORDER_BY_STATUS,
  221.                 nulltruenull, [Genders::FEMALE], $avoidOrTopPlacement);
  222.         }
  223.         if (null !== $alternativeSpec || null !== $alternativeSource) {
  224.             $prevCount $result->count();
  225.             $result $this->checkEmptyResultNotMasseur($result$city$alternativeSpec$alternativeSource);
  226.             if ($result->count() > $prevCount) {
  227.                 $response?->setMaxAge(60);
  228.             }
  229.         }
  230.         return $result;
  231.     }
  232.     #[ParamConverter("city"converter"city_converter")]
  233.     #[Route("/api/profiles/listing/city/{city}"name"api.profile_listing.by_city"methods"GET"format"json")]
  234.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  235.     #[OA\Tag(name"ProfileListing")]
  236.     #[OA\Response(
  237.         response200,
  238.         description'Листинг анкет по городу',
  239.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  240.     )]
  241.     public function listByCity(ParameterBagInterface $parameterBagRequest $requestCity $citybool $subRequest false): Response
  242.     {
  243.         $page $this->getCurrentPageNumber();
  244.         if ($this->features->redirect_default_city_to_homepage() && false === $subRequest && $city->equals($parameterBag->get('default_city')) && $page 2) {
  245.             return $this->redirectToRoute('homepage', [], 301);
  246.         }
  247.         $specs $this->profileListSpecificationService->listByCity();
  248.         $response = new Response();
  249.         $result $this->paginatedListing($city'/city/{city}', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  250.         if ($this->isApiRequest($request)) {
  251.             return $this->json($result);
  252.         }
  253.         $homepageCityListingsBlock null;
  254.         if ($this->shouldShowHomepageCityListingsBlock($city$page$subRequest)) {
  255.             $homepageCityListingsBlock $this->homepageCityListingsBlockProvider->getForCity($city);
  256.         }
  257.         return $this->render('ProfileList/list.html.twig', [
  258.             'profiles' => $result,
  259.             'homepage_city_listings_block' => $homepageCityListingsBlock,
  260.             'recommendationSpec' => $specs->recommendationSpec(),
  261.         ], response$response);
  262.     }
  263.     /**
  264.      * @Feature("intim_moscow_listing")
  265.      */
  266.     #[Cache(maxage3600, public: true)]
  267.     #[Route("/api/profiles/listing/city/{city}/intim"name"api.profile_listing.intim"methods"GET"format"json")]
  268.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  269.     #[OA\Tag(name"ProfileListing")]
  270.     #[OA\Response(
  271.         response200,
  272.         description'',
  273.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  274.     )]
  275.     public function listIntim(Request $requestDefaultCityProvider $defaultCityProvider): Response
  276.     {
  277.         $city $defaultCityProvider->getDefaultCity();
  278.         $request->attributes->set('city'$city);
  279.         $specs $this->profileListSpecificationService->listByCity();
  280.         $response = new Response();
  281.         $result $this->paginatedListing($city'/city/{city}/intim', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  282.         $result $this->shuffleProfilesOnPage($result);
  283.         $response->setMaxAge(3600);
  284.         if ($this->isApiRequest($request)) {
  285.             return $this->json($result);
  286.         }
  287.         return $this->render('ProfileList/list.html.twig', [
  288.             'profiles' => $result,
  289.             'city' => $city,
  290.             'recommendationSpec' => $specs->recommendationSpec(),
  291.         ], response$response);
  292.     }
  293.     #[ParamConverter("city"converter"city_converter")]
  294.     #[Entity("county"expr"repository.ofUriIdentityWithinCity(county, city)")]
  295.     #[Route("/api/profiles/listing/city/{city}/county/{county}"name"api.profile_listing.by_county"methods"GET"format"json")]
  296.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  297.     #[OA\Tag(name"ProfileListing")]
  298.     #[OA\Response(
  299.         response200,
  300.         description'',
  301.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  302.     )]
  303.     public function listByCounty(Request $requestCity $cityCounty $county): Response
  304.     {
  305.         if (!$city->hasCounty($county)) {
  306.             throw $this->createNotFoundException();
  307.         }
  308.         $specs $this->profileListSpecificationService->listByCounty($county);
  309.         $response = new Response();
  310.         $alternativeSpec Spec::orX(ProfileIsLocated::withinCounties($city$city->getCounties()->toArray()));
  311.         $result $this->paginatedListing($city'/city/{city}/county/{county}', ['city' => $city->getId(), 'county' => $county->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_COUNTY$response);
  312.         if ($this->isApiRequest($request)) {
  313.             return $this->json($result);
  314.         }
  315.         return $this->render('ProfileList/list.html.twig', [
  316.             'profiles' => $result,
  317.             'source' => $this->source,
  318.             'source_default' => self::RESULT_SOURCE_COUNTY,
  319.             'county' => $county,
  320.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  321.                 'city' => $city->getUriIdentity(),
  322.                 'county' => $county->getUriIdentity(),
  323.                 'page' => $this->getCurrentPageNumber()
  324.             ]),
  325.             'recommendationSpec' => $specs->recommendationSpec(),
  326.         ], response$response);
  327.     }
  328.     #[ParamConverter("city"converter"city_converter")]
  329.     #[Entity("district"expr"repository.ofUriIdentityWithinCity(district, city)")]
  330.     #[Route("/api/profiles/listing/city/{city}/district/{district}"name"api.profile_listing.by_district"methods"GET"format"json")]
  331.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  332.     #[OA\Tag(name"ProfileListing")]
  333.     #[OA\Response(
  334.         response200,
  335.         description'',
  336.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  337.     )]
  338.     public function listByDistrict(Request $requestCity $cityDistrict $district): Response
  339.     {
  340.         if (!$city->hasDistrict($district)) {
  341.             throw $this->createNotFoundException();
  342.         }
  343.         $specs $this->profileListSpecificationService->listByDistrict($district);
  344.         $response = new Response();
  345.         $alternativeSpec Spec::orX(ProfileIsLocated::withinDistricts($city$city->getDistricts()->toArray()));
  346.         $result $this->paginatedListing($city'/city/{city}/district/{district}', ['city' => $city->getId(), 'district' => $district->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_DISTRICT$response);
  347.         if ($this->isApiRequest($request)) {
  348.             return $this->json($result);
  349.         }
  350.         return $this->render('ProfileList/list.html.twig', [
  351.             'profiles' => $result,
  352.             'source' => $this->source,
  353.             'source_default' => self::RESULT_SOURCE_DISTRICT,
  354.             'district' => $district,
  355.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  356.                 'city' => $city->getUriIdentity(),
  357.                 'district' => $district->getUriIdentity(),
  358.                 'page' => $this->getCurrentPageNumber()
  359.             ]),
  360.             'recommendationSpec' => $specs->recommendationSpec(),
  361.         ], response$response);
  362.     }
  363.     /**
  364.      * @Feature("extra_category_without_prepayment")
  365.      */
  366.     #[ParamConverter("city"converter"city_converter")]
  367.     #[Route("/api/profiles/listing/city/{city}/category/without_prepayment"name"api.profile_listing.category.without_prepayment"methods"GET"format"json")]
  368.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  369.     #[OA\Tag(name"ProfileListing")]
  370.     #[OA\Response(
  371.         response200,
  372.         description'',
  373.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  374.     )]
  375.     public function listWithoutPrepayment(Request $requestCity $city): Response
  376.     {
  377.         $listingData $this->profileListingDataCreator->getListingDataForFilter('listWithoutPrepayment', [], $city);
  378.         $specs $listingData['specs'];
  379.         $listingTypeName $listingData['listingTypeName'];
  380.         $response = new Response();
  381.         $result $this->paginatedListing($city'/city/{city}/category/without_prepayment', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  382.         if ($this->isApiRequest($request)) {
  383.             return $this->json($result);
  384.         }
  385.         $request->attributes->set('profiles_count'$result->totalCount());
  386.         $request->attributes->set('listingTypeName'$listingTypeName);
  387.         $request->attributes->set('city'$city);
  388.         return $this->render('ProfileList/list.html.twig', [
  389.             'profiles' => $result,
  390.             'source' => $this->source,
  391.             'source_default' => 'without_prepayment',
  392.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  393.                 'city' => $city->getUriIdentity(),
  394.                 'page' => $this->getCurrentPageNumber(),
  395.             ]),
  396.             'recommendationSpec' => $specs->recommendationSpec(),
  397.         ], response$response);
  398.     }
  399.     #[ParamConverter("city"converter"city_converter")]
  400.     #[Entity("station"expr"repository.ofUriIdentityWithinCity(station, city)")]
  401.     #[Route("/api/profiles/listing/city/{city}/station/{station}"name"api.profile_listing.by_station"methods"GET"format"json")]
  402.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  403.     #[OA\Tag(name"ProfileListing")]
  404.     #[OA\Response(
  405.         response200,
  406.         description'',
  407.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  408.     )]
  409.     public function listByStation(Request $requestCity $cityStation $station): Response
  410.     {
  411.         if (!$city->hasStation($station)) {
  412.             throw $this->createNotFoundException();
  413.         }
  414.         $specs $this->profileListSpecificationService->listByStation($station);
  415.         $response = new Response();
  416.         $result $this->paginatedListing($city'/city/{city}/station/{station}', ['city' => $city->getId(), 'station' => $station->getId()], $specs->spec(), nullnull$response);
  417.         $prevCount $result->count();
  418.         if (true === $this->features->station_page_add_profiles()) {
  419.             $spread $this->parameterBag->get('app.profile.station_page.added_profiles.spread');
  420.             $result $this->addSinglePageStationResults($result$city$station$spread ?: 5);
  421.         }
  422.         if (null !== $station->getDistrict()) {
  423.             $result $this->checkEmptyResultNotMasseur($result$citySpec::orX(ProfileIsLocated::nearStations($city$station->getDistrict()->getStations()->toArray())), self::RESULT_SOURCE_STATION);
  424.         } else {
  425.             $result $this->checkCityAndCountrySource($result$city);
  426.         }
  427.         if ($result->count() > $prevCount) {
  428.             $response?->setMaxAge(60);
  429.         }
  430.         if ($this->isApiRequest($request)) {
  431.             return $this->json($result);
  432.         }
  433.         return $this->render('ProfileList/list.html.twig', [
  434.             'profiles' => $result,
  435.             'source' => $this->source,
  436.             'source_default' => self::RESULT_SOURCE_STATION,
  437.             'station' => $station,
  438.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  439.                 'city' => $city->getUriIdentity(),
  440.                 'station' => $station->getUriIdentity(),
  441.                 'page' => $this->getCurrentPageNumber()
  442.             ]),
  443.             'recommendationSpec' => $specs->recommendationSpec(),
  444.         ], response$response);
  445.     }
  446.     private function addSinglePageStationResults(Page $resultCity $cityStation $stationint $spread): Page
  447.     {
  448.         if ($result->totalCount() >= $result->getCurrentLimit()) {
  449.             return $result;
  450.         }
  451.         $addedProfileIds $this->stationAddedProfilesCache->get(self::CACHE_ITEM_STATION_ADDED_PROFILES $station->getId(), function () use ($result$city$station$spread): array {
  452.             $currentSpread rand(0$spread);
  453.             $plannedTotalCount $result->getCurrentLimit() - $spread $currentSpread;
  454.             $result iterator_to_array($result->getIterator());
  455.             $originalProfileIds $this->extractProfileIds($result);
  456.             if ($station->getDistrict()) {
  457.                 $result $this->addSinglePageResultsUptoAmount($result$citySpec::orX(ProfileIsLocated::withinDistrict($station->getDistrict())), $plannedTotalCount);
  458.             }
  459.             if ($station->getDistrict()?->getCounty()) {
  460.                 $result $this->addSinglePageResultsUptoAmount($result$citySpec::orX(ProfileIsLocated::withinCounty($station->getDistrict()->getCounty())), $plannedTotalCount);
  461.             }
  462.             $result $this->addSinglePageResultsUptoAmount($result$citySpec::orX(ProfileIsLocated::withinCity($city)), $plannedTotalCount);
  463.             $result $this->extractProfileIds($result);
  464.             return array_diff($result$originalProfileIds);
  465.         });
  466.         $addedProfileIds array_slice($addedProfileIds0$result->getCurrentLimit() - $result->totalCount());
  467.         $originalProfiles iterator_to_array($result->getIterator());
  468.         $addedProfiles $this->listActiveWithinCityOrderedByStatusWithSpecAvoidingTopPlacementLimited($city, new ProfileIdIn($addedProfileIds), null, [Genders::FEMALE], count($addedProfileIds));
  469.         $newResult array_merge($originalProfiles$addedProfiles);
  470.         return new FakeORMQueryPage(01$result->getCurrentLimit(), count($newResult), $newResult);
  471.     }
  472.     private function addSinglePageResultsUptoAmount(array $resultCity $city, ?Filter $specsint $totalCount): array
  473.     {
  474.         $toAdd $totalCount count($result);
  475.         if ($toAdd 0) {
  476.             $currentResultIds $this->extractProfileIds($result);
  477.             $resultsToAdd $this->listActiveWithinCityOrderedByStatusWithSpecAvoidingTopPlacementLimited($city$specs, [new ProfileIdNotIn($currentResultIds)], [Genders::FEMALE], $toAdd);
  478.             $result array_merge($result$resultsToAdd);
  479.         }
  480.         return $result;
  481.     }
  482.     #[ParamConverter("city"converter"city_converter")]
  483.     public function listByStations(City $citystring $stationsStationRepository $stationRepository): Response
  484.     {
  485.         $stationIds explode(','$stations);
  486.         $stations $stationRepository->findBy(['uriIdentity' => $stationIds]);
  487.         $specs $this->profileListSpecificationService->listByStations($stations);
  488.         $response = new Response();
  489.         $result $this->paginatedListing($citynull, [], $specs->spec(), nullnull$response);
  490.         return $this->render('ProfileList/list.html.twig', [
  491.             'profiles' => $result,
  492.             'recommendationSpec' => $specs->recommendationSpec(),
  493.         ]);
  494.     }
  495.     #[ParamConverter("city"converter"city_converter")]
  496.     #[Route("/api/profiles/listing/city/{city}/approved"name"api.profile_listing.approved"methods"GET"format"json")]
  497.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  498.     #[OA\Tag(name"ProfileListing")]
  499.     #[OA\Response(
  500.         response200,
  501.         description'',
  502.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  503.     )]
  504.     public function listApproved(Request $requestCity $city): Response
  505.     {
  506.         $specs $this->profileListSpecificationService->listApproved();
  507.         $response = new Response();
  508.         $result $this->paginatedListing($city'/city/{city}/approved', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  509.         $prevCount $result->count();
  510.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  511.             $this->source self::RESULT_SOURCE_WITH_COMMENTS;
  512.             $result $this->listRandomSinglePage($citynull, new ProfileHasComments(), nulltruefalse);
  513.             if ($result->count() == 0) {
  514.                 $this->source self::RESULT_SOURCE_WITH_VIDEO;
  515.                 $result $this->listRandomSinglePage($citynull, new ProfileHasVideo(), nulltruefalse);
  516.             }
  517.             if ($result->count() == 0) {
  518.                 $this->source self::RESULT_SOURCE_ELITE;
  519.                 $result $this->listRandomSinglePage($citynull$this->getSpecForEliteGirls($city), nulltruenull);
  520.             }
  521.             $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  522.         }
  523.         if ($result->count() > $prevCount) {
  524.             $response?->setMaxAge(60);
  525.         }
  526.         if ($this->isApiRequest($request)) {
  527.             return $this->json($result);
  528.         }
  529.         return $this->render('ProfileList/list.html.twig', [
  530.             'profiles' => $result,
  531.             'source' => $this->source,
  532.             'source_default' => self::RESULT_SOURCE_APPROVED,
  533.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  534.                 'city' => $city->getUriIdentity(),
  535.                 'page' => $this->getCurrentPageNumber()
  536.             ]),
  537.             'recommendationSpec' => $specs->recommendationSpec(),
  538.         ], response$response);
  539.     }
  540.     /**
  541.      * @Feature("extra_category_with_whatsapp")
  542.      */
  543.     #[ParamConverter("city"converter"city_converter")]
  544.     #[Route("/api/profiles/listing/city/{city}/category/whatsapp"name"api.profile_listing.category.whatsapp"methods"GET"format"json")]
  545.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  546.     #[OA\Tag(name"ProfileListing")]
  547.     #[OA\Response(
  548.         response200,
  549.         description'',
  550.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  551.     )]
  552.     public function listWithWhatsapp(Request $requestCity $city): Response
  553.     {
  554.         $specs $this->profileListSpecificationService->listWithWhatsapp();
  555.         $response = new Response();
  556.         $result $this->paginatedListing($city'/city/{city}/category/whatsapp', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  557.         if ($this->isApiRequest($request)) {
  558.             return $this->json($result);
  559.         }
  560.         return $this->render('ProfileList/list.html.twig', [
  561.             'profiles' => $result,
  562.             'source' => $this->source,
  563.             'source_default' => self::RESULT_SOURCE_WITH_WHATSAPP,
  564.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  565.                 'city' => $city->getUriIdentity(),
  566.                 'page' => $this->getCurrentPageNumber(),
  567.             ]),
  568.             'recommendationSpec' => $specs->recommendationSpec(),
  569.         ], response$response);
  570.     }
  571.     /**
  572.      * @Feature("extra_category_with_telegram")
  573.      */
  574.     #[ParamConverter("city"converter"city_converter")]
  575.     #[Route("/api/profiles/listing/city/{city}/category/telegram"name"api.profile_listing.category.telegram"methods"GET"format"json")]
  576.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  577.     #[OA\Tag(name"ProfileListing")]
  578.     #[OA\Response(
  579.         response200,
  580.         description'',
  581.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  582.     )]
  583.     public function listWithTelegram(Request $requestCity $city): Response
  584.     {
  585.         $specs $this->profileListSpecificationService->listWithTelegram();
  586.         $response = new Response();
  587.         $result $this->paginatedListing($city'/city/{city}/category/telegram', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  588.         if ($this->isApiRequest($request)) {
  589.             return $this->json($result);
  590.         }
  591.         return $this->render('ProfileList/list.html.twig', [
  592.             'profiles' => $result,
  593.             'source' => $this->source,
  594.             'source_default' => self::RESULT_SOURCE_WITH_TELEGRAM,
  595.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  596.                 'city' => $city->getUriIdentity(),
  597.                 'page' => $this->getCurrentPageNumber(),
  598.             ]),
  599.             'recommendationSpec' => $specs->recommendationSpec(),
  600.         ], response$response);
  601.     }
  602.     /**
  603.      * @Feature("extra_category_eighteen_years_old")
  604.      */
  605.     #[ParamConverter("city"converter"city_converter")]
  606.     #[Route("/api/profiles/listing/city/{city}/category/eighteen_years_old"name"api.profile_listing.category.eighteen_years_old"methods"GET"format"json")]
  607.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  608.     #[OA\Tag(name"ProfileListing")]
  609.     #[OA\Response(
  610.         response200,
  611.         description'',
  612.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  613.     )]
  614.     public function listEighteenYearsOld(Request $requestCity $city): Response
  615.     {
  616.         $specs $this->profileListSpecificationService->listEighteenYearsOld();
  617.         $response = new Response();
  618.         $result $this->paginatedListing($city'/city/{city}/category/eighteen_years_old', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  619.         if ($this->isApiRequest($request)) {
  620.             return $this->json($result);
  621.         }
  622.         return $this->render('ProfileList/list.html.twig', [
  623.             'profiles' => $result,
  624.             'source' => $this->source,
  625.             'source_default' => self::RESULT_SOURCE_EIGHTEEN_YEARS_OLD,
  626.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  627.                 'city' => $city->getUriIdentity(),
  628.                 'page' => $this->getCurrentPageNumber(),
  629.             ]),
  630.             'recommendationSpec' => $specs->recommendationSpec(),
  631.         ], response$response);
  632.     }
  633.     /**
  634.      * @Feature("extra_category_rublevskie")
  635.      */
  636.     #[ParamConverter("city"converter"city_converter")]
  637.     #[Route("/api/profiles/listing/city/{city}/category/rublevskie"name"api.profile_listing.category.rublevskie"methods"GET"format"json")]
  638.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  639.     #[OA\Tag(name"ProfileListing")]
  640.     #[OA\Response(
  641.         response200,
  642.         description'',
  643.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  644.     )]
  645.     public function listRublevskie(Request $requestCity $city): Response
  646.     {
  647.         if ($city->getUriIdentity() !== 'moscow') {
  648.             throw $this->createNotFoundException();
  649.         }
  650.         $specs $this->profileListSpecificationService->listRublevskie($city);
  651.         $response = new Response();
  652.         $result $this->paginatedListing($city'/city/{city}/category/rublevskie', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  653.         if ($this->isApiRequest($request)) {
  654.             return $this->json($result);
  655.         }
  656.         return $this->render('ProfileList/list.html.twig', [
  657.             'profiles' => $result,
  658.             'source' => $this->source,
  659.             'source_default' => 'rublevskie',
  660.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  661.                 'city' => $city->getUriIdentity(),
  662.                 'page' => $this->getCurrentPageNumber(),
  663.             ]),
  664.             'recommendationSpec' => $specs->recommendationSpec(),
  665.         ], response$response);
  666.     }
  667.     /**
  668.      * @Feature("extra_category_with_tattoo")
  669.      */
  670.     #[ParamConverter("city"converter"city_converter")]
  671.     #[Route("/api/profiles/listing/city/{city}/category/with_tattoo"name"api.profile_listing.category.with_tattoo"methods"GET"format"json")]
  672.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  673.     #[OA\Tag(name"ProfileListing")]
  674.     #[OA\Response(
  675.         response200,
  676.         description'',
  677.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  678.     )]
  679.     public function listWithTattoo(Request $requestCity $city): Response
  680.     {
  681.         $specs $this->profileListSpecificationService->listWithTattoo();
  682.         $response = new Response();
  683.         $result $this->paginatedListing($city'/city/{city}/category/with_tattoo', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  684.         if ($this->isApiRequest($request)) {
  685.             return $this->json($result);
  686.         }
  687.         return $this->render('ProfileList/list.html.twig', [
  688.             'profiles' => $result,
  689.             'source' => $this->source,
  690.             'source_default' => self::RESULT_SOURCE_WITH_TATTOO,
  691.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  692.                 'city' => $city->getUriIdentity(),
  693.                 'page' => $this->getCurrentPageNumber(),
  694.             ]),
  695.             'recommendationSpec' => $specs->recommendationSpec(),
  696.         ], response$response);
  697.     }
  698.     #[ParamConverter("city"converter"city_converter")]
  699.     #[Route("/api/profiles/listing/city/{city}/with_comments"name"api.profile_listing.with_comments"methods"GET"format"json")]
  700.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  701.     #[OA\Tag(name"ProfileListing")]
  702.     #[OA\Response(
  703.         response200,
  704.         description'',
  705.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  706.     )]
  707.     public function listWithComments(Request $requestCity $city): Response
  708.     {
  709.         $specs $this->profileListSpecificationService->listWithComments();
  710.         $response = new Response();
  711.         $result $this->paginatedListing($city'/city/{city}/with_comments', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  712.         $prevCount $result->count();
  713.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  714.             $this->source self::RESULT_SOURCE_APPROVED;
  715.             $result $this->listRandomSinglePage($citynull, new ProfileIsApproved(), nulltruefalse);
  716.             if ($result->count() == 0) {
  717.                 $this->source self::RESULT_SOURCE_WITH_VIDEO;
  718.                 $result $this->listRandomSinglePage($citynull, new ProfileHasVideo(), nulltruefalse);
  719.             }
  720.             if ($result->count() == 0) {
  721.                 $this->source self::RESULT_SOURCE_ELITE;
  722.                 $result $this->listRandomSinglePage($citynull$this->getSpecForEliteGirls($city), nulltruenull);
  723.             }
  724.             $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  725.         }
  726.         if ($result->count() > $prevCount) {
  727.             $response?->setMaxAge(60);
  728.         }
  729.         if ($this->isApiRequest($request)) {
  730.             return $this->json($result);
  731.         }
  732.         return $this->render('ProfileList/list.html.twig', [
  733.             'profiles' => $result,
  734.             'source' => $this->source,
  735.             'source_default' => self::RESULT_SOURCE_WITH_COMMENTS,
  736.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  737.                 'city' => $city->getUriIdentity(),
  738.                 'page' => $this->getCurrentPageNumber()
  739.             ]),
  740.             'recommendationSpec' => $specs->recommendationSpec(),
  741.         ], response$response);
  742.     }
  743.     /**
  744.      * @Feature("extra_category_with_piercing")
  745.      */
  746.     #[ParamConverter("city"converter"city_converter")]
  747.     #[Route("/api/profiles/listing/city/{city}/category/with_piercing"name"api.profile_listing.category.with_piercing"methods"GET"format"json")]
  748.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  749.     #[OA\Tag(name"ProfileListing")]
  750.     #[OA\Response(
  751.         response200,
  752.         description'',
  753.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  754.     )]
  755.     public function listWithPiercing(Request $requestCity $city): Response
  756.     {
  757.         $specs $this->profileListSpecificationService->listWithPiercing();
  758.         $response = new Response();
  759.         $result $this->paginatedListing($city'/city/{city}/category/with_piercing', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  760.         if ($this->isApiRequest($request)) {
  761.             return $this->json($result);
  762.         }
  763.         return $this->render('ProfileList/list.html.twig', [
  764.             'profiles' => $result,
  765.             'source' => $this->source,
  766.             'source_default' => self::RESULT_SOURCE_WITH_PIERCING,
  767.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  768.                 'city' => $city->getUriIdentity(),
  769.                 'page' => $this->getCurrentPageNumber(),
  770.             ]),
  771.             'recommendationSpec' => $specs->recommendationSpec(),
  772.         ], response$response);
  773.     }
  774.     #[ParamConverter("city"converter"city_converter")]
  775.     #[Route("/api/profiles/listing/city/{city}/with_video"name"api.profile_listing.with_video"methods"GET"format"json")]
  776.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  777.     #[OA\Tag(name"ProfileListing")]
  778.     #[OA\Response(
  779.         response200,
  780.         description'',
  781.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  782.     )]
  783.     public function listWithVideo(Request $requestCity $city): Response
  784.     {
  785.         $specs $this->profileListSpecificationService->listWithVideo();
  786.         $response = new Response();
  787.         $result $this->paginatedListing($city'/city/{city}/with_video', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  788.         $prevCount $result->count();
  789.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  790.             $this->source self::RESULT_SOURCE_APPROVED;
  791.             $result $this->listRandomSinglePage($citynull, new ProfileIsApproved(), nulltruefalse);
  792.             if ($result->count() == 0) {
  793.                 $this->source self::RESULT_SOURCE_WITH_COMMENTS;
  794.                 $result $this->listRandomSinglePage($citynull, new ProfileHasComments(), nulltruefalse);
  795.             }
  796.             if ($result->count() == 0) {
  797.                 $this->source self::RESULT_SOURCE_ELITE;
  798.                 $result $this->listRandomSinglePage($citynull$this->getSpecForEliteGirls($city), nulltruenull);
  799.             }
  800.             $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  801.         }
  802.         if ($result->count() > $prevCount) {
  803.             $response?->setMaxAge(60);
  804.         }
  805.         if ($this->isApiRequest($request)) {
  806.             return $this->json($result);
  807.         }
  808.         return $this->render('ProfileList/list.html.twig', [
  809.             'profiles' => $result,
  810.             'source' => $this->source,
  811.             'source_default' => self::RESULT_SOURCE_WITH_VIDEO,
  812.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  813.                 'city' => $city->getUriIdentity(),
  814.                 'page' => $this->getCurrentPageNumber()
  815.             ]),
  816.             'recommendationSpec' => $specs->recommendationSpec(),
  817.         ], response$response);
  818.     }
  819.      /**
  820.      * @Feature("extra_category_round_the_clock")
  821.      */
  822.     #[ParamConverter("city"converter"city_converter")]
  823.     #[Route("/api/profiles/listing/city/{city}/category/round_the_clock"name"api.profile_listing.category.round_the_clock"methods"GET"format"json")]
  824.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  825.     #[OA\Tag(name"ProfileListing")]
  826.     #[OA\Response(
  827.         response200,
  828.         description'',
  829.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  830.     )]
  831.     public function listRoundTheClock(Request $requestCity $city): Response
  832.     {
  833.         $specs $this->profileListSpecificationService->listRoundTheClock();
  834.         $response = new Response();
  835.         $result $this->paginatedListing($city'/city/{city}/category/round_the_clock', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  836.         if ($this->isApiRequest($request)) {
  837.             return $this->json($result);
  838.         }
  839.         return $this->render('ProfileList/list.html.twig', [
  840.             'profiles' => $result,
  841.             'source' => $this->source,
  842.             'source_default' => self::RESULT_SOURCE_ROUND_THE_CLOCK,
  843.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  844.                 'city' => $city->getUriIdentity(),
  845.                 'page' => $this->getCurrentPageNumber(),
  846.             ]),
  847.             'recommendationSpec' => $specs->recommendationSpec(),
  848.         ], response$response);
  849.     }
  850.     /**
  851.      * @Feature("extra_category_for_two_hours")
  852.      */
  853.     #[ParamConverter("city"converter"city_converter")]
  854.     #[Route("/api/profiles/listing/city/{city}/category/for_two_hours"name"api.profile_listing.category.for_two_hours"methods"GET"format"json")]
  855.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  856.     #[OA\Tag(name"ProfileListing")]
  857.     #[OA\Response(
  858.         response200,
  859.         description'',
  860.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  861.     )]
  862.     public function listForTwoHours(Request $requestCity $city): Response
  863.     {
  864.         $specs $this->profileListSpecificationService->listForTwoHours();
  865.         $response = new Response();
  866.         $result $this->paginatedListing($city'/city/{city}/category/for_two_hours', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  867.         if ($this->isApiRequest($request)) {
  868.             return $this->json($result);
  869.         }
  870.         return $this->render('ProfileList/list.html.twig', [
  871.             'profiles' => $result,
  872.             'source' => $this->source,
  873.             'source_default' => self::RESULT_SOURCE_FOR_TWO_HOURS,
  874.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  875.                 'city' => $city->getUriIdentity(),
  876.                 'page' => $this->getCurrentPageNumber(),
  877.             ]),
  878.             'recommendationSpec' => $specs->recommendationSpec(),
  879.         ], response$response);
  880.     }
  881.     /**
  882.      * @Feature("extra_category_for_hour")
  883.      */
  884.     #[ParamConverter("city"converter"city_converter")]
  885.     #[Route("/api/profiles/listing/city/{city}/category/for_hour"name"api.profile_listing.category.for_hour"methods"GET"format"json")]
  886.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  887.     #[OA\Tag(name"ProfileListing")]
  888.     #[OA\Response(
  889.         response200,
  890.         description'',
  891.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  892.     )]
  893.     public function listForHour(Request $requestCity $city): Response
  894.     {
  895.         $specs $this->profileListSpecificationService->listForHour();
  896.         $response = new Response();
  897.         $result $this->paginatedListing($city'/city/{city}/category/for_hour', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  898.         if ($this->isApiRequest($request)) {
  899.             return $this->json($result);
  900.         }
  901.         return $this->render('ProfileList/list.html.twig', [
  902.             'profiles' => $result,
  903.             'source' => $this->source,
  904.             'source_default' => self::RESULT_SOURCE_FOR_HOUR,
  905.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  906.                 'city' => $city->getUriIdentity(),
  907.                 'page' => $this->getCurrentPageNumber(),
  908.             ]),
  909.             'recommendationSpec' => $specs->recommendationSpec(),
  910.         ], response$response);
  911.     }
  912.     /**
  913.      * @Feature("extra_category_express_program")
  914.      */
  915.     #[ParamConverter("city"converter"city_converter")]
  916.     #[Route("/api/profiles/listing/city/{city}/category/express"name"api.profile_listing.category.express"methods"GET"format"json")]
  917.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  918.     #[OA\Tag(name"ProfileListing")]
  919.     #[OA\Response(
  920.         response200,
  921.         description'',
  922.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  923.     )]
  924.     public function listExpress(Request $requestCity $city): Response
  925.     {
  926.         $specs $this->profileListSpecificationService->listExpress();
  927.         $response = new Response();
  928.         $result $this->paginatedListing($city'/city/{city}/category/express', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  929.         if ($this->isApiRequest($request)) {
  930.             return $this->json($result);
  931.         }
  932.         return $this->render('ProfileList/list.html.twig', [
  933.             'profiles' => $result,
  934.             'source' => $this->source,
  935.             'source_default' => self::RESULT_SOURCE_EXPRESS_PROGRAM,
  936.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  937.                 'city' => $city->getUriIdentity(),
  938.                 'page' => $this->getCurrentPageNumber(),
  939.             ]),
  940.             'recommendationSpec' => $specs->recommendationSpec(),
  941.         ], response$response);
  942.     }
  943.     /**
  944.      * @Feature("extra_category_grandmothers")
  945.      */
  946.     #[ParamConverter("city"converter"city_converter")]
  947.     #[Route("/api/profiles/listing/city/{city}/category/grandmothers"name"api.profile_listing.category.grandmothers"methods"GET"format"json")]
  948.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  949.     #[OA\Tag(name"ProfileListing")]
  950.     #[OA\Response(
  951.         response200,
  952.         description'',
  953.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  954.     )]
  955.     public function listGrandmothers(Request $requestCity $city): Response
  956.     {
  957.         $specs $this->profileListSpecificationService->listGrandmothers();
  958.         $response = new Response();
  959.         $result $this->paginatedListing($city'/city/{city}/category/grandmothers', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  960.         if ($this->isApiRequest($request)) {
  961.             return $this->json($result);
  962.         }
  963.         return $this->render('ProfileList/list.html.twig', [
  964.             'profiles' => $result,
  965.             'source' => $this->source,
  966.             'source_default' => 'grandmothers',
  967.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  968.                 'city' => $city->getUriIdentity(),
  969.                 'page' => $this->getCurrentPageNumber(),
  970.             ]),
  971.             'recommendationSpec' => $specs->recommendationSpec(),
  972.         ], response$response);
  973.     }
  974.         /**
  975.      * @Feature("extra_category_big_breast")
  976.      */
  977.     #[ParamConverter("city"converter"city_converter")]
  978.     #[Route("/api/profiles/listing/city/{city}/category/big_breast"name"api.profile_listing.category.big_breast"methods"GET"format"json")]
  979.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  980.     #[OA\Tag(name"ProfileListing")]
  981.     #[OA\Response(
  982.         response200,
  983.         description'',
  984.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  985.     )]
  986.     public function listBigBreast(Request $requestCity $city): Response
  987.     {
  988.         $specs $this->profileListSpecificationService->listBigBreast();
  989.         $response = new Response();
  990.         $result $this->paginatedListing($city'/city/{city}/category/big_breast', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  991.         if ($this->isApiRequest($request)) {
  992.             return $this->json($result);
  993.         }
  994.         return $this->render('ProfileList/list.html.twig', [
  995.             'profiles' => $result,
  996.             'source' => $this->source,
  997.             'source_default' => 'big_breast',
  998.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  999.                 'city' => $city->getUriIdentity(),
  1000.                 'page' => $this->getCurrentPageNumber(),
  1001.             ]),
  1002.             'recommendationSpec' => $specs->recommendationSpec(),
  1003.         ], response$response);
  1004.     }
  1005.     /**
  1006.      * @Feature("extra_category_very_skinny")
  1007.      */
  1008.     #[ParamConverter("city"converter"city_converter")]
  1009.     #[Route("/api/profiles/listing/city/{city}/category/very_skinny"name"api.profile_listing.category.very_skinny"methods"GET"format"json")]
  1010.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1011.     #[OA\Tag(name"ProfileListing")]
  1012.     #[OA\Response(
  1013.         response200,
  1014.         description'',
  1015.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1016.     )]
  1017.     public function listVerySkinny(Request $requestCity $city): Response
  1018.     {
  1019.         $specs $this->profileListSpecificationService->listVerySkinny();
  1020.         $response = new Response();
  1021.         $result $this->paginatedListing($city'/city/{city}/category/very_skinny', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1022.         if ($this->isApiRequest($request)) {
  1023.             return $this->json($result);
  1024.         }
  1025.         return $this->render('ProfileList/list.html.twig', [
  1026.             'profiles' => $result,
  1027.             'source' => $this->source,
  1028.             'source_default' => 'very_skinny',
  1029.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1030.                 'city' => $city->getUriIdentity(),
  1031.                 'page' => $this->getCurrentPageNumber(),
  1032.             ]),
  1033.             'recommendationSpec' => $specs->recommendationSpec(),
  1034.         ], response$response);
  1035.     }
  1036.     /**
  1037.      * @Feature("extra_category_small_ass")
  1038.      */
  1039.     #[ParamConverter("city"converter"city_converter")]
  1040.     #[Route("/api/profiles/listing/city/{city}/category/small_ass"name"api.profile_listing.category.small_ass"methods"GET"format"json")]
  1041.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1042.     #[OA\Tag(name"ProfileListing")]
  1043.     #[OA\Response(
  1044.         response200,
  1045.         description'',
  1046.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1047.     )]
  1048.     public function listSmallAss(Request $requestCity $city): Response
  1049.     {
  1050.         $specs $this->profileListSpecificationService->listSmallAss();
  1051.         $response = new Response();
  1052.         $result $this->paginatedListing($city'/city/{city}/category/small_ass', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1053.         if ($this->isApiRequest($request)) {
  1054.             return $this->json($result);
  1055.         }
  1056.         return $this->render('ProfileList/list.html.twig', [
  1057.             'profiles' => $result,
  1058.             'source' => $this->source,
  1059.             'source_default' => 'small_ass',
  1060.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1061.                 'city' => $city->getUriIdentity(),
  1062.                 'page' => $this->getCurrentPageNumber(),
  1063.             ]),
  1064.             'recommendationSpec' => $specs->recommendationSpec(),
  1065.         ], response$response);
  1066.     }
  1067.     /**
  1068.      * @Feature("extra_category_beautiful_prostitutes")
  1069.      */
  1070.     #[ParamConverter("city"converter"city_converter")]
  1071.     #[Route("/api/profiles/listing/city/{city}/category/beautiful_prostitutes"name"api.profile_listing.category.beautiful_prostitutes"methods"GET"format"json")]
  1072.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1073.     #[OA\Tag(name"ProfileListing")]
  1074.     #[OA\Response(
  1075.         response200,
  1076.         description'',
  1077.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1078.     )]
  1079.     public function listBeautifulProstitutes(Request $requestCity $city): Response
  1080.     {
  1081.         $specs $this->profileListSpecificationService->listBeautifulProstitutes();
  1082.         $response = new Response();
  1083.         $result $this->paginatedListing($city'/city/{city}/category/beautiful_prostitutes', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1084.         if ($this->isApiRequest($request)) {
  1085.             return $this->json($result);
  1086.         }
  1087.         return $this->render('ProfileList/list.html.twig', [
  1088.             'profiles' => $result,
  1089.             'source' => $this->source,
  1090.             'source_default' => 'beautiful_prostitutes',
  1091.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1092.                 'city' => $city->getUriIdentity(),
  1093.                 'page' => $this->getCurrentPageNumber(),
  1094.             ]),
  1095.             'recommendationSpec' => $specs->recommendationSpec(),
  1096.         ], response$response);
  1097.     }
  1098.     /**
  1099.      * @Feature("extra_category_without_intermediaries")
  1100.      */
  1101.     #[ParamConverter("city"converter"city_converter")]
  1102.     #[Route("/api/profiles/listing/city/{city}/category/without_intermediaries"name"api.profile_listing.category.without_intermediaries"methods"GET"format"json")]
  1103.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1104.     #[OA\Tag(name"ProfileListing")]
  1105.     #[OA\Response(
  1106.         response200,
  1107.         description'',
  1108.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1109.     )]
  1110.     public function listWithoutIntermediaries(Request $requestCity $city): Response
  1111.     {
  1112.         $specs $this->profileListSpecificationService->listWithoutIntermediaries();
  1113.         $response = new Response();
  1114.         $result $this->paginatedListing($city'/city/{city}/category/without_intermediaries', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1115.         if ($this->isApiRequest($request)) {
  1116.             return $this->json($result);
  1117.         }
  1118.         return $this->render('ProfileList/list.html.twig', [
  1119.             'profiles' => $result,
  1120.             'source' => $this->source,
  1121.             'source_default' => 'without_intermediaries',
  1122.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1123.                 'city' => $city->getUriIdentity(),
  1124.                 'page' => $this->getCurrentPageNumber(),
  1125.             ]),
  1126.             'recommendationSpec' => $specs->recommendationSpec(),
  1127.         ], response$response);
  1128.     }
  1129.     /**
  1130.      * @Feature("extra_category_intim_services")
  1131.      */
  1132.     #[ParamConverter("city"converter"city_converter")]
  1133.     public function intimServices(Request $requestCity $city): Response
  1134.     {
  1135.         $servicesByGroup $this->serviceRepository->allIndexedByGroup();
  1136.         return $this->render('ProfileList/intim_services.html.twig', [
  1137.             'city' => $city,
  1138.             'servicesByGroup' => $servicesByGroup,
  1139.             'skipSetCurrentListingPage' => true,
  1140.         ]);
  1141.     }
  1142.     /**
  1143.      * @Feature("extra_category_outcall")
  1144.      */
  1145.     #[ParamConverter("city"converter"city_converter")]
  1146.     #[Route("/api/profiles/listing/city/{city}/category/outcall"name"api.profile_listing.category.outcall"methods"GET"format"json")]
  1147.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1148.     #[OA\Tag(name"ProfileListing")]
  1149.     #[OA\Response(
  1150.         response200,
  1151.         description'',
  1152.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1153.     )]
  1154.     public function listOutcall(Request $requestCity $city): Response
  1155.     {
  1156.         $specs $this->profileListSpecificationService->listByOutcall();
  1157.         $response = new Response();
  1158.         $result $this->paginatedListing($city'/city/{city}/category/outcall', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1159.         if ($this->isApiRequest($request)) {
  1160.             return $this->json($result);
  1161.         }
  1162.         return $this->render('ProfileList/list.html.twig', [
  1163.             'profiles' => $result,
  1164.             'source' => $this->source,
  1165.             'source_default' => 'outcall',
  1166.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1167.                 'city' => $city->getUriIdentity(),
  1168.                 'page' => $this->getCurrentPageNumber(),
  1169.             ]),
  1170.             'recommendationSpec' => $specs->recommendationSpec(),
  1171.         ], response$response);
  1172.     }
  1173.     /**
  1174.      * @Feature("extra_category_dwarfs")
  1175.      */
  1176.     #[ParamConverter("city"converter"city_converter")]
  1177.     #[Route("/api/profiles/listing/city/{city}/category/dwarfs"name"api.profile_listing.category.dwarfs"methods"GET"format"json")]
  1178.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1179.     #[OA\Tag(name"ProfileListing")]
  1180.     #[OA\Response(
  1181.         response200,
  1182.         description'',
  1183.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1184.     )]
  1185.     public function listDwarfs(Request $requestCity $city): Response
  1186.     {
  1187.         $specs $this->profileListSpecificationService->listDwarfs();
  1188.         $response = new Response();
  1189.         $result $this->paginatedListing($city'/city/{city}/category/dwarfs', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1190.         if ($this->isApiRequest($request)) {
  1191.             return $this->json($result);
  1192.         }
  1193.         return $this->render('ProfileList/list.html.twig', [
  1194.             'profiles' => $result,
  1195.             'source' => $this->source,
  1196.             'source_default' => 'dwarfs',
  1197.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1198.                 'city' => $city->getUriIdentity(),
  1199.                 'page' => $this->getCurrentPageNumber(),
  1200.             ]),
  1201.             'recommendationSpec' => $specs->recommendationSpec(),
  1202.         ], response$response);
  1203.     }
  1204.     #[ParamConverter("city"converter"city_converter")]
  1205.     #[Route("/api/profiles/listing/city/{city}/with_selfie"name"api.profile_listing.with_selfie"methods"GET"format"json")]
  1206.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1207.     #[OA\Tag(name"ProfileListing")]
  1208.     #[OA\Response(
  1209.         response200,
  1210.         description'',
  1211.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1212.     )]
  1213.     public function listWithSelfie(Request $requestCity $city): Response
  1214.     {
  1215.         $specs $this->profileListSpecificationService->listWithSelfie();
  1216.         $response = new Response();
  1217.         $result $this->paginatedListing($city'/city/{city}/with_selfie', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1218.         $prevCount $result->count();
  1219.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  1220.             $this->source self::RESULT_SOURCE_WITH_VIDEO;
  1221.             $result $this->listRandomSinglePage($citynull, new ProfileHasVideo(), nulltruefalse);
  1222.             if ($result->count() == 0) {
  1223.                 $this->source self::RESULT_SOURCE_APPROVED;
  1224.                 $result $this->listRandomSinglePage($citynull, new ProfileIsApproved(), nulltruefalse);
  1225.             }
  1226.             if ($result->count() == 0) {
  1227.                 $this->source self::RESULT_SOURCE_ELITE;
  1228.                 $result $this->listRandomSinglePage($citynull$this->getSpecForEliteGirls($city), nulltruenull);
  1229.             }
  1230.             $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  1231.         }
  1232.         if ($result->count() > $prevCount) {
  1233.             $response?->setMaxAge(60);
  1234.         }
  1235.         if ($this->isApiRequest($request)) {
  1236.             return $this->json($result);
  1237.         }
  1238.         return $this->render('ProfileList/list.html.twig', [
  1239.             'profiles' => $result,
  1240.             'source' => $this->source,
  1241.             'source_default' => self::RESULT_SOURCE_WITH_SELFIE,
  1242.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1243.                 'city' => $city->getUriIdentity(),
  1244.                 'page' => $this->getCurrentPageNumber()
  1245.             ]),
  1246.             'recommendationSpec' => $specs->recommendationSpec(),
  1247.         ], response$response);
  1248.     }
  1249.     /**
  1250.      * @Feature("extra_category_top_100")
  1251.      */
  1252.     #[ParamConverter("city"converter"city_converter")]
  1253.     #[Route("/api/profiles/listing/city/{city}/category/top_100"name"api.profile_listing.category.top_100"methods"GET"format"json")]
  1254.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1255.     #[OA\Tag(name"ProfileListing")]
  1256.     #[OA\Response(
  1257.         response200,
  1258.         description'',
  1259.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1260.     )]
  1261.     public function listTop100(Request $requestCity $city): Response
  1262.     {
  1263.         $specs $this->profileListSpecificationService->listApproved();
  1264.         $result $this->top100ProfilesService->getSortedProfilesByVisits($city);
  1265.         if ($this->isApiRequest($request)) {
  1266.             return $this->json($result);
  1267.         }
  1268.         return $this->render('ProfileList/list.html.twig', [
  1269.             'profiles' => $result,
  1270.             'source' => self::RESULT_SOURCE_TOP_100,
  1271.             'source_default' => self::RESULT_SOURCE_TOP_100,
  1272.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1273.                 'city' => $city->getUriIdentity(),
  1274.                 'page' => $this->getCurrentPageNumber(),
  1275.             ]),
  1276.             'recommendationSpec' => $specs->recommendationSpec(),
  1277.         ]);
  1278.     }
  1279.     /**
  1280.      * @Feature("extra_category_eromassage")
  1281.      */
  1282.     #[ParamConverter("city"converter"city_converter")]
  1283.     #[Entity("county"expr"repository.ofUriIdentityWithinCity(county, city)")]
  1284.     public function listByCountyEromassage(Request $requestCity $cityCounty $county): Response
  1285.     {
  1286.         if (!$city->hasCounty($county)) {
  1287.             throw $this->createNotFoundException();
  1288.         }
  1289.         $specs $this->profileListSpecificationService->listByCountyEromassage($county);
  1290.         $response = new Response();
  1291.         $result $this->paginatedListing(
  1292.             $city,
  1293.             '/city/{city}/county/{county}/eromassage',
  1294.             ['city' => $city->getId(), 'county' => $county->getId()],
  1295.             $specs->spec(),
  1296.             null,
  1297.             null,
  1298.             $response
  1299.         );
  1300.         $request->attributes->set('profiles_count'$result->totalCount());
  1301.         return $this->render('ProfileList/list.html.twig', [
  1302.             'profiles' => $result,
  1303.             'source' => $this->source,
  1304.             'source_default' => self::RESULT_SOURCE_EROMASSAGE,
  1305.             'county' => $county,
  1306.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1307.                 'city' => $city->getUriIdentity(),
  1308.                 'county' => $county->getUriIdentity(),
  1309.                 'page' => $this->getCurrentPageNumber(),
  1310.             ]),
  1311.             'recommendationSpec' => $specs->recommendationSpec(),
  1312.         ], response$response);
  1313.     }
  1314.     /**
  1315.      * @Feature("extra_category_eromassage")
  1316.      */
  1317.     #[ParamConverter("city"converter"city_converter")]
  1318.     #[Entity("district"expr"repository.ofUriIdentityWithinCity(district, city)")]
  1319.     public function listByDistrictEromassage(Request $requestCity $cityDistrict $district): Response
  1320.     {
  1321.         if (!$city->hasDistrict($district)) {
  1322.             throw $this->createNotFoundException();
  1323.         }
  1324.         $specs $this->profileListSpecificationService->listByDistrictEromassage($district);
  1325.         $response = new Response();
  1326.         $result $this->paginatedListing(
  1327.             $city,
  1328.             '/city/{city}/district/{district}/eromassage',
  1329.             ['city' => $city->getId(), 'district' => $district->getId()],
  1330.             $specs->spec(),
  1331.             null,
  1332.             null,
  1333.             $response
  1334.         );
  1335.         $request->attributes->set('profiles_count'$result->totalCount());
  1336.         return $this->render('ProfileList/list.html.twig', [
  1337.             'profiles' => $result,
  1338.             'source' => $this->source,
  1339.             'source_default' => self::RESULT_SOURCE_EROMASSAGE,
  1340.             'district' => $district,
  1341.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1342.                 'city' => $city->getUriIdentity(),
  1343.                 'district' => $district->getUriIdentity(),
  1344.                 'page' => $this->getCurrentPageNumber(),
  1345.             ]),
  1346.             'recommendationSpec' => $specs->recommendationSpec(),
  1347.         ], response$response);
  1348.     }
  1349.     /**
  1350.      * @Feature("extra_category_eromassage")
  1351.      */
  1352.     #[ParamConverter("city"converter"city_converter")]
  1353.     #[Entity("station"expr"repository.ofUriIdentityWithinCity(station, city)")]
  1354.     public function listByStationEromassage(Request $requestCity $cityStation $station): Response
  1355.     {
  1356.         if (!$city->hasStation($station)) {
  1357.             throw $this->createNotFoundException();
  1358.         }
  1359.         $specs $this->profileListSpecificationService->listByStationEromassage($station);
  1360.         $response = new Response();
  1361.         $result $this->paginatedListing(
  1362.             $city,
  1363.             '/city/{city}/station/{station}/eromassage',
  1364.             ['city' => $city->getId(), 'station' => $station->getId()],
  1365.             $specs->spec(),
  1366.             null,
  1367.             null,
  1368.             $response
  1369.         );
  1370.         $request->attributes->set('profiles_count'$result->totalCount());
  1371.         return $this->render('ProfileList/list.html.twig', [
  1372.             'profiles' => $result,
  1373.             'source' => $this->source,
  1374.             'source_default' => self::RESULT_SOURCE_EROMASSAGE,
  1375.             'station' => $station,
  1376.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1377.                 'city' => $city->getUriIdentity(),
  1378.                 'station' => $station->getUriIdentity(),
  1379.                 'page' => $this->getCurrentPageNumber(),
  1380.             ]),
  1381.             'recommendationSpec' => $specs->recommendationSpec(),
  1382.         ], response$response);
  1383.     }
  1384.     /**
  1385.      * @Feature("extra_category_verified")
  1386.      */
  1387.     #[ParamConverter("city"converter"city_converter")]
  1388.     #[Entity("county"expr"repository.ofUriIdentityWithinCity(county, city)")]
  1389.     public function listByCountyVerified(Request $requestCity $cityCounty $county): Response
  1390.     {
  1391.         if (!$city->hasCounty($county)) {
  1392.             throw $this->createNotFoundException();
  1393.         }
  1394.         $specs $this->profileListSpecificationService->listByCountyVerified($county);
  1395.         $response = new Response();
  1396.         $result $this->paginatedListing(
  1397.             $city,
  1398.             '/city/{city}/county/{county}/proverennye',
  1399.             ['city' => $city->getId(), 'county' => $county->getId()],
  1400.             $specs->spec(),
  1401.             null,
  1402.             null,
  1403.             $response
  1404.         );
  1405.         $request->attributes->set('profiles_count'$result->totalCount());
  1406.         return $this->render('ProfileList/list.html.twig', [
  1407.             'profiles' => $result,
  1408.             'source' => $this->source,
  1409.             'source_default' => self::RESULT_SOURCE_VERIFIED,
  1410.             'county' => $county,
  1411.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1412.                 'city' => $city->getUriIdentity(),
  1413.                 'county' => $county->getUriIdentity(),
  1414.                 'page' => $this->getCurrentPageNumber(),
  1415.             ]),
  1416.             'recommendationSpec' => $specs->recommendationSpec(),
  1417.         ], response$response);
  1418.     }
  1419.     /**
  1420.      * @Feature("extra_category_verified")
  1421.      */
  1422.     #[ParamConverter("city"converter"city_converter")]
  1423.     #[Entity("district"expr"repository.ofUriIdentityWithinCity(district, city)")]
  1424.     public function listByDistrictVerified(Request $requestCity $cityDistrict $district): Response
  1425.     {
  1426.         if (!$city->hasDistrict($district)) {
  1427.             throw $this->createNotFoundException();
  1428.         }
  1429.         $specs $this->profileListSpecificationService->listByDistrictVerified($district);
  1430.         $response = new Response();
  1431.         $result $this->paginatedListing(
  1432.             $city,
  1433.             '/city/{city}/district/{district}/proverennye',
  1434.             ['city' => $city->getId(), 'district' => $district->getId()],
  1435.             $specs->spec(),
  1436.             null,
  1437.             null,
  1438.             $response
  1439.         );
  1440.         $request->attributes->set('profiles_count'$result->totalCount());
  1441.         return $this->render('ProfileList/list.html.twig', [
  1442.             'profiles' => $result,
  1443.             'source' => $this->source,
  1444.             'source_default' => self::RESULT_SOURCE_VERIFIED,
  1445.             'district' => $district,
  1446.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1447.                 'city' => $city->getUriIdentity(),
  1448.                 'district' => $district->getUriIdentity(),
  1449.                 'page' => $this->getCurrentPageNumber(),
  1450.             ]),
  1451.             'recommendationSpec' => $specs->recommendationSpec(),
  1452.         ], response$response);
  1453.     }
  1454.     /**
  1455.      * @Feature("extra_category_verified")
  1456.      */
  1457.     #[ParamConverter("city"converter"city_converter")]
  1458.     #[Entity("station"expr"repository.ofUriIdentityWithinCity(station, city)")]
  1459.     public function listByStationVerified(Request $requestCity $cityStation $station): Response
  1460.     {
  1461.         if (!$city->hasStation($station)) {
  1462.             throw $this->createNotFoundException();
  1463.         }
  1464.         $specs $this->profileListSpecificationService->listByStationVerified($station);
  1465.         $response = new Response();
  1466.         $result $this->paginatedListing(
  1467.             $city,
  1468.             '/city/{city}/station/{station}/proverennye',
  1469.             ['city' => $city->getId(), 'station' => $station->getId()],
  1470.             $specs->spec(),
  1471.             null,
  1472.             null,
  1473.             $response
  1474.         );
  1475.         $request->attributes->set('profiles_count'$result->totalCount());
  1476.         return $this->render('ProfileList/list.html.twig', [
  1477.             'profiles' => $result,
  1478.             'source' => $this->source,
  1479.             'source_default' => self::RESULT_SOURCE_VERIFIED,
  1480.             'station' => $station,
  1481.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1482.                 'city' => $city->getUriIdentity(),
  1483.                 'station' => $station->getUriIdentity(),
  1484.                 'page' => $this->getCurrentPageNumber(),
  1485.             ]),
  1486.             'recommendationSpec' => $specs->recommendationSpec(),
  1487.         ], response$response);
  1488.     }
  1489.     /**
  1490.      * @Feature("extra_category_cheap")
  1491.      */
  1492.     #[ParamConverter("city"converter"city_converter")]
  1493.     #[Entity("county"expr"repository.ofUriIdentityWithinCity(county, city)")]
  1494.     public function listByCountyCheap(Request $requestCity $cityCounty $county): Response
  1495.     {
  1496.         if (!$city->hasCounty($county)) {
  1497.             throw $this->createNotFoundException();
  1498.         }
  1499.         $specs $this->profileListSpecificationService->listByCountyCheap($county);
  1500.         $response = new Response();
  1501.         $result $this->paginatedListing(
  1502.             $city,
  1503.             null,
  1504.             [],
  1505.             $specs->spec(),
  1506.             null,
  1507.             null,
  1508.             $response
  1509.         );
  1510.         $request->attributes->set('profiles_count'$result->totalCount());
  1511.         return $this->render('ProfileList/list.html.twig', [
  1512.             'profiles' => $result,
  1513.             'source' => $this->source,
  1514.             'source_default' => self::RESULT_SOURCE_CHEAP,
  1515.             'county' => $county,
  1516.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1517.                 'city' => $city->getUriIdentity(),
  1518.                 'county' => $county->getUriIdentity(),
  1519.                 'page' => $this->getCurrentPageNumber(),
  1520.             ]),
  1521.             'recommendationSpec' => $specs->recommendationSpec(),
  1522.         ], response$response);
  1523.     }
  1524.     /**
  1525.      * @Feature("extra_category_cheap")
  1526.      */
  1527.     #[ParamConverter("city"converter"city_converter")]
  1528.     #[Entity("district"expr"repository.ofUriIdentityWithinCity(district, city)")]
  1529.     public function listByDistrictCheap(Request $requestCity $cityDistrict $district): Response
  1530.     {
  1531.         if (!$city->hasDistrict($district)) {
  1532.             throw $this->createNotFoundException();
  1533.         }
  1534.         $specs $this->profileListSpecificationService->listByDistrictCheap($district);
  1535.         $response = new Response();
  1536.         $result $this->paginatedListing(
  1537.             $city,
  1538.             null,
  1539.             [],
  1540.             $specs->spec(),
  1541.             null,
  1542.             null,
  1543.             $response
  1544.         );
  1545.         $request->attributes->set('profiles_count'$result->totalCount());
  1546.         return $this->render('ProfileList/list.html.twig', [
  1547.             'profiles' => $result,
  1548.             'source' => $this->source,
  1549.             'source_default' => self::RESULT_SOURCE_CHEAP,
  1550.             'district' => $district,
  1551.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1552.                 'city' => $city->getUriIdentity(),
  1553.                 'district' => $district->getUriIdentity(),
  1554.                 'page' => $this->getCurrentPageNumber(),
  1555.             ]),
  1556.             'recommendationSpec' => $specs->recommendationSpec(),
  1557.         ], response$response);
  1558.     }
  1559.     /**
  1560.      * @Feature("extra_category_cheap")
  1561.      */
  1562.     #[ParamConverter("city"converter"city_converter")]
  1563.     #[Entity("station"expr"repository.ofUriIdentityWithinCity(station, city)")]
  1564.     public function listByStationCheap(Request $requestCity $cityStation $station): Response
  1565.     {
  1566.         if (!$city->hasStation($station)) {
  1567.             throw $this->createNotFoundException();
  1568.         }
  1569.         $specs $this->profileListSpecificationService->listByStationCheap($station);
  1570.         $response = new Response();
  1571.         $result $this->paginatedListing(
  1572.             $city,
  1573.             null,
  1574.             [],
  1575.             $specs->spec(),
  1576.             null,
  1577.             null,
  1578.             $response
  1579.         );
  1580.         $request->attributes->set('profiles_count'$result->totalCount());
  1581.         return $this->render('ProfileList/list.html.twig', [
  1582.             'profiles' => $result,
  1583.             'source' => $this->source,
  1584.             'source_default' => self::RESULT_SOURCE_CHEAP,
  1585.             'station' => $station,
  1586.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1587.                 'city' => $city->getUriIdentity(),
  1588.                 'station' => $station->getUriIdentity(),
  1589.                 'page' => $this->getCurrentPageNumber(),
  1590.             ]),
  1591.             'recommendationSpec' => $specs->recommendationSpec(),
  1592.         ], response$response);
  1593.     }
  1594.     /**
  1595.      * @Feature("extra_category_mature")
  1596.      */
  1597.     #[ParamConverter("city"converter"city_converter")]
  1598.     #[Entity("county"expr"repository.ofUriIdentityWithinCity(county, city)")]
  1599.     public function listByCountyMature(Request $requestCity $cityCounty $county): Response
  1600.     {
  1601.         if (!$city->hasCounty($county)) {
  1602.             throw $this->createNotFoundException();
  1603.         }
  1604.         $specs $this->profileListSpecificationService->listByCountyMature($county);
  1605.         $response = new Response();
  1606.         $result $this->paginatedListing(
  1607.             $city,
  1608.             null,
  1609.             [],
  1610.             $specs->spec(),
  1611.             null,
  1612.             null,
  1613.             $response
  1614.         );
  1615.         $request->attributes->set('profiles_count'$result->totalCount());
  1616.         return $this->render('ProfileList/list.html.twig', [
  1617.             'profiles' => $result,
  1618.             'source' => $this->source,
  1619.             'source_default' => self::RESULT_SOURCE_MATURE,
  1620.             'county' => $county,
  1621.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1622.                 'city' => $city->getUriIdentity(),
  1623.                 'county' => $county->getUriIdentity(),
  1624.                 'page' => $this->getCurrentPageNumber(),
  1625.             ]),
  1626.             'recommendationSpec' => $specs->recommendationSpec(),
  1627.         ], response$response);
  1628.     }
  1629.     /**
  1630.      * @Feature("extra_category_mature")
  1631.      */
  1632.     #[ParamConverter("city"converter"city_converter")]
  1633.     #[Entity("district"expr"repository.ofUriIdentityWithinCity(district, city)")]
  1634.     public function listByDistrictMature(Request $requestCity $cityDistrict $district): Response
  1635.     {
  1636.         if (!$city->hasDistrict($district)) {
  1637.             throw $this->createNotFoundException();
  1638.         }
  1639.         $specs $this->profileListSpecificationService->listByDistrictMature($district);
  1640.         $response = new Response();
  1641.         $result $this->paginatedListing(
  1642.             $city,
  1643.             null,
  1644.             [],
  1645.             $specs->spec(),
  1646.             null,
  1647.             null,
  1648.             $response
  1649.         );
  1650.         $request->attributes->set('profiles_count'$result->totalCount());
  1651.         return $this->render('ProfileList/list.html.twig', [
  1652.             'profiles' => $result,
  1653.             'source' => $this->source,
  1654.             'source_default' => self::RESULT_SOURCE_MATURE,
  1655.             'district' => $district,
  1656.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1657.                 'city' => $city->getUriIdentity(),
  1658.                 'district' => $district->getUriIdentity(),
  1659.                 'page' => $this->getCurrentPageNumber(),
  1660.             ]),
  1661.             'recommendationSpec' => $specs->recommendationSpec(),
  1662.         ], response$response);
  1663.     }
  1664.     /**
  1665.      * @Feature("extra_category_mature")
  1666.      */
  1667.     #[ParamConverter("city"converter"city_converter")]
  1668.     #[Entity("station"expr"repository.ofUriIdentityWithinCity(station, city)")]
  1669.     public function listByStationMature(Request $requestCity $cityStation $station): Response
  1670.     {
  1671.         if (!$city->hasStation($station)) {
  1672.             throw $this->createNotFoundException();
  1673.         }
  1674.         $specs $this->profileListSpecificationService->listByStationMature($station);
  1675.         $response = new Response();
  1676.         $result $this->paginatedListing(
  1677.             $city,
  1678.             null,
  1679.             [],
  1680.             $specs->spec(),
  1681.             null,
  1682.             null,
  1683.             $response
  1684.         );
  1685.         $request->attributes->set('profiles_count'$result->totalCount());
  1686.         return $this->render('ProfileList/list.html.twig', [
  1687.             'profiles' => $result,
  1688.             'source' => $this->source,
  1689.             'source_default' => self::RESULT_SOURCE_MATURE,
  1690.             'station' => $station,
  1691.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1692.                 'city' => $city->getUriIdentity(),
  1693.                 'station' => $station->getUriIdentity(),
  1694.                 'page' => $this->getCurrentPageNumber(),
  1695.             ]),
  1696.             'recommendationSpec' => $specs->recommendationSpec(),
  1697.         ], response$response);
  1698.     }
  1699.     /**
  1700.      * @Feature("extra_category_uzbek")
  1701.      */
  1702.     #[ParamConverter("city"converter"city_converter")]
  1703.     #[Entity("county"expr"repository.ofUriIdentityWithinCity(county, city)")]
  1704.     public function listByCountyUzbek(Request $requestCity $cityCounty $county): Response
  1705.     {
  1706.         if (!$city->hasCounty($county)) {
  1707.             throw $this->createNotFoundException();
  1708.         }
  1709.         $specs $this->profileListSpecificationService->listByCountyUzbek($county);
  1710.         $response = new Response();
  1711.         $result $this->paginatedListing(
  1712.             $city,
  1713.             '/city/{city}/county/{county}/uzbechki',
  1714.             ['city' => $city->getId(), 'county' => $county->getId()],
  1715.             $specs->spec(),
  1716.             null,
  1717.             null,
  1718.             $response
  1719.         );
  1720.         $request->attributes->set('profiles_count'$result->totalCount());
  1721.         return $this->render('ProfileList/list.html.twig', [
  1722.             'profiles' => $result,
  1723.             'source' => $this->source,
  1724.             'source_default' => self::RESULT_SOURCE_UZBEK,
  1725.             'county' => $county,
  1726.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1727.                 'city' => $city->getUriIdentity(),
  1728.                 'county' => $county->getUriIdentity(),
  1729.                 'page' => $this->getCurrentPageNumber(),
  1730.             ]),
  1731.             'recommendationSpec' => $specs->recommendationSpec(),
  1732.         ], response$response);
  1733.     }
  1734.     /**
  1735.      * @Feature("extra_category_uzbek")
  1736.      */
  1737.     #[ParamConverter("city"converter"city_converter")]
  1738.     #[Entity("district"expr"repository.ofUriIdentityWithinCity(district, city)")]
  1739.     public function listByDistrictUzbek(Request $requestCity $cityDistrict $district): Response
  1740.     {
  1741.         if (!$city->hasDistrict($district)) {
  1742.             throw $this->createNotFoundException();
  1743.         }
  1744.         $specs $this->profileListSpecificationService->listByDistrictUzbek($district);
  1745.         $response = new Response();
  1746.         $result $this->paginatedListing(
  1747.             $city,
  1748.             '/city/{city}/district/{district}/uzbechki',
  1749.             ['city' => $city->getId(), 'district' => $district->getId()],
  1750.             $specs->spec(),
  1751.             null,
  1752.             null,
  1753.             $response
  1754.         );
  1755.         $request->attributes->set('profiles_count'$result->totalCount());
  1756.         return $this->render('ProfileList/list.html.twig', [
  1757.             'profiles' => $result,
  1758.             'source' => $this->source,
  1759.             'source_default' => self::RESULT_SOURCE_UZBEK,
  1760.             'district' => $district,
  1761.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1762.                 'city' => $city->getUriIdentity(),
  1763.                 'district' => $district->getUriIdentity(),
  1764.                 'page' => $this->getCurrentPageNumber(),
  1765.             ]),
  1766.             'recommendationSpec' => $specs->recommendationSpec(),
  1767.         ], response$response);
  1768.     }
  1769.     /**
  1770.      * @Feature("extra_category_uzbek")
  1771.      */
  1772.     #[ParamConverter("city"converter"city_converter")]
  1773.     #[Entity("station"expr"repository.ofUriIdentityWithinCity(station, city)")]
  1774.     public function listByStationUzbek(Request $requestCity $cityStation $station): Response
  1775.     {
  1776.         if (!$city->hasStation($station)) {
  1777.             throw $this->createNotFoundException();
  1778.         }
  1779.         $specs $this->profileListSpecificationService->listByStationUzbek($station);
  1780.         $response = new Response();
  1781.         $result $this->paginatedListing(
  1782.             $city,
  1783.             '/city/{city}/station/{station}/uzbechki',
  1784.             ['city' => $city->getId(), 'station' => $station->getId()],
  1785.             $specs->spec(),
  1786.             null,
  1787.             null,
  1788.             $response
  1789.         );
  1790.         $request->attributes->set('profiles_count'$result->totalCount());
  1791.         return $this->render('ProfileList/list.html.twig', [
  1792.             'profiles' => $result,
  1793.             'source' => $this->source,
  1794.             'source_default' => self::RESULT_SOURCE_UZBEK,
  1795.             'station' => $station,
  1796.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1797.                 'city' => $city->getUriIdentity(),
  1798.                 'station' => $station->getUriIdentity(),
  1799.                 'page' => $this->getCurrentPageNumber(),
  1800.             ]),
  1801.             'recommendationSpec' => $specs->recommendationSpec(),
  1802.         ], response$response);
  1803.     }
  1804.     #[ParamConverter("city"converter"city_converter")]
  1805.     #[Route("/api/profiles/listing/city/{city}/price/{priceType}"name"api.profile_listing.by_price"methods"GET"format"json")]
  1806.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1807.     #[OA\Tag(name"ProfileListing")]
  1808.     #[OA\Response(
  1809.         response200,
  1810.         description'',
  1811.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1812.     )]
  1813.     public function listByPrice(Request $requestCountryCurrencyResolver $countryCurrencyResolverCity $citystring $priceTypeint $minPrice nullint $maxPrice null): Response
  1814.     {
  1815.         $specs $this->profileListSpecificationService->listByPrice($city$priceType$minPrice$maxPrice);
  1816.         $response = new Response();
  1817.         $apiEndpoint in_array($priceType, ['low''high''elite']) ? '/city/{city}/price/'.$priceType null;
  1818.         $result $this->paginatedListing($city$apiEndpoint, ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1819.         $prevCount $result->count();
  1820.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  1821.             $result $this->processListByPriceEmptyResult($result$city$priceType$minPrice$maxPrice);
  1822.         }
  1823.         if ($result->count() > $prevCount) {
  1824.             $response?->setMaxAge(60);
  1825.         }
  1826.         if ($this->isApiRequest($request)) {
  1827.             return $this->json($result);
  1828.         }
  1829.         return $this->render('ProfileList/list.html.twig', [
  1830.             'profiles' => $result,
  1831.             'source' => $this->source,
  1832.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  1833.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1834.                 'city' => $city->getUriIdentity(),
  1835.                 'priceType' => $priceType,
  1836.                 'minPrice' => $minPrice,
  1837.                 'maxPrice' => $maxPrice,
  1838.                 'page' => $this->getCurrentPageNumber()
  1839.             ]),
  1840.             'recommendationSpec' => $specs->recommendationSpec(),
  1841.         ], response$response);
  1842.     }
  1843.     private function processListByPriceEmptyResult(Page $resultCity $citystring $priceTypeint $minPrice nullint $maxPrice null)
  1844.     {
  1845.         if (!$this->features->fill_empty_profile_list())
  1846.             return $result;
  1847.         $this->source self::RESULT_SOURCE_BY_PARAMS;
  1848.         if ($this->countryCurrencyResolver->getCurrencyFor($city->getCountryCode()) == 'RUB') {
  1849.             if ($minPrice && $maxPrice) {
  1850.                 if ($minPrice == 2000 && $maxPrice == 3000) {
  1851.                     $priceSpec = [
  1852.                         ProfileWithApartmentsOneHourPrice::range(15002000),
  1853.                         ProfileWithApartmentsOneHourPrice::range(30004000),
  1854.                     ];
  1855.                 } else if ($minPrice == 3000 && $maxPrice == 4000) {
  1856.                     $priceSpec = [
  1857.                         ProfileWithApartmentsOneHourPrice::range(20003000),
  1858.                         ProfileWithApartmentsOneHourPrice::range(40005000),
  1859.                     ];
  1860.                 } else if ($minPrice == 4000 && $maxPrice == 5000) {
  1861.                     $priceSpec = [
  1862.                         ProfileWithApartmentsOneHourPrice::range(30004000),
  1863.                         ProfileWithApartmentsOneHourPrice::range(50006000),
  1864.                     ];
  1865.                 } else if ($minPrice == 5000 && $maxPrice == 6000) {
  1866.                     $priceSpec = [
  1867.                         ProfileWithApartmentsOneHourPrice::range(4000999999)
  1868.                     ];
  1869.                 } else {
  1870.                     $priceSpec = [
  1871.                         ProfileWithApartmentsOneHourPrice::range($minPrice$maxPrice)
  1872.                     ];
  1873.                 }
  1874.                 $result $this->listRandomSinglePage($citynullnull$priceSpectruefalse);
  1875.             } elseif ($maxPrice) {
  1876.                 if ($maxPrice == 500) {
  1877.                     $priceSpec ProfileWithApartmentsOneHourPrice::cheaperThan(1500);
  1878.                     $result $this->listRandomSinglePage($citynull$priceSpecnulltruefalse);
  1879.                     if ($result->count() == 0) {
  1880.                         $priceSpec ProfileWithApartmentsOneHourPrice::range(15002000);
  1881.                         $result $this->listRandomSinglePage($citynull$priceSpecnulltruefalse);
  1882.                     }
  1883.                 } else if ($maxPrice == 1500) {
  1884.                     $priceSpec ProfileWithApartmentsOneHourPrice::range(15002000);
  1885.                     $result $this->listRandomSinglePage($citynull$priceSpecnulltruefalse);
  1886.                     if ($result->count() == 0) {
  1887.                         $priceSpec ProfileWithApartmentsOneHourPrice::range(20003000);
  1888.                         $result $this->listRandomSinglePage($citynull$priceSpecnulltruefalse);
  1889.                     }
  1890.                 }
  1891.             } else {
  1892.                 $priceThresholds = new ProfilePriceThresholds($city->getCityPriceCategory(), 'RUB');
  1893.                 switch ($priceType) {
  1894.                     case 'not_expensive':
  1895.                         $priceSpec ProfileWithApartmentsOneHourPrice::cheaperThan(2000);
  1896.                         break;
  1897.                     case 'high':
  1898.                         $priceSpec ProfileWithApartmentsOneHourPrice::range(
  1899.                             $priceThresholds->highMinPrice(),
  1900.                             $priceThresholds->highMaxPrice()
  1901.                         );
  1902.                         break;
  1903.                     case 'low':
  1904.                         $priceSpec ProfileWithApartmentsOneHourPrice::cheaperThan($priceThresholds->lowMaxPrice());
  1905.                         break;
  1906.                     case 'elite':
  1907.                         $priceSpec ProfileWithApartmentsOneHourPrice::moreExpensiveThan($priceThresholds->eliteMinPrice());
  1908.                         break;
  1909.                     default:
  1910.                         throw new \LogicException('Unknown price type');
  1911.                         break;
  1912.                 }
  1913.                 $result $this->listRandomSinglePage($citynull$priceSpecnulltruefalse);
  1914.             }
  1915.         }
  1916.         $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  1917.         return $result;
  1918.     }
  1919.     #[ParamConverter("city"converter"city_converter")]
  1920.     #[Route("/api/profiles/listing/city/{city}/age/{ageType}"name"api.profile_listing.by_age"methods"GET"format"json")]
  1921.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1922.     #[OA\Tag(name"ProfileListing")]
  1923.     #[OA\Response(
  1924.         response200,
  1925.         description'',
  1926.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1927.     )]
  1928.     public function listByAge(Request $requestCity $citystring $ageTypeint $minAge nullint $maxAge null): Response
  1929.     {
  1930.         $specs $this->profileListSpecificationService->listByAge($ageType$minAge$maxAge);
  1931.         $response = new Response();
  1932.         $apiEndpoint in_array($ageType, ['young''old']) ? '/city/{city}/age/'.$ageType null;
  1933.         $result $this->paginatedListing($city$apiEndpoint, ['city' => $city->getId()], $specs->spec(), nullnull$response);
  1934.         $prevCount $result->count();
  1935.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  1936.             $filled $this->processListByAgeEmptyResult($result$city$ageType$minAge$maxAge);
  1937.             if ($filled)
  1938.                 $result $filled;
  1939.         }
  1940.         if ($result->count() > $prevCount) {
  1941.             $response?->setMaxAge(60);
  1942.         }
  1943.         if ($this->isApiRequest($request)) {
  1944.             return $this->json($result);
  1945.         }
  1946.         return $this->render('ProfileList/list.html.twig', [
  1947.             'profiles' => $result,
  1948.             'source' => $this->source,
  1949.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  1950.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  1951.                 'city' => $city->getUriIdentity(),
  1952.                 'ageType' => $ageType,
  1953.                 'minAge' => $minAge,
  1954.                 'maxAge' => $maxAge,
  1955.                 'page' => $this->getCurrentPageNumber()
  1956.             ]),
  1957.             'recommendationSpec' => $specs->recommendationSpec(),
  1958.         ], response$response);
  1959.     }
  1960.     private function processListByAgeEmptyResult(Page $resultCity $citystring $ageTypeint $minAge nullint $maxAge null)
  1961.     {
  1962.         if (!$this->features->fill_empty_profile_list())
  1963.             return $result;
  1964.         $this->source self::RESULT_SOURCE_BY_PARAMS;
  1965.         if (in_array($ageType, ['young''old'], true)) {
  1966.             return $result;
  1967.         }
  1968.         if ($minAge && !$maxAge) {
  1969.             $startMinAge $minAge;
  1970.             do {
  1971.                 $startMinAge -= 2;
  1972.                 $ageSpec ProfileWithAge::olderThan($startMinAge);
  1973.                 $result $this->listRandomSinglePage($citynull$ageSpecnulltruefalse);
  1974.             } while ($result->count() == && $startMinAge >= 18);
  1975.         } else if ($ageType == 'young') {
  1976.             $startMaxAge 20;
  1977.             do {
  1978.                 $startMaxAge += 2;
  1979.                 $ageSpec ProfileWithAge::youngerThan($startMaxAge);
  1980.                 $result $this->listRandomSinglePage($citynull$ageSpecnulltruefalse);
  1981.             } while ($result->count() == && $startMaxAge <= 100);
  1982.         }
  1983.         $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  1984.         return $result;
  1985.     }
  1986.     #[ParamConverter("city"converter"city_converter")]
  1987.     #[Route("/api/profiles/listing/city/{city}/height/{heightType}"name"api.profile_listing.by_height"methods"GET"format"json")]
  1988.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  1989.     #[OA\Tag(name"ProfileListing")]
  1990.     #[OA\Response(
  1991.         response200,
  1992.         description'',
  1993.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  1994.     )]
  1995.     public function listByHeight(Request $requestCity $citystring $heightType): Response
  1996.     {
  1997.         $specs $this->profileListSpecificationService->listByHeight($heightType);
  1998.         $response = new Response();
  1999.         $result $this->paginatedListing($city'/city/{city}/height/'.$heightType, ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2000.         if ($this->isApiRequest($request)) {
  2001.             return $this->json($result);
  2002.         }
  2003.         return $this->render('ProfileList/list.html.twig', [
  2004.             'profiles' => $result,
  2005.             'source' => $this->source,
  2006.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2007.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2008.                 'city' => $city->getUriIdentity(),
  2009.                 'heightType' => $heightType,
  2010.                 'page' => $this->getCurrentPageNumber()
  2011.             ]),
  2012.             'recommendationSpec' => $specs->recommendationSpec(),
  2013.         ], response$response);
  2014.     }
  2015.     #[ParamConverter("city"converter"city_converter")]
  2016.     #[Route("/api/profiles/listing/city/{city}/breasttype/{breastType}"name"api.profile_listing.by_breast_type"methods"GET"format"json")]
  2017.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2018.     #[OA\Tag(name"ProfileListing")]
  2019.     #[OA\Response(
  2020.         response200,
  2021.         description'',
  2022.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2023.     )]
  2024.     public function listByBreastType(Request $requestCity $citystring $breastType): Response
  2025.     {
  2026.         if (null === $type BreastTypes::getValueByUriIdentity($breastType)) {
  2027.             throw $this->createNotFoundException();
  2028.         }
  2029.         $specs $this->profileListSpecificationService->listByBreastType($breastType);
  2030.         $response = new Response();
  2031.         $alternativeSpec $this->getORSpecForItemsArray(BreastTypes::getList(), function($item): ProfileWithBreastType {
  2032.             return new ProfileWithBreastType($item);
  2033.         });
  2034.         $result $this->paginatedListing($city'/city/{city}/breasttype/'.$type, ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_BY_PARAMS$response);
  2035.         if ($this->isApiRequest($request)) {
  2036.             return $this->json($result);
  2037.         }
  2038.         return $this->render('ProfileList/list.html.twig', [
  2039.             'profiles' => $result,
  2040.             'source' => $this->source,
  2041.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2042.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2043.                 'city' => $city->getUriIdentity(),
  2044.                 'breastType' => $breastType,
  2045.                 'page' => $this->getCurrentPageNumber()
  2046.             ]),
  2047.             'recommendationSpec' => $specs->recommendationSpec(),
  2048.         ], response$response);
  2049.     }
  2050.     #[ParamConverter("city"converter"city_converter")]
  2051.     #[Route("/api/profiles/listing/city/{city}/haircolor/{hairColor}"name"api.profile_listing.by_haircolor"methods"GET"format"json")]
  2052.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2053.     #[OA\Tag(name"ProfileListing")]
  2054.     #[OA\Response(
  2055.         response200,
  2056.         description'',
  2057.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2058.     )]
  2059.     public function listByHairColor(Request $requestCity $citystring $hairColor): Response
  2060.     {
  2061.         if (null === $color HairColors::getValueByUriIdentity($hairColor)) {
  2062.             throw $this->createNotFoundException();
  2063.         }
  2064.         $specs $this->profileListSpecificationService->listByHairColor($hairColor);
  2065.         $response = new Response();
  2066.         $alternativeSpec $this->getORSpecForItemsArray(HairColors::getList(), function($item): ProfileWithHairColor {
  2067.             return new ProfileWithHairColor($item);
  2068.         });
  2069.         $result $this->paginatedListing($city'/city/{city}/haircolor/'.$color, ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_BY_PARAMS$response);
  2070.         if ($this->isApiRequest($request)) {
  2071.             return $this->json($result);
  2072.         }
  2073.         return $this->render('ProfileList/list.html.twig', [
  2074.             'profiles' => $result,
  2075.             'source' => $this->source,
  2076.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2077.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2078.                 'city' => $city->getUriIdentity(),
  2079.                 'hairColor' => $hairColor,
  2080.                 'page' => $this->getCurrentPageNumber()
  2081.             ]),
  2082.             'recommendationSpec' => $specs->recommendationSpec(),
  2083.         ], response$response);
  2084.     }
  2085.     #[ParamConverter("city"converter"city_converter")]
  2086.     #[Route("/api/profiles/listing/city/{city}/bodytype/{bodyType}"name"api.profile_listing.by_bodytype"methods"GET"format"json")]
  2087.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2088.     #[OA\Tag(name"ProfileListing")]
  2089.     #[OA\Response(
  2090.         response200,
  2091.         description'',
  2092.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2093.     )]
  2094.     public function listByBodyType(Request $requestCity $citystring $bodyType): Response
  2095.     {
  2096.         if (null === $type BodyTypes::getValueByUriIdentity($bodyType)) {
  2097.             throw $this->createNotFoundException();
  2098.         }
  2099.         $specs $this->profileListSpecificationService->listByBodyType($bodyType);
  2100.         $response = new Response();
  2101.         $alternativeSpec $this->getORSpecForItemsArray(BodyTypes::getList(), function($item): ProfileWithBodyType {
  2102.             return new ProfileWithBodyType($item);
  2103.         });
  2104.         $result $this->paginatedListing($city'/city/{city}/bodytype/'.$type, ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_BY_PARAMS$response);
  2105.         if ($this->isApiRequest($request)) {
  2106.             return $this->json($result);
  2107.         }
  2108.         return $this->render('ProfileList/list.html.twig', [
  2109.             'profiles' => $result,
  2110.             'source' => $this->source,
  2111.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2112.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2113.                 'city' => $city->getUriIdentity(),
  2114.                 'bodyType' => $bodyType,
  2115.                 'page' => $this->getCurrentPageNumber()
  2116.             ]),
  2117.             'recommendationSpec' => $specs->recommendationSpec(),
  2118.         ], response$response);
  2119.     }
  2120.     #[ParamConverter("city"converter"city_converter")]
  2121.     #[Route("/api/profiles/listing/city/{city}/place/{placeType}"name"api.profile_listing.by_place"methods"GET"format"json")]
  2122.     #[Route("/api/profiles/listing/city/{city}/place/{placeType}/{takeOutLocation}"name"api.profile_listing.by_place.take_out_location"methods"GET"format"json")]
  2123.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2124.     #[OA\Tag(name"ProfileListing")]
  2125.     #[OA\Response(
  2126.         response200,
  2127.         description'',
  2128.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2129.     )]
  2130.     public function listByPlace(Request $requestCity $citystring $placeTypestring $takeOutLocation null): Response
  2131.     {
  2132.         if ('take-out' === $placeType && null !== $takeOutLocation && null === TakeOutLocations::getValueByUriIdentity($takeOutLocation)) {
  2133.             throw $this->createNotFoundException();
  2134.         }
  2135.         $specs $this->profileListSpecificationService->listByPlace($placeType$takeOutLocation);
  2136.         if (null === $specs) {
  2137.             throw $this->createNotFoundException();
  2138.         }
  2139.         $response = new Response();
  2140.         $alternativeSpec $this->getORSpecForItemsArray(TakeOutLocations::getList(), function($item): ProfileIsProvidingTakeOut {
  2141.             return new ProfileIsProvidingTakeOut($item);
  2142.         });
  2143.         if ($placeType === 'take-out') {
  2144.             $alternativeSpec->orX(new ProfileHasApartments());
  2145.         }
  2146.         $apiEndpoint '/city/{city}/place/'.$placeType;
  2147.         if (null !== $takeOutLocation) {
  2148.             $apiEndpoint .= '/'.$takeOutLocation;
  2149.         }
  2150.         $result $this->paginatedListing($city$apiEndpoint, ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_BY_PARAMS$response);
  2151.         if ($this->isApiRequest($request)) {
  2152.             return $this->json($result);
  2153.         }
  2154.         return $this->render('ProfileList/list.html.twig', [
  2155.             'profiles' => $result,
  2156.             'source' => $this->source,
  2157.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2158.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2159.                 'city' => $city->getUriIdentity(),
  2160.                 'placeType' => $placeType,
  2161.                 'takeOutLocation' => TakeOutLocations::getUriIdentity(TakeOutLocations::getValueByUriIdentity($takeOutLocation)),
  2162.                 'page' => $this->getCurrentPageNumber()
  2163.             ]),
  2164.             'recommendationSpec' => $specs->recommendationSpec(),
  2165.         ], response$response);
  2166.     }
  2167.     #[ParamConverter("city"converter"city_converter")]
  2168.     #[Route("/api/profiles/listing/city/{city}/privatehaircut/{privateHaircut}"name"api.profile_listing.by_privatehaircut"methods"GET"format"json")]
  2169.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2170.     #[OA\Tag(name"ProfileListing")]
  2171.     #[OA\Response(
  2172.         response200,
  2173.         description'',
  2174.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2175.     )]
  2176.     public function listByPrivateHaircut(Request $requestCity $citystring $privateHaircut): Response
  2177.     {
  2178.         if(null === $type PrivateHaircuts::getValueByUriIdentity($privateHaircut))
  2179.             throw $this->createNotFoundException();
  2180.         $specs $this->profileListSpecificationService->listByPrivateHaircut($privateHaircut);
  2181.         $response = new Response();
  2182.         $apiEndpoint '/city/{city}/privatehaircut/'.$type;
  2183.         $alternativeSpec $this->getORSpecForItemsArray(PrivateHaircuts::getList(), function($item): ProfileWithPrivateHaircut {
  2184.             return new ProfileWithPrivateHaircut($item);
  2185.         });
  2186.         $result $this->paginatedListing($city$apiEndpoint, ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_BY_PARAMS$response);
  2187.         if ($this->isApiRequest($request)) {
  2188.             return $this->json($result);
  2189.         }
  2190.         return $this->render('ProfileList/list.html.twig', [
  2191.             'profiles' => $result,
  2192.             'source' => $this->source,
  2193.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2194.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2195.                 'city' => $city->getUriIdentity(),
  2196.                 'privateHaircut' => $privateHaircut,
  2197.                 'page' => $this->getCurrentPageNumber()
  2198.             ]),
  2199.             'recommendationSpec' => $specs->recommendationSpec(),
  2200.         ], response$response);
  2201.     }
  2202.     #[ParamConverter("city"converter"city_converter")]
  2203.     #[Route("/api/profiles/listing/city/{city}/nationality/{nationality}"name"api.profile_listing.by_nationality"methods"GET"format"json")]
  2204.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2205.     #[OA\Tag(name"ProfileListing")]
  2206.     #[OA\Response(
  2207.         response200,
  2208.         description'',
  2209.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2210.     )]
  2211.     public function listByNationality(Request $requestCity $citystring $nationality): Response
  2212.     {
  2213.         if (null === $type Nationalities::getValueByUriIdentity($nationality))
  2214.             throw $this->createNotFoundException();
  2215.         $specs $this->profileListSpecificationService->listByNationality($nationality);
  2216.         $response = new Response();
  2217.         $alternativeSpec $this->getORSpecForItemsArray(Nationalities::getList(), function($item): ProfileWithNationality {
  2218.             return new ProfileWithNationality($item);
  2219.         });
  2220.         $apiEndpoint '/city/{city}/nationality/'.$type;
  2221.         $result $this->paginatedListing($city$apiEndpoint, ['city' => $city->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_BY_PARAMS$response);
  2222.         if ($this->isApiRequest($request)) {
  2223.             return $this->json($result);
  2224.         }
  2225.         return $this->render('ProfileList/list.html.twig', [
  2226.             'profiles' => $result,
  2227.             'source' => $this->source,
  2228.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2229.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2230.                 'city' => $city->getUriIdentity(),
  2231.                 'nationality' => $nationality,
  2232.                 'page' => $this->getCurrentPageNumber()
  2233.             ]),
  2234.             'recommendationSpec' => $specs->recommendationSpec(),
  2235.         ], response$response);
  2236.     }
  2237.     #[ParamConverter("city"converter"city_converter")]
  2238.     #[ParamConverter("service"options: ['mapping' => ['service' => 'uriIdentity']])]
  2239.     #[Route("/api/profiles/listing/city/{city}/service/{service}"name"api.profile_listing.by_service"methods"GET"format"json")]
  2240.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2241.     #[OA\Tag(name"ProfileListing")]
  2242.     #[OA\Response(
  2243.         response200,
  2244.         description'',
  2245.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2246.     )]
  2247.     public function listByProvidedService(Request $requestCity $cityService $service): Response
  2248.     {
  2249.         $specs $this->profileListSpecificationService->listByProvidedService($service$city);
  2250.         $response = new Response();
  2251.         $sameGroupServices $this->serviceRepository->findBy(['group' => $service->getGroup()]);
  2252.         $alternativeSpec $this->getORSpecForItemsArray([$sameGroupServices], function($item): ProfileIsProvidingOneOfServices {
  2253.             return new ProfileIsProvidingOneOfServices($item);
  2254.         });
  2255.         $result $this->paginatedListing($city'/city/{city}/service/{service}', ['city' => $city->getId(), 'service' => $service->getId()], $specs->spec(), $alternativeSpecself::RESULT_SOURCE_SERVICE$response);
  2256.         if ($this->isApiRequest($request)) {
  2257.             return $this->json($result);
  2258.         }
  2259.         return $this->render('ProfileList/list.html.twig', [
  2260.             'profiles' => $result,
  2261.             'source' => $this->source,
  2262.             'source_default' => self::RESULT_SOURCE_SERVICE,
  2263.             'service' => $service,
  2264.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2265.                 'city' => $city->getUriIdentity(),
  2266.                 'service' => $service->getUriIdentity(),
  2267.                 'page' => $this->getCurrentPageNumber()
  2268.             ]),
  2269.             'recommendationSpec' => $specs->recommendationSpec(),
  2270.         ], response$response);
  2271.     }
  2272.     /**
  2273.      * @Feature("has_archive_page")
  2274.      */
  2275.     #[ParamConverter("city"converter"city_converter")]
  2276.     #[Route("/api/profiles/listing/city/{city}/archive"name"api.profile_listing.archive"methods"GET"format"json")]
  2277.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2278.     #[OA\Tag(name"ProfileListing")]
  2279.     #[OA\Response(
  2280.         response200,
  2281.         description'',
  2282.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2283.     )]
  2284.     public function listArchived(Request $requestCity $city): Response
  2285.     {
  2286.         $result $this->profileList->list($citynullnullnullfalsenullProfileList::ORDER_BY_UPDATED);
  2287.         if ($this->isApiRequest($request)) {
  2288.             return $this->json($result);
  2289.         }
  2290.         return $this->render('ProfileList/list.html.twig', [
  2291.             'profiles' => $result,
  2292.             'recommendationSpec' => new \App\Specification\ElasticSearch\ProfileIsNotArchived(), //ProfileIsArchived, согласно https://redminez.net/issues/28305 в реках выводятся неарзивные
  2293.         ]);
  2294.     }
  2295.     #[ParamConverter("city"converter"city_converter")]
  2296.     #[Route("/api/profiles/listing/city/{city}/recent"name"api.profile_listing.recent"methods"GET"format"json")]
  2297.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2298.     #[OA\Tag(name"ProfileListing")]
  2299.     #[OA\Response(
  2300.         response200,
  2301.         description'',
  2302.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2303.     )]
  2304.     public function listNew(Request $requestCity $cityint $weeks 2): Response
  2305.     {
  2306.         $specs $this->profileListSpecificationService->listNew($weeks);
  2307.         $response = new Response();
  2308.         $result $this->paginatedListing($city'/city/{city}/recent', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  2309.         if ($this->isApiRequest($request)) {
  2310.             return $this->json($result);
  2311.         }
  2312.         return $this->render('ProfileList/list.html.twig', [
  2313.             'profiles' => $result,
  2314.             'recommendationSpec' => $specs->recommendationSpec(),
  2315.         ], response$response);
  2316.     }
  2317.     #[ParamConverter("city"converter"city_converter")]
  2318.     #[Route("/api/profiles/listing/city/{city}/noretouch"name"api.profile_listing.noretouch"methods"GET"format"json")]
  2319.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2320.     #[OA\Tag(name"ProfileListing")]
  2321.     #[OA\Response(
  2322.         response200,
  2323.         description'',
  2324.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2325.     )]
  2326.     public function listByNoRetouch(Request $requestCity $city): Response
  2327.     {
  2328.         $specs $this->profileListSpecificationService->listByNoRetouch();
  2329.         $response = new Response();
  2330.         $result $this->paginatedListing($city'/city/{city}/noretouch', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2331.         if ($this->isApiRequest($request)) {
  2332.             return $this->json($result);
  2333.         }
  2334.         return $this->render('ProfileList/list.html.twig', [
  2335.             'profiles' => $result,
  2336.             'profiles_count' => $result->count(),
  2337.             'source' => $this->source,
  2338.             'recommendationSpec' => $specs->recommendationSpec(),
  2339.         ], response$response);
  2340.     }
  2341.     #[ParamConverter("city"converter"city_converter")]
  2342.     #[Route("/api/profiles/listing/city/{city}/nice"name"api.profile_listing.nice"methods"GET"format"json")]
  2343.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2344.     #[OA\Tag(name"ProfileListing")]
  2345.     #[OA\Response(
  2346.         response200,
  2347.         description'',
  2348.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2349.     )]
  2350.     public function listByNice(Request $requestCity $city): Response
  2351.     {
  2352.         $specs $this->profileListSpecificationService->listByNice();
  2353.         $response = new Response();
  2354.         $result $this->paginatedListing($city'/city/{city}/nice', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2355.         if ($this->isApiRequest($request)) {
  2356.             return $this->json($result);
  2357.         }
  2358.         return $this->render('ProfileList/list.html.twig', [
  2359.             'profiles' => $result,
  2360.             'source' => $this->source,
  2361.             'recommendationSpec' => $specs->recommendationSpec(),
  2362.         ], response$response);
  2363.     }
  2364.     #[ParamConverter("city"converter"city_converter")]
  2365.     #[Route("/api/profiles/listing/city/{city}/oncall"name"api.profile_listing.oncall"methods"GET"format"json")]
  2366.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2367.     #[OA\Tag(name"ProfileListing")]
  2368.     #[OA\Response(
  2369.         response200,
  2370.         description'',
  2371.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2372.     )]
  2373.     public function listByOnCall(Request $requestCity $city): Response
  2374.     {
  2375.         $specs $this->profileListSpecificationService->listByOnCall();
  2376.         $response = new Response();
  2377.         $result $this->paginatedListing($city'/city/{city}/oncall', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2378.         if ($this->isApiRequest($request)) {
  2379.             return $this->json($result);
  2380.         }
  2381.         return $this->render('ProfileList/list.html.twig', [
  2382.             'profiles' => $result,
  2383.             'source' => $this->source,
  2384.             'recommendationSpec' => $specs->recommendationSpec(),
  2385.         ], response$response);
  2386.     }
  2387.     #[ParamConverter("city"converter"city_converter")]
  2388.     #[Route("/api/profiles/listing/city/{city}/fornight"name"api.profile_listing.fornight"methods"GET"format"json")]
  2389.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2390.     #[OA\Tag(name"ProfileListing")]
  2391.     #[OA\Response(
  2392.         response200,
  2393.         description'',
  2394.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2395.     )]
  2396.     public function listForNight(Request $requestCity $city): Response
  2397.     {
  2398.         $specs $this->profileListSpecificationService->listForNight();
  2399.         $response = new Response();
  2400.         $result $this->paginatedListing($city'/city/{city}/fornight', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2401.         if ($this->isApiRequest($request)) {
  2402.             return $this->json($result);
  2403.         }
  2404.         return $this->render('ProfileList/list.html.twig', [
  2405.             'profiles' => $result,
  2406.             'source' => $this->source,
  2407.             'recommendationSpec' => $specs->recommendationSpec(),
  2408.         ], response$response);
  2409.     }
  2410.     private function getSpecForEliteGirls(City $city): Filter
  2411.     {
  2412.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  2413.             'RUB' => 5000,
  2414.             'UAH' => 1500,
  2415.             'USD' => 100,
  2416.             'EUR' => 130,
  2417.         ]);
  2418.         return new ProfileIsElite($minPrice);
  2419.     }
  2420.     private function getElasticSearchSpecForEliteGirls(City $city): ISpecification
  2421.     {
  2422.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  2423.             'RUB' => 5000,
  2424.             'UAH' => 1500,
  2425.             'USD' => 100,
  2426.             'EUR' => 130,
  2427.         ]);
  2428.         return new \App\Specification\ElasticSearch\ProfileIsElite($minPrice);
  2429.     }
  2430.     #[ParamConverter("city"converter"city_converter")]
  2431.     #[Route("/api/profiles/listing/city/{city}/elite"name"api.profile_listing.elite"methods"GET"format"json")]
  2432.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2433.     #[OA\Tag(name"ProfileListing")]
  2434.     #[OA\Response(
  2435.         response200,
  2436.         description'',
  2437.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2438.     )]
  2439.     public function listForEliteGirls(CountryCurrencyResolver $countryCurrencyResolverRequest $requestCity $city): Response
  2440.     {
  2441.         $specs $this->profileListSpecificationService->listForEliteGirls($city);
  2442.         $response = new Response();
  2443.         $result $this->paginatedListing($city'/city/{city}/elite', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  2444.         $prevCount $result->count();
  2445.         if ($this->features->fill_empty_profile_list() && $result->count() == 0) {
  2446.             $prices = [
  2447.                 'RUB' => 5000,
  2448.                 'UAH' => 1500,
  2449.                 'USD' => 100,
  2450.                 'EUR' => 130,
  2451.             ];
  2452.             $currency $countryCurrencyResolver->getCurrencyFor($city->getCountryCode());
  2453.             if (isset($prices[$currency])) {
  2454.                 $minPrice $prices[$currency];
  2455.                 switch ($currency) {
  2456.                     case 'RUB':
  2457.                         $diff 1000;
  2458.                         break;
  2459.                     case 'UAH':
  2460.                         $diff 500;
  2461.                         break;
  2462.                     case 'USD':
  2463.                     case 'EUR':
  2464.                         $diff 20;
  2465.                         break;
  2466.                     default:
  2467.                         throw new \LogicException('Unexpected currency code');
  2468.                 }
  2469.                 while ($minPrice >= $diff) {
  2470.                     $minPrice -= $diff;
  2471.                     $result $this->listRandomSinglePage($citynullProfileWithApartmentsOneHourPrice::moreExpensiveThan($minPrice), nulltruefalse);
  2472.                     if ($result->count() > 0) {
  2473.                         $this->source self::RESULT_SOURCE_BY_PARAMS;
  2474.                         break;
  2475.                     }
  2476.                 }
  2477.                 $result $this->checkEmptyResultNotMasseur($result$citynullself::RESULT_SOURCE_CITY);
  2478.             }
  2479.         }
  2480.         if ($result->count() > $prevCount) {
  2481.             $response?->setMaxAge(60);
  2482.         }
  2483.         if ($this->isApiRequest($request)) {
  2484.             return $this->json($result);
  2485.         }
  2486.         return $this->render('ProfileList/list.html.twig', [
  2487.             'profiles' => $result,
  2488.             'source' => $this->source,
  2489.             'source_default' => self::RESULT_SOURCE_BY_PARAMS,
  2490.             'category_url' => $this->generateUrl($request->attributes->get('_route'), [
  2491.                 'city' => $city->getUriIdentity(),
  2492.                 'page' => $this->getCurrentPageNumber()
  2493.             ]),
  2494.             'recommendationSpec' => $specs->recommendationSpec(),
  2495.         ], response$response);
  2496.     }
  2497.     #[ParamConverter("city"converter"city_converter")]
  2498.     #[Route("/api/profiles/listing/city/{city}/realelite"name"api.profile_listing.real_elite"methods"GET"format"json")]
  2499.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2500.     #[OA\Tag(name"ProfileListing")]
  2501.     #[OA\Response(
  2502.         response200,
  2503.         description'',
  2504.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2505.     )]
  2506.     public function listForRealElite(Request $requestCountryCurrencyResolver $countryCurrencyResolverCity $city): Response
  2507.     {
  2508.         $specs $this->profileListSpecificationService->listForRealElite($city);
  2509.         $response = new Response();
  2510.         $result $this->paginatedListing($city'/city/{city}/realelite', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2511.         if ($this->isApiRequest($request)) {
  2512.             return $this->json($result);
  2513.         }
  2514.         return $this->render('ProfileList/list.html.twig', [
  2515.             'profiles' => $result,
  2516.             'source' => $this->source,
  2517.             'recommendationSpec' => $specs->recommendationSpec(),
  2518.         ], response$response);
  2519.     }
  2520.     #[ParamConverter("city"converter"city_converter")]
  2521.     #[Route("/api/profiles/listing/city/{city}/vip"name"api.profile_listing.vip"methods"GET"format"json")]
  2522.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2523.     #[OA\Tag(name"ProfileListing")]
  2524.     #[OA\Response(
  2525.         response200,
  2526.         description'',
  2527.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2528.     )]
  2529.     public function listForVipPros(Request $requestCountryCurrencyResolver $countryCurrencyResolverCity $city): Response
  2530.     {
  2531.         $specs $this->profileListSpecificationService->listForVipPros($city);
  2532.         $response = new Response();
  2533.         $result $this->paginatedListing($city'/city/{city}/vip', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2534.         if ($this->isApiRequest($request)) {
  2535.             return $this->json($result);
  2536.         }
  2537.         return $this->render('ProfileList/list.html.twig', [
  2538.             'profiles' => $result,
  2539.             'source' => $this->source,
  2540.             'recommendationSpec' => $specs->recommendationSpec(),
  2541.         ], response$response);
  2542.     }
  2543.     #[ParamConverter("city"converter"city_converter")]
  2544.     #[Route("/api/profiles/listing/city/{city}/vipindi"name"api.profile_listing.vipindi"methods"GET"format"json")]
  2545.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2546.     #[OA\Tag(name"ProfileListing")]
  2547.     #[OA\Response(
  2548.         response200,
  2549.         description'',
  2550.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2551.     )]
  2552.     public function listForVipIndividual(Request $requestCountryCurrencyResolver $countryCurrencyResolverCity $city): Response
  2553.     {
  2554.         $specs $this->profileListSpecificationService->listForVipIndividual($city);
  2555.         $response = new Response();
  2556.         $result $this->paginatedListing($city'/city/{city}/vipindi', ['city' => $city->getId()], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2557.         if ($this->isApiRequest($request)) {
  2558.             return $this->json($result);
  2559.         }
  2560.         return $this->render('ProfileList/list.html.twig', [
  2561.             'profiles' => $result,
  2562.             'source' => $this->source,
  2563.             'recommendationSpec' => $specs->recommendationSpec(),
  2564.         ], response$response);
  2565.     }
  2566.     #[ParamConverter("city"converter"city_converter")]
  2567.     #[Route("/api/profiles/listing/city/{city}/vipgirls"name"api.profile_listing.vipgirls"methods"GET"format"json")]
  2568.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2569.     #[OA\Tag(name"ProfileListing")]
  2570.     #[OA\Response(
  2571.         response200,
  2572.         description'',
  2573.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2574.     )]
  2575.     public function listForVipGirlsCity(Request $requestCity $city): Response
  2576.     {
  2577.         $specs $this->profileListSpecificationService->listForVipGirlsCity($city);
  2578.         $response = new Response();
  2579.         $result $this->paginatedListing($citynull, [], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2580.         if ($this->isApiRequest($request)) {
  2581.             return $this->json($result);
  2582.         }
  2583.         return $this->render('ProfileList/list.html.twig', [
  2584.             'profiles' => $result,
  2585.             'source' => $this->source,
  2586.             'recommendationSpec' => $specs->recommendationSpec(),
  2587.         ], response$response);
  2588.     }
  2589.     #[ParamConverter("city"converter"city_converter")]
  2590.     #[Route("/api/profiles/listing/city/{city}/girlfriends"name"api.profile_listing.girlfriends"methods"GET"format"json")]
  2591.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2592.     #[OA\Tag(name"ProfileListing")]
  2593.     #[OA\Response(
  2594.         response200,
  2595.         description'',
  2596.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2597.     )]
  2598.     public function listOfGirlfriends(Request $requestCity $city): Response
  2599.     {
  2600.         $specs $this->profileListSpecificationService->listOfGirlfriends();
  2601.         $response = new Response();
  2602.         $result $this->paginatedListing($citynull, [], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2603.         if ($this->isApiRequest($request)) {
  2604.             return $this->json($result);
  2605.         }
  2606.         return $this->render('ProfileList/list.html.twig', [
  2607.             'profiles' => $result,
  2608.             'source' => $this->source,
  2609.             'recommendationSpec' => $specs->recommendationSpec(),
  2610.         ]);
  2611.     }
  2612.     #[ParamConverter("city"converter"city_converter")]
  2613.     #[Route("/api/profiles/listing/city/{city}/most_expensive"name"api.profile_listing.most_expensive"methods"GET"format"json")]
  2614.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2615.     #[OA\Tag(name"ProfileListing")]
  2616.     #[OA\Response(
  2617.         response200,
  2618.         description'',
  2619.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2620.     )]
  2621.     public function listOfMostExpensive(Request $requestCity $city): Response
  2622.     {
  2623.         $specs $this->profileListSpecificationService->listOfMostExpensive($city);
  2624.         $response = new Response();
  2625.         $result $this->paginatedListing($citynull, [], $specs->spec(), nullself::RESULT_SOURCE_CITY$response);
  2626.         if ($this->isApiRequest($request)) {
  2627.             return $this->json($result);
  2628.         }
  2629.         return $this->render('ProfileList/list.html.twig', [
  2630.             'profiles' => $result,
  2631.             'source' => $this->source,
  2632.             'recommendationSpec' => $specs->recommendationSpec(),
  2633.         ]);
  2634.     }
  2635.     #[ParamConverter("city"converter"city_converter")]
  2636.     #[Route("/api/profiles/listing/city/{city}/bdsm"name"api.profile_listing.bdsm"methods"GET"format"json")]
  2637.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2638.     #[OA\Tag(name"ProfileListing")]
  2639.     #[OA\Response(
  2640.         response200,
  2641.         description'',
  2642.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2643.     )]
  2644.     public function listBdsm(Request $requestCity $cityServiceRepository $serviceRepositoryParameterBagInterface $parameterBag): Response
  2645.     {
  2646.         $specs $this->profileListSpecificationService->listBdsm();
  2647.         $response = new Response();
  2648.         $result $this->paginatedListing($city'/city/{city}/bdsm', ['city' => $city->getId()], $specs->spec(), nullnull$response);
  2649.         if ($this->isApiRequest($request)) {
  2650.             return $this->json($result);
  2651.         }
  2652.         return $this->render('ProfileList/list.html.twig', [
  2653.             'profiles' => $result,
  2654.             'recommendationSpec' => $specs->recommendationSpec(),
  2655.         ], response$response);
  2656.     }
  2657.     #[ParamConverter("city"converter"city_converter")]
  2658.     #[Route("/api/profiles/listing/city/{city}/gender/{gender}"name"api.profile_listing.by_gender"methods"GET"format"json")]
  2659.     #[OA\Parameter(name"page"in"query"schema: new OA\Schema(type"integer", default: 1minimum1))]
  2660.     #[OA\Tag(name"ProfileListing")]
  2661.     #[OA\Response(
  2662.         response200,
  2663.         description'',
  2664.         content: new OA\JsonContent(ref"#/components/schemas/ProfileListingPage")
  2665.     )]
  2666.     public function listByGender(Request $requestCity $citystring $genderDefaultCityProvider $defaultCityProvider): Response
  2667.     {
  2668.         if ($city->getId() != $defaultCityProvider->getDefaultCity()->getId()) {
  2669.             throw $this->createNotFoundException();
  2670.         }
  2671.         if (null === Genders::getValueByUriIdentity($gender))
  2672.             throw $this->createNotFoundException();
  2673.         $specs $this->profileListSpecificationService->listByGender($gender);
  2674.         $response = new Response();
  2675.         $result $this->paginatedListing($citynull, [], $specs->spec(), nullnull$response);
  2676.         if ($this->isApiRequest($request)) {
  2677.             return $this->json($result);
  2678.         }
  2679.         return $this->render('ProfileList/list.html.twig', [
  2680.             'profiles' => $result,
  2681.             'recommendationSpec' => $specs->recommendationSpec(),
  2682.         ]);
  2683.     }
  2684.     protected function checkCityAndCountrySource(Page $resultCity $city): Page
  2685.     {
  2686.         if (($result && $result->count() != 0) || false == $this->features->fill_empty_profile_list())
  2687.             return $result;
  2688.         $this->source self::RESULT_SOURCE_CITY;
  2689.         $result $this->listRandomSinglePage($citynullnullnulltruefalse);
  2690.         if ($result->count() == 0) {
  2691.             $this->source self::RESULT_SOURCE_COUNTRY;
  2692.             $result $this->listRandomSinglePage($city$city->getCountryCode(), nullnulltruefalse);
  2693.         }
  2694.         return $result;
  2695.     }
  2696.     protected function checkEmptyResultNotMasseur(Page $resultCity $city, ?OrX $alternativeSpecstring $source): Page
  2697.     {
  2698.         if ($result->count() != || false == $this->features->fill_empty_profile_list())
  2699.             return $result;
  2700.         if (null != $alternativeSpec) {
  2701.             $this->source $source;
  2702.             $result $this->listRandomSinglePage($citynull$alternativeSpecnulltruefalse);
  2703.         }
  2704.         if ($result->count() == 0)
  2705.             $result $this->checkCityAndCountrySource($result$city);
  2706.         return $result;
  2707.     }
  2708.     /**
  2709.      * Сейчас не используется, решили доставать их всех соседних подкатегорий разом.
  2710.      * Пока оставил, вдруг передумают.
  2711.      * @deprecated
  2712.      */
  2713.     public function listByNextSimilarCategories(callable $listMethod$requestCategory, array $similarItems): ORMQueryResult
  2714.     {
  2715.         $similarItems array_filter($similarItems, function ($item) use ($requestCategory): bool {
  2716.             return $item != $requestCategory;
  2717.         });
  2718.         //shuffle($similarItems);
  2719.         $item null;
  2720.         $result null;
  2721.         do {
  2722.             $item $item == null current($similarItems) : next($similarItems);
  2723.             if (false === $item)
  2724.                 return $result;
  2725.             $result $listMethod($item);
  2726.         } while ($result->count() == 0);
  2727.         return $result;
  2728.     }
  2729.     private function shouldShowHomepageCityListingsBlock(City $cityint $pagebool $subRequest): bool
  2730.     {
  2731.         if ($page !== 1) {
  2732.             return false;
  2733.         }
  2734.         if ($subRequest) {
  2735.             return true;
  2736.         }
  2737.         return !$city->equals($this->parameterBag->get('default_city'));
  2738.     }
  2739.     protected function getCurrentPageNumber(): int
  2740.     {
  2741.         $page = (int) $this->requestStack->getCurrentRequest()?->get($this->pageParameter1);
  2742.         if ($page 1) {
  2743.             $page 1;
  2744.         }
  2745.         return $page;
  2746.     }
  2747.     protected function render(string $view, array $parameters = [], Response $response null): Response
  2748.     {
  2749.         $this->listingService->setCurrentListingPage($parameters['profiles']);
  2750.         $requestAttrs $this->requestStack->getCurrentRequest();
  2751.         $listing $requestAttrs->get('_controller');
  2752.         $listing is_array($listing) ? $listing[count($listing) - 1] : $listing;
  2753.         $listing preg_replace('/[^:]+::/'''$listing);
  2754.         $listingParameters $requestAttrs->get('_route_params');
  2755.         $listingParameters is_array($listingParameters) ? $listingParameters : [];
  2756.         $mainRequestHasPageParam = isset(($this->requestStack->getMainRequest()->get('_route_params') ?? [])['page']);
  2757.         if ($this->requestStack->getCurrentRequest()->isXmlHttpRequest()) {
  2758.             $view = (
  2759.                 str_starts_with($listing'list')
  2760.                 && 'ProfileList/list.html.twig' === $view
  2761.                 && $mainRequestHasPageParam //isset($listingParameters['page'])
  2762.             )
  2763.                 ? 'ProfileList/list.profiles.html.twig'
  2764.                 $view;
  2765.             return $this->prepareForXhr(parent::render($view$parameters$response));
  2766.             //return $this->getJSONResponse($parameters);
  2767.         } else {
  2768.             $parameters array_merge($parameters, [
  2769.                 'listing' => $listing,
  2770.                 'listing_parameters' => $listingParameters,
  2771.             ]);
  2772.             return parent::render($view$parameters$response);
  2773.         }
  2774.     }
  2775.     private function listActiveWithinCityOrderedByStatusWithSpecAvoidingTopPlacementLimited(
  2776.         City $city,
  2777.         ?Filter $spec,
  2778.         array $additionalSpecs null,
  2779.         array $genders = [Genders::FEMALE],
  2780.         int $limit 0,
  2781.     ): array|Page {
  2782.         return $this->profileList->listActiveWithinCityOrderedByStatusWithSpecLimited($city$spec$additionalSpecs$genderstrue$limit);
  2783.     }
  2784.     private function listRandomSinglePage(
  2785.         City $city,
  2786.         ?string $country,
  2787.         ?Filter $spec,
  2788.         ?array $additionalSpecs,
  2789.         bool $active,
  2790.         ?bool $masseur false,
  2791.         array $genders = [Genders::FEMALE]
  2792.     ): Page {
  2793.         return $this->profileList->listRandom($city$country$spec$additionalSpecs$active$masseur$genderstrue);
  2794.     }
  2795.     private function shuffleProfilesOnPage(Page $result): Page
  2796.     {
  2797.         $profiles iterator_to_array($result->getIterator());
  2798.         if(count($profiles) > 1) {
  2799.             shuffle($profiles);
  2800.         }
  2801.         return new FakeORMQueryPage(
  2802.             $result->getCurrentOffset(),
  2803.             $result->getCurrentPage(),
  2804.             $result->getCurrentLimit(),
  2805.             $result->totalCount(),
  2806.             $profiles
  2807.         );
  2808.     }
  2809.     /**
  2810.      * Достает из списка анкет их id с учетом совместимости разных форматов данных
  2811.      */
  2812.     private function extractProfileIds(array $profiles): array
  2813.     {
  2814.         $ids array_map(static function ($item) {
  2815.             /**
  2816.              * - array - данные из микросервиса ротации через API
  2817.              * - Profile::getId() - полноценная сущность анкеты
  2818.              * - ProfileListingReadModel::$id - read-model анкеты
  2819.              */
  2820.             return is_array($item) ? $item['id'] : ($item?->id ?? $item?->getId());
  2821.         }, $profiles);
  2822.         return array_filter($ids); // remove null values
  2823.     }
  2824. //    protected function getJSONResponse(array $parameters)
  2825. //    {
  2826. //        $request = $this->request;
  2827. //        $data = json_decode($request->getContent(), true);
  2828. //
  2829. //        $imageSize = !empty($data['imageSize']) ? $data['imageSize'] : "357x500";
  2830. //
  2831. //        /** @var FakeORMQueryPage $queryPage */
  2832. //        $queryPage = $parameters['profiles'];
  2833. //
  2834. //        $profiles = array_map(function(ProfileListingReadModel $profile) use ($imageSize) {
  2835. //            $profile->stations = array_values($profile->stations);
  2836. //            $profile->avatar['path'] = $this->responsiveAssetsService->getResponsiveImageUrl($profile->avatar['path'], 'profile_media', $imageSize, 'jpg');
  2837. //            $profile->uri = $this->generateUrl('profile_preview.page', ['city' => $profile->city->uriIdentity, 'profile' => $profile->uriIdentity]);
  2838. //            return $profile;
  2839. //        }, $queryPage->getArray());
  2840. //
  2841. //        return new JsonResponse([
  2842. //            'profiles' => $profiles,
  2843. //            'currentPage' => $queryPage->getCurrentPage(),
  2844. //        ], Response::HTTP_OK);
  2845. //    }
  2846. }