src/Service/ProfileListSpecificationService.php line 102

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use App\Dto\ProfileListSpecification;
  4. use App\Entity\Location\City;
  5. use App\Entity\Location\County;
  6. use App\Entity\Location\District;
  7. use App\Entity\Location\Station;
  8. use App\Entity\Profile\BodyTypes;
  9. use App\Entity\Profile\BreastTypes;
  10. use App\Entity\Profile\Genders;
  11. use App\Entity\Profile\HairColors;
  12. use App\Entity\Profile\Nationalities;
  13. use App\Entity\Profile\PrivateHaircuts;
  14. use App\Entity\Service;
  15. use App\Entity\ServiceGroups;
  16. use App\Entity\TakeOutLocations;
  17. use App\Repository\DistrictRepository;
  18. use App\Repository\ProfileRepository;
  19. use Doctrine\ORM\EntityManagerInterface;
  20. use App\Repository\ServiceRepository;
  21. use App\Specification\ElasticSearch\ISpecification;
  22. use App\Specification\Profile\BdsmProfile;
  23. use App\Specification\Profile\ProfileAdBoardPlacement;
  24. use App\Specification\Profile\ProfileHasApartments;
  25. use App\Specification\Profile\ProfileHasComments;
  26. use App\Specification\Profile\ProfileHasHighPrice;
  27. use App\Specification\Profile\ProfileHasLowPrice;
  28. use App\Specification\Profile\ProfileHasLowPriceInLocation;
  29. use App\Specification\Profile\ProfileHasOldAgeInLocation;
  30. use App\Specification\Profile\ProfileHasOnCall;
  31. use App\Specification\Profile\ProfileHasOneOfGenders;
  32. use App\Specification\Profile\ProfileHasPriceGreaterThan;
  33. use App\Specification\Profile\ProfileHasSelfie;
  34. use App\Specification\Profile\ProfileHasVideo;
  35. use App\Specification\Profile\ProfileInMoskowDistricts;
  36. use App\Specification\Profile\ProfileIsActive;
  37. use App\Specification\Profile\ProfileIsApproved;
  38. use App\Specification\Profile\ProfileIsElite;
  39. use App\Specification\Profile\ProfileIsForHour;
  40. use App\Specification\Profile\ProfileIsForNight;
  41. use App\Specification\Profile\ProfileIsGirlfriend;
  42. use App\Specification\Profile\ProfileIsLocated;
  43. use App\Specification\Profile\ProfileIsMasseur;
  44. use App\Specification\Profile\ProfileIsMostExpensive;
  45. use App\Specification\Profile\ProfileIsNew;
  46. use App\Specification\Profile\ProfileIsNice;
  47. use App\Specification\Profile\ProfileIsNotExpensive;
  48. use App\Specification\Profile\ProfileIsNotHidden;
  49. use App\Specification\Profile\ProfileIsProvidingOneOfServices;
  50. use App\Specification\Profile\ProfileIsProvidingTakeOut;
  51. use App\Specification\Profile\ProfileIsRealElite;
  52. use App\Specification\Profile\ProfileIsUpdatedWithinAYear;
  53. use App\Specification\Profile\ProfileIsWithoutPrepayment;
  54. use App\Specification\Profile\ProfileHasWhatsapp;
  55. use App\Specification\Profile\ProfileHasTelegram;
  56. use App\Specification\Profile\ProfileIsEighteenYearsOld;
  57. use App\Specification\Profile\ProfileIsVip;
  58. use App\Specification\Profile\ProfileIsVipIndividual;
  59. use App\Specification\Profile\ProfileIsVipMoskow;
  60. use App\Specification\Profile\ProfileNoRetouch;
  61. use App\Specification\Profile\ProfileWithAge;
  62. use App\Specification\Profile\ProfileWithApartmentsOneHourPrice;
  63. use App\Specification\Profile\ProfileWithBodyType;
  64. use App\Specification\Profile\ProfileWithBreastType;
  65. use App\Specification\Profile\ProfileWithHairColor;
  66. use App\Specification\Profile\ProfileWithHeight;
  67. use App\Specification\Profile\ProfileWithNationality;
  68. use App\Specification\Profile\ProfileWithPrivateHaircut;
  69. use App\Specification\QueryModifier\LimitResult;
  70. use App\Specification\QueryModifier\ProfileAvatar;
  71. use App\Specification\QueryModifier\ProfileOrderedByNightPrice;
  72. use App\Specification\QueryModifier\ProfilePlacementHiding;
  73. use Happyr\DoctrineSpecification\Filter\Filter;
  74. use Happyr\DoctrineSpecification\Logic\AndX;
  75. use Happyr\DoctrineSpecification\Spec;
  76. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  77. class ProfileListSpecificationService
  78. {
  79.     public function __construct(
  80.         private CountryCurrencyResolver $countryCurrencyResolver,
  81.         private ServiceRepository $serviceRepository,
  82.         private ParameterBagInterface $parameterBag,
  83.         private ProfileRepository $profileRepository,
  84.         private EntityManagerInterface $entityManager,
  85.         private DistrictRepository $districtRepository,
  86.         private Features $features,
  87.     ) {}
  88.     public function listForMasseur(City $city): ProfileListSpecification
  89.     {
  90.         return new ProfileListSpecification(new ProfileIsMasseur(), \App\Specification\ElasticSearch\ProfileIsLocated::withinCity($city));
  91.     }
  92.     public function listByCity(): ProfileListSpecification
  93.     {
  94.         return new ProfileListSpecification(nullnull);
  95.     }
  96.     public function listByCounty(County $county): ProfileListSpecification
  97.     {
  98.         return new ProfileListSpecification(ProfileIsLocated::withinCounty($county), \App\Specification\ElasticSearch\ProfileIsLocated::withinCounty($county));
  99.     }
  100.     public function listByCountyEromassage(County $county): ProfileListSpecification
  101.     {
  102.         $massageServices $this->getMassageGroupServices();
  103.         return new ProfileListSpecification(
  104.             Spec::andX(
  105.                 ProfileIsLocated::withinCounty($county),
  106.                 new ProfileIsProvidingOneOfServices($massageServices)
  107.             ),
  108.             \App\Specification\ElasticSearch\Spec::andX(
  109.                 \App\Specification\ElasticSearch\ProfileIsLocated::withinCounty($county),
  110.                 new \App\Specification\ElasticSearch\ProfileIsProvidingOneOfServices($massageServices)
  111.             )
  112.         );
  113.     }
  114.     public function listByCountyVerified(County $county): ProfileListSpecification
  115.     {
  116.         return new ProfileListSpecification(
  117.             Spec::andX(
  118.                 ProfileIsLocated::withinCounty($county),
  119.                 new ProfileIsApproved()
  120.             ),
  121.             \App\Specification\ElasticSearch\Spec::andX(
  122.                 \App\Specification\ElasticSearch\ProfileIsLocated::withinCounty($county),
  123.                 new \App\Specification\ElasticSearch\ProfileIsApproved()
  124.             )
  125.         );
  126.     }
  127.     public function listByCountyCheap(County $county): ProfileListSpecification
  128.     {
  129.         $stationIds $this->extractStationIds($county->getStations()->toArray());
  130.         return new ProfileListSpecification(
  131.             Spec::andX(
  132.                 ProfileIsLocated::withinCounty($county),
  133.                 new ProfileHasLowPriceInLocation($county->getCity(), $stationIds$this->features->hard_moderation())
  134.             ),
  135.             null
  136.         );
  137.     }
  138.     public function listByCountyMature(County $county): ProfileListSpecification
  139.     {
  140.         $stationIds $this->extractStationIds($county->getStations()->toArray());
  141.         return new ProfileListSpecification(
  142.             Spec::andX(
  143.                 ProfileIsLocated::withinCounty($county),
  144.                 new ProfileHasOldAgeInLocation($county->getCity(), $stationIds$this->features->hard_moderation())
  145.             ),
  146.             null
  147.         );
  148.     }
  149.     public function listByCountyUzbek(County $county): ProfileListSpecification
  150.     {
  151.         return new ProfileListSpecification(
  152.             Spec::andX(
  153.                 ProfileIsLocated::withinCounty($county),
  154.                 new ProfileWithNationality(Nationalities::UZBEK)
  155.             ),
  156.             \App\Specification\ElasticSearch\Spec::andX(
  157.                 \App\Specification\ElasticSearch\ProfileIsLocated::withinCounty($county),
  158.                 new \App\Specification\ElasticSearch\ProfileWithNationality(Nationalities::UZBEK)
  159.             )
  160.         );
  161.     }
  162.     public function listByDistrict(District $district): ProfileListSpecification
  163.     {
  164.         return new ProfileListSpecification(ProfileIsLocated::withinDistrict($district), \App\Specification\ElasticSearch\ProfileIsLocated::withinDistrict($district));
  165.     }
  166.     public function listByDistrictEromassage(District $district): ProfileListSpecification
  167.     {
  168.         $massageServices $this->getMassageGroupServices();
  169.         return new ProfileListSpecification(
  170.             Spec::andX(
  171.                 ProfileIsLocated::withinDistrict($district),
  172.                 new ProfileIsProvidingOneOfServices($massageServices)
  173.             ),
  174.             \App\Specification\ElasticSearch\Spec::andX(
  175.                 \App\Specification\ElasticSearch\ProfileIsLocated::withinDistrict($district),
  176.                 new \App\Specification\ElasticSearch\ProfileIsProvidingOneOfServices($massageServices)
  177.             )
  178.         );
  179.     }
  180.     public function listByDistrictVerified(District $district): ProfileListSpecification
  181.     {
  182.         return new ProfileListSpecification(
  183.             Spec::andX(
  184.                 ProfileIsLocated::withinDistrict($district),
  185.                 new ProfileIsApproved()
  186.             ),
  187.             \App\Specification\ElasticSearch\Spec::andX(
  188.                 \App\Specification\ElasticSearch\ProfileIsLocated::withinDistrict($district),
  189.                 new \App\Specification\ElasticSearch\ProfileIsApproved()
  190.             )
  191.         );
  192.     }
  193.     public function listByDistrictCheap(District $district): ProfileListSpecification
  194.     {
  195.         $stationIds $this->extractStationIds($district->getStations()->toArray());
  196.         return new ProfileListSpecification(
  197.             Spec::andX(
  198.                 ProfileIsLocated::withinDistrict($district),
  199.                 new ProfileHasLowPriceInLocation($district->getCity(), $stationIds$this->features->hard_moderation())
  200.             ),
  201.             null
  202.         );
  203.     }
  204.     public function listByDistrictMature(District $district): ProfileListSpecification
  205.     {
  206.         $stationIds $this->extractStationIds($district->getStations()->toArray());
  207.         return new ProfileListSpecification(
  208.             Spec::andX(
  209.                 ProfileIsLocated::withinDistrict($district),
  210.                 new ProfileHasOldAgeInLocation($district->getCity(), $stationIds$this->features->hard_moderation())
  211.             ),
  212.             null
  213.         );
  214.     }
  215.     public function listByDistrictUzbek(District $district): ProfileListSpecification
  216.     {
  217.         return new ProfileListSpecification(
  218.             Spec::andX(
  219.                 ProfileIsLocated::withinDistrict($district),
  220.                 new ProfileWithNationality(Nationalities::UZBEK)
  221.             ),
  222.             \App\Specification\ElasticSearch\Spec::andX(
  223.                 \App\Specification\ElasticSearch\ProfileIsLocated::withinDistrict($district),
  224.                 new \App\Specification\ElasticSearch\ProfileWithNationality(Nationalities::UZBEK)
  225.             )
  226.         );
  227.     }
  228.     public function listByStation(Station $station): ProfileListSpecification
  229.     {
  230.         return new ProfileListSpecification(ProfileIsLocated::nearStation($station), \App\Specification\ElasticSearch\ProfileIsLocated::nearStations([$station]));
  231.     }
  232.     public function listByStationEromassage(Station $station): ProfileListSpecification
  233.     {
  234.         $massageServices $this->getMassageGroupServices();
  235.         return new ProfileListSpecification(
  236.             Spec::andX(
  237.                 ProfileIsLocated::nearStation($station),
  238.                 new ProfileIsProvidingOneOfServices($massageServices)
  239.             ),
  240.             \App\Specification\ElasticSearch\Spec::andX(
  241.                 \App\Specification\ElasticSearch\ProfileIsLocated::nearStations([$station]),
  242.                 new \App\Specification\ElasticSearch\ProfileIsProvidingOneOfServices($massageServices)
  243.             )
  244.         );
  245.     }
  246.     public function listByStationVerified(Station $station): ProfileListSpecification
  247.     {
  248.         return new ProfileListSpecification(
  249.             Spec::andX(
  250.                 ProfileIsLocated::nearStation($station),
  251.                 new ProfileIsApproved()
  252.             ),
  253.             \App\Specification\ElasticSearch\Spec::andX(
  254.                 \App\Specification\ElasticSearch\ProfileIsLocated::nearStations([$station]),
  255.                 new \App\Specification\ElasticSearch\ProfileIsApproved()
  256.             )
  257.         );
  258.     }
  259.     public function listByStationCheap(Station $station): ProfileListSpecification
  260.     {
  261.         return new ProfileListSpecification(
  262.             Spec::andX(
  263.                 ProfileIsLocated::nearStation($station),
  264.                 new ProfileHasLowPriceInLocation($station->getCity(), [$station->getId()], $this->features->hard_moderation())
  265.             ),
  266.             null
  267.         );
  268.     }
  269.     public function listByStationMature(Station $station): ProfileListSpecification
  270.     {
  271.         return new ProfileListSpecification(
  272.             Spec::andX(
  273.                 ProfileIsLocated::nearStation($station),
  274.                 new ProfileHasOldAgeInLocation($station->getCity(), [$station->getId()], $this->features->hard_moderation())
  275.             ),
  276.             null
  277.         );
  278.     }
  279.     public function listByStationUzbek(Station $station): ProfileListSpecification
  280.     {
  281.         return new ProfileListSpecification(
  282.             Spec::andX(
  283.                 ProfileIsLocated::nearStation($station),
  284.                 new ProfileWithNationality(Nationalities::UZBEK)
  285.             ),
  286.             \App\Specification\ElasticSearch\Spec::andX(
  287.                 \App\Specification\ElasticSearch\ProfileIsLocated::nearStations([$station]),
  288.                 new \App\Specification\ElasticSearch\ProfileWithNationality(Nationalities::UZBEK)
  289.             )
  290.         );
  291.     }
  292.     public function listByStations(array $stations): ProfileListSpecification
  293.     {
  294.         //        $stationIds = explode(',', $stations);
  295.         //        $stations = $this->stationRepository->findBy(['uriIdentity' => $stationIds]);
  296.         return new ProfileListSpecification(new ProfileIsLocated(nullnullnull$stations), \App\Specification\ElasticSearch\ProfileIsLocated::nearStations($stations));
  297.     }
  298.     public function listApproved(): ProfileListSpecification
  299.     {
  300.         return new ProfileListSpecification(new ProfileIsApproved(), new \App\Specification\ElasticSearch\ProfileIsApproved());
  301.     }
  302.     public function listWithWhatsapp(): ProfileListSpecification
  303.     {
  304.         return new ProfileListSpecification(
  305.             new ProfileHasWhatsapp(),
  306.             new \App\Specification\ElasticSearch\ProfileHasWhatsapp()
  307.         );
  308.     }
  309.     public function listWithTelegram(): ProfileListSpecification
  310.     {
  311.         return new ProfileListSpecification(
  312.             new ProfileHasTelegram(),
  313.             new \App\Specification\ElasticSearch\ProfileHasTelegram()
  314.         );
  315.     }
  316.     public function listEighteenYearsOld(): ProfileListSpecification
  317.     {
  318.         return new ProfileListSpecification(
  319.             new ProfileIsEighteenYearsOld(),
  320.             new \App\Specification\ElasticSearch\ProfileIsEighteenYearsOld()
  321.         );
  322.     }
  323.     public function listRublevskie(City $city): ProfileListSpecification
  324.     {
  325.         $stationRepo $this->entityManager->getRepository(\App\Entity\Location\Station::class);
  326.         $stationUris = require __DIR__ '/../../config/rublevskie_stations.php';
  327.         $stations $stationRepo->createQueryBuilder('s')
  328.             ->andWhere('s.city = :city')
  329.             ->andWhere('s.uriIdentity IN (:uris)')
  330.             ->setParameter('city'$city)
  331.             ->setParameter('uris'$stationUris)
  332.             ->getQuery()->getResult();
  333.         return new ProfileListSpecification(
  334.             new \App\Specification\Profile\ProfileIsRublevskie($city$this->entityManager),
  335.             new \App\Specification\ElasticSearch\ProfileIsRublevskie($city$stations)
  336.         );
  337.     }
  338.     public function listWithTattoo(): ProfileListSpecification
  339.     {
  340.         return new ProfileListSpecification(
  341.             new \App\Specification\Profile\ProfileIsHavingTattoo(true),
  342.             new \App\Specification\ElasticSearch\ProfileIsHavingTattoo(true)
  343.         );
  344.     }
  345.     public function listWithPiercing(): ProfileListSpecification
  346.     {
  347.         return new ProfileListSpecification(
  348.             new \App\Specification\Profile\ProfileIsHavingPiercing(true),
  349.             new \App\Specification\ElasticSearch\ProfileIsHavingPiercing(true)
  350.         );
  351.     }
  352.     public function listRoundTheClock(): ProfileListSpecification
  353.     {
  354.         return new ProfileListSpecification(
  355.             new \App\Specification\Profile\ProfileIsRoundTheClock(),
  356.             new \App\Specification\ElasticSearch\ProfileIsRoundTheClock()
  357.         );
  358.     }
  359.     public function listForTwoHours(): ProfileListSpecification
  360.     {
  361.         return new ProfileListSpecification(
  362.             new \App\Specification\Profile\ProfileIsForTwoHours(),
  363.             new \App\Specification\ElasticSearch\ProfileIsForTwoHours()
  364.         );
  365.     }
  366.     public function listGrandmothers(): ProfileListSpecification
  367.     {
  368.         return new ProfileListSpecification(
  369.             new \App\Specification\Profile\ProfileIsGrandmother(),
  370.             new \App\Specification\ElasticSearch\ProfileIsGrandmother()
  371.         );
  372.     }
  373.     public function listWithComments(): ProfileListSpecification
  374.     {
  375.         return new ProfileListSpecification(new ProfileHasComments(), new \App\Specification\ElasticSearch\ProfileHasComments());
  376.     }
  377.     public function listWithVideo(): ProfileListSpecification
  378.     {
  379.         return new ProfileListSpecification(new ProfileHasVideo(), new \App\Specification\ElasticSearch\ProfileHasVideo());
  380.     }
  381.     public function listWithSelfie(): ProfileListSpecification
  382.     {
  383.         return new ProfileListSpecification(new ProfileHasSelfie(), new \App\Specification\ElasticSearch\ProfileHasSelfie());
  384.     }
  385.     public function listByPrice(City $citystring $priceTypeint $minPrice nullint $maxPrice null): ProfileListSpecification
  386.     {
  387.         $currency $this->countryCurrencyResolver->getCurrencyFor($city->getCountryCode());
  388.         if ($minPrice && $maxPrice) {
  389.             $priceSpec ProfileWithApartmentsOneHourPrice::range($minPrice$maxPrice);
  390.             $recommendationSpec \App\Specification\ElasticSearch\ProfileWithApartmentsOneHourPrice::range($minPrice$maxPrice);
  391.         } elseif ($maxPrice) {
  392.             $priceSpec ProfileWithApartmentsOneHourPrice::cheaperThan($maxPrice);
  393.             $recommendationSpec \App\Specification\ElasticSearch\ProfileWithApartmentsOneHourPrice::cheaperThan($maxPrice);
  394.         } else {
  395.             switch ($priceType) {
  396.                 case 'not_expensive':
  397.                     $priceSpec = new ProfileIsNotExpensive($city);
  398.                     $recommendationSpec = new \App\Specification\ElasticSearch\ProfileIsNotExpensive($currency);
  399.                     break;
  400.                 case 'low':
  401.                     $priceSpec = new ProfileHasLowPrice($city$currency);
  402.                     $recommendationSpec = new \App\Specification\ElasticSearch\ProfileHasLowPrice($city$currency);
  403.                     break;
  404.                 case 'elite':
  405.                     $priceSpec = new ProfileHasHighPrice($city$currency, [
  406.                         'RUB' => 20000,
  407.                     ], [
  408.                         'RUB' => 20000,
  409.                     ]);
  410.                     $recommendationSpec = new \App\Specification\ElasticSearch\ProfileHasHighPrice($city$currency, [], []);
  411.                     break;
  412.                 case 'high':
  413.                 default:
  414.                     $priceSpec = new ProfileHasHighPrice($city$currency);
  415.                     $recommendationSpec = new \App\Specification\ElasticSearch\ProfileHasHighPrice($city$currency);
  416.                     break;
  417.             }
  418.         }
  419.         return new ProfileListSpecification($priceSpec$recommendationSpec);
  420.     }
  421.     public function listByAge(string $ageTypeint $minAge nullint $maxAge null): ProfileListSpecification
  422.     {
  423.         if ($minAge && $maxAge) {
  424.             $ageSpec ProfileWithAge::range($minAge$maxAge);
  425.             $recommendationSpec \App\Specification\ElasticSearch\ProfileWithAge::range($minAge$maxAge);
  426.         } elseif ($minAge) {
  427.             $ageSpec ProfileWithAge::olderThan($minAge);
  428.             $recommendationSpec \App\Specification\ElasticSearch\ProfileWithAge::olderThan($minAge);
  429.         } else {
  430.             switch ($ageType) {
  431.                 case 'old':
  432.                     $ageSpec ProfileWithAge::old();
  433.                     $recommendationSpec \App\Specification\ElasticSearch\ProfileWithAge::old();
  434.                     break;
  435.                 case 'young':
  436.                 default:
  437.                     $ageSpec ProfileWithAge::young();
  438.                     $recommendationSpec \App\Specification\ElasticSearch\ProfileWithAge::young();
  439.                     break;
  440.             }
  441.         }
  442.         return new ProfileListSpecification($ageSpec$recommendationSpec);
  443.     }
  444.     public function listByHeight(string $heightType): ProfileListSpecification
  445.     {
  446.         if ('short' === $heightType) {
  447.             $heightSpec ProfileWithHeight::short();
  448.             $recommendationSpec \App\Specification\ElasticSearch\ProfileWithHeight::short();
  449.         } else {
  450.             $heightSpec ProfileWithHeight::tall();
  451.             $recommendationSpec \App\Specification\ElasticSearch\ProfileWithHeight::tall();
  452.         }
  453.         return new ProfileListSpecification($heightSpec$recommendationSpec);
  454.     }
  455.     public function listByBreastType(string $breastType): ProfileListSpecification
  456.     {
  457.         $breastTypeSpec = new ProfileWithBreastType(BreastTypes::getValueByUriIdentity($breastType));
  458.         return new ProfileListSpecification($breastTypeSpec, new \App\Specification\ElasticSearch\ProfileWithBreastType(BreastTypes::getValueByUriIdentity($breastType)));
  459.     }
  460.     public function listByHairColor(string $hairColor): ProfileListSpecification
  461.     {
  462.         $hairColorSpec = new ProfileWithHairColor(HairColors::getValueByUriIdentity($hairColor));
  463.         return new ProfileListSpecification($hairColorSpec, new \App\Specification\ElasticSearch\ProfileWithHairColor(HairColors::getValueByUriIdentity($hairColor)));
  464.     }
  465.     public function listByBodyType(string $bodyType): ProfileListSpecification
  466.     {
  467.         $bodyTypeSpec = new ProfileWithBodyType(BodyTypes::getValueByUriIdentity($bodyType));
  468.         return new ProfileListSpecification($bodyTypeSpec, new \App\Specification\ElasticSearch\ProfileWithBodyType(BodyTypes::getValueByUriIdentity($bodyType)));
  469.     }
  470.     public function listByPlace(string $placeTypestring $takeOutLocation null): ?ProfileListSpecification
  471.     {
  472.         switch ($placeType) {
  473.             case 'apartments':
  474.                 $placeSpec = new ProfileHasApartments();
  475.                 $recommendationSpec = new \App\Specification\ElasticSearch\ProfileHasApartments();
  476.                 break;
  477.             case 'take-out':
  478.                 $takeOutLocation TakeOutLocations::getValueByUriIdentity($takeOutLocation);
  479.                 $placeSpec = new ProfileIsProvidingTakeOut($takeOutLocation);
  480.                 $recommendationSpec = new \App\Specification\ElasticSearch\ProfileIsProvidingTakeOut($takeOutLocation);
  481.                 break;
  482.             case 'on-call':
  483.                 $placeSpec Spec::andX(
  484.                     new ProfileIsProvidingTakeOut(null),
  485.                     Spec::not(new ProfileHasApartments())
  486.                 );
  487.                 $recommendationSpec \App\Specification\ElasticSearch\Spec::andX(
  488.                     (new \App\Specification\ElasticSearch\ProfileIsProvidingTakeOut(null))->getSpec(),
  489.                     \App\Specification\ElasticSearch\Spec::not((new \App\Specification\ElasticSearch\ProfileHasApartments())->getSpec())
  490.                 );
  491.                 break;
  492.             default:
  493.                 return null;
  494.         }
  495.         return new ProfileListSpecification($placeSpec$recommendationSpec);
  496.     }
  497.     public function listByPrivateHaircut(string $privateHaircut): ProfileListSpecification
  498.     {
  499.         $privateHaircutSpec = new ProfileWithPrivateHaircut(PrivateHaircuts::getValueByUriIdentity($privateHaircut));
  500.         return new ProfileListSpecification($privateHaircutSpec, new \App\Specification\ElasticSearch\ProfileWithPrivateHaircut(PrivateHaircuts::getValueByUriIdentity($privateHaircut)));
  501.     }
  502.     public function listByNationality(string $nationality): ProfileListSpecification
  503.     {
  504.         $nationalitySpec = new ProfileWithNationality(Nationalities::getValueByUriIdentity($nationality));
  505.         return new ProfileListSpecification($nationalitySpec, new \App\Specification\ElasticSearch\ProfileWithNationality(Nationalities::getValueByUriIdentity($nationality)));
  506.     }
  507.     public function listByProvidedService(Service $serviceCity $city): ProfileListSpecification
  508.     {
  509.         $sameGroupServices $this->serviceRepository->findBy(['group' => $service->getGroup()]);
  510.         $spec = new AndX(new ProfileIsProvidingOneOfServices([$service]));
  511.         if ('eskort' == $service->getUriIdentity() && true === $this->features->escort_additional_requirements()) {
  512.             $spec->andX(new ProfileIsApproved());
  513.             $spec->andX(new ProfileHasPriceGreaterThan($city'RUB', [
  514.                 'RUB' => 12000,
  515.             ]));
  516.             $spec->andX(new ProfileIsUpdatedWithinAYear());
  517.         }
  518.         return new ProfileListSpecification($spec, new \App\Specification\ElasticSearch\ProfileIsProvidingOneOfServices($sameGroupServices));
  519.     }
  520.     public function listNew(int $weeks 2): ProfileListSpecification
  521.     {
  522.         return new ProfileListSpecification(new ProfileIsNew($weeks), new \App\Specification\ElasticSearch\ProfileIsNew($weeks));
  523.     }
  524.     public function listByNoRetouch(): ProfileListSpecification
  525.     {
  526.         return new ProfileListSpecification(new ProfileNoRetouch(), new \App\Specification\ElasticSearch\ProfileNoRetouch());
  527.     }
  528.     public function listByNice(): ProfileListSpecification
  529.     {
  530.         return new ProfileListSpecification(new ProfileIsNice(), new \App\Specification\ElasticSearch\ProfileIsNice());
  531.     }
  532.     public function listByOnCall(): ProfileListSpecification
  533.     {
  534.         return new ProfileListSpecification(new ProfileHasOnCall(), new \App\Specification\ElasticSearch\ProfileHasOnCall());
  535.     }
  536.     public function listForHour(): ProfileListSpecification
  537.     {
  538.         return new ProfileListSpecification(new ProfileIsForHour(), new \App\Specification\ElasticSearch\ProfileIsForHour());
  539.     }
  540.     public function listForNight(): ProfileListSpecification
  541.     {
  542.         return new ProfileListSpecification(new ProfileIsForNight(), new \App\Specification\ElasticSearch\ProfileIsForNight());
  543.     }
  544.     private function getSpecForEliteGirls(City $city): Filter
  545.     {
  546.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  547.             'RUB' => 5000,
  548.             'UAH' => 1500,
  549.             'USD' => 100,
  550.             'EUR' => 130,
  551.         ]);
  552.         return new ProfileIsElite($minPrice);
  553.     }
  554.     private function getElasticSearchSpecForEliteGirls(City $city): ISpecification
  555.     {
  556.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  557.             'RUB' => 5000,
  558.             'UAH' => 1500,
  559.             'USD' => 100,
  560.             'EUR' => 130,
  561.         ]);
  562.         return new \App\Specification\ElasticSearch\ProfileIsElite($minPrice);
  563.     }
  564.     public function listForEliteGirls(City $city): ProfileListSpecification
  565.     {
  566.         $eliteSpec $this->getSpecForEliteGirls($city);
  567.         return new ProfileListSpecification($eliteSpec$this->getElasticSearchSpecForEliteGirls($city));
  568.     }
  569.     public function listForRealElite(City $city): ProfileListSpecification
  570.     {
  571.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  572.             'RUB' => 5000,
  573.             'UAH' => 1500,
  574.             'USD' => 100,
  575.             'EUR' => 130,
  576.         ]);
  577.         return new ProfileListSpecification(new ProfileIsRealElite($minPrice), new \App\Specification\ElasticSearch\ProfileIsRealElite($minPrice));
  578.     }
  579.     public function listForVipPros(City $city): ProfileListSpecification
  580.     {
  581.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  582.             'RUB' => 4000,
  583.             'UAH' => 1200,
  584.             'USD' => 100,
  585.             'EUR' => 100,
  586.         ]);
  587.         $districts = [];
  588.         foreach (ProfileInMoskowDistricts::$districtsUri as $uri) {
  589.             $districts[] = $this->districtRepository->ofUriIdentityWithinCity($uri$city);
  590.         }
  591.         return new ProfileListSpecification(new ProfileIsVip($city$districts$minPrice), new \App\Specification\ElasticSearch\ProfileIsVip($city$districts$minPrice));
  592.     }
  593.     public function listForVipIndividual(City $city): ProfileListSpecification
  594.     {
  595.         $minPrice $this->countryCurrencyResolver->getValueByCountryCode($city->getCountryCode(), [
  596.             'RUB' => 30000,
  597.             'UAH' => 10000,
  598.             'USD' => 400,
  599.             'EUR' => 400,
  600.         ]);
  601.         return new ProfileListSpecification(new ProfileIsVipIndividual($minPrice), new \App\Specification\ElasticSearch\ProfileIsVipIndividual($minPrice));
  602.     }
  603.     public function listForVipGirlsCity(City $city): ProfileListSpecification
  604.     {
  605.         return new ProfileListSpecification(new ProfileIsVipMoskow($city), new \App\Specification\ElasticSearch\ProfileIsVipMoskow($city));
  606.     }
  607.     public function listOfGirlfriends(): ProfileListSpecification
  608.     {
  609.         return new ProfileListSpecification(new ProfileIsGirlfriend(), new \App\Specification\ElasticSearch\ProfileIsGirlfriend());
  610.     }
  611.     public function listOfMostExpensive(City $city): ProfileListSpecification
  612.     {
  613.         $count intval($this->profileRepository->match(Spec::countOf(Spec::andX(
  614.             ProfileIsLocated::withinCity($city),
  615.             new ProfileHasOneOfGenders([Genders::FEMALE])
  616.         )))[0][1]);
  617.         $criteria Spec::andX(
  618.             $this->features->free_profiles() ? new ProfileIsNotHidden() : new ProfileIsActive(),
  619.             new ProfileAdBoardPlacement(),
  620.             new ProfilePlacementHiding(),
  621.             new ProfileAvatar(),
  622.             ProfileIsLocated::withinCity($city),
  623.             new LimitResult(round($count 10), 0),
  624.             new ProfileOrderedByNightPrice(),
  625.             new ProfileHasOneOfGenders([Genders::FEMALE])
  626.         );
  627.         $profilesTenPercents $this->profileRepository->match($criteria);
  628.         $criteriaProfile end($profilesTenPercents);
  629.         return new ProfileListSpecification(new ProfileIsMostExpensive($criteriaProfile), new \App\Specification\ElasticSearch\ProfileIsMostExpensive($criteriaProfile));
  630.     }
  631.     public function listBdsm(): ProfileListSpecification
  632.     {
  633.         $bdsmIds $this->serviceRepository->findBy(['group' => ServiceGroups::BDSM]);
  634.         return new ProfileListSpecification(null, new \App\Specification\ElasticSearch\ProfileIsProvidingOneOfServices($bdsmIds), [new BdsmProfile($this->parameterBag->get('profile_list.bdsm_page.min_profile_services'))]);
  635.     }
  636.     public function listByGender(string $gender): ProfileListSpecification
  637.     {
  638.         $gender Genders::getValueByUriIdentity($gender);
  639.         $genders = [$gender];
  640.         return new ProfileListSpecification(nullnullnull$genders);
  641.     }
  642.     public function listBigAss(): ProfileListSpecification
  643.     {
  644.         return new ProfileListSpecification(
  645.             new \App\Specification\Profile\ProfileIsBigAss(),
  646.             new \App\Specification\ElasticSearch\ProfileIsBigAss()
  647.         );
  648.     }
  649.     public function listExpress(): ProfileListSpecification
  650.     {
  651.         return new ProfileListSpecification(
  652.             new \App\Specification\Profile\ProfileIsProvidingExpress(),
  653.             new \App\Specification\ElasticSearch\ProfileIsProvidingExpress()
  654.         );
  655.     }
  656.     public function listBigBreast(): ProfileListSpecification
  657.     {
  658.         return new ProfileListSpecification(
  659.             new \App\Specification\Profile\ProfileHasBigBreast(),
  660.             new \App\Specification\ElasticSearch\ProfileHasBigBreast()
  661.         );
  662.     }
  663.     
  664.     public function listVerySkinny(): ProfileListSpecification
  665.     {
  666.         return new ProfileListSpecification(
  667.             new \App\Specification\Profile\ProfileIsVerySkinny(),
  668.             new \App\Specification\ElasticSearch\ProfileIsVerySkinny()
  669.         );
  670.     }
  671.     public function listSmallAss(): ProfileListSpecification
  672.     {
  673.         return new ProfileListSpecification(
  674.             new \App\Specification\Profile\ProfileIsSmallAss(),
  675.             new \App\Specification\ElasticSearch\ProfileIsSmallAss()
  676.         );
  677.     }
  678.     public function listBeautifulProstitutes(): ProfileListSpecification
  679.     {
  680.         return new ProfileListSpecification(
  681.             new \App\Specification\Profile\ProfileIsBeautifulProstitute(),
  682.             new \App\Specification\ElasticSearch\ProfileIsBeautifulProstitute()
  683.         );
  684.     }
  685.         public function listWithoutIntermediaries(): ProfileListSpecification
  686.     {
  687.         return new ProfileListSpecification(
  688.             new \App\Specification\Profile\ProfileIsWithoutIntermediaries(),
  689.             null 
  690.         );
  691.     }
  692.     public function listByOutcall(): ProfileListSpecification
  693.     {
  694.         return new ProfileListSpecification(new \App\Specification\Profile\ProfileHasOutcall(), new \App\Specification\ElasticSearch\ProfileHasOutcall());
  695.     }
  696.     public function listDwarfs(): ProfileListSpecification
  697.     {
  698.         return new ProfileListSpecification(new \App\Specification\Profile\ProfileIsDwarf(), new \App\Specification\ElasticSearch\ProfileIsDwarf());
  699.     }
  700.     public function listWithoutPrepayment(): ProfileListSpecification
  701.     {
  702.         return new ProfileListSpecification(
  703.             new \App\Specification\Profile\ProfileWithoutPrepayment(),
  704.             new \App\Specification\ElasticSearch\ProfileWithoutPrepayment()
  705.         );
  706.     }
  707.     private function getMassageGroupServices(): array
  708.     {
  709.         return $this->serviceRepository->findBy(['group' => ServiceGroups::MASSAGE]);
  710.     }
  711.     private function extractStationIds(array $stations): array
  712.     {
  713.         $stationIds = [];
  714.         foreach ($stations as $station) {
  715.             if ($station instanceof Station) {
  716.                 $stationIds[] = $station->getId();
  717.             }
  718.         }
  719.         return $stationIds;
  720.     }
  721. }