src/Controller/ProfileListController.php line 1782

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