src/Service/ProfileListSpecificationService.php line 578

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