src/Controller/ProfileListController.php line 2356

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