src/Service/ProfileListSpecificationService.php line 101

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