src/Controller/ProfileListController.php line 577

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