src/Service/ProfileListSpecificationService.php line 574

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