src/Controller/ProfileListController.php line 370

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