src/Controller/ProfileListController.php line 747

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