<?php
namespace App\Controller;
use App\Entity\Location\City;
use App\Entity\Profile\Genders;
use App\Entity\Saloon\Saloon;
use App\Event\Profile\ProfilesShownEvent;
use App\Form\FilterMapForm;
use App\Repository\CityRepository;
use App\Repository\ProfileRepository;
use App\Repository\ReadModel\ProfileMapReadModel;
use App\Repository\SaloonRepository;
use App\Repository\ServiceRepository;
use App\Service\Features;
use App\Service\ProfileList;
use App\Specification\Profile\ProfileHasMapCoordinates;
use App\Specification\Profile\ProfileIdINOrderedByINValues;
use App\Specification\Profile\ProfileIsLocated;
use App\Specification\QueryModifier\PossibleSaloonAdBoardPlacement;
use App\Specification\QueryModifier\PossibleSaloonPlacementHiding;
use App\Specification\Saloon\SaloonIsNotHidden;
use App\Specification\QueryModifier\SaloonThumbnail;
use App\Specification\Saloon\SaloonIsActive;
use Happyr\DoctrineSpecification\Spec;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Asset\Packages;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class MapController extends AbstractController
{
use ProfileMinPriceTrait;
const MAP_PROFILES_CACHE_ITEM_NAME = 'map_profiles_';
public function __construct(
private ProfileRepository $profileRepository,
private CityRepository $cityRepository,
private Features $features,
private Packages $assetPackage,
private SaloonRepository $saloonRepository,
private ProfileList $profileList,
private EventDispatcherInterface $eventDispatcher,
private ServiceRepository $serviceRepository,
private CacheItemPoolInterface $profilesFilterCache,
) {}
#[ParamConverter("city", converter: "city_converter")]
public function page(City $city): Response
{
return $this->render('Map/page.html.twig', [
'cityUriIdentity' => $city->getUriIdentity(),
'cityLatitude' => $city->getMapCoordinate()->getLatitude(),
'cityLongitude' => $city->getMapCoordinate()->getLongitude(),
'multipleCities' => (int)$this->features->multiple_cities(),
]);
}
public function form(City $city): Response
{
$form = $this->createForm(FilterMapForm::class, null, ['data' => ['city_id' => $city->getId()]]);
return $this->render('Map/form.html.twig', [
'form' => $form->createView(),
]);
}
public function filter(Request $request, TranslatorInterface $translator): Response
{
// $this->detail($request, $translator);
$params = json_decode($request->request->get('form'), true);
$form = $this->createForm(FilterMapForm::class);
$form->submit($params);
$scale = $request->request->get('scale') ?? 0;
if($scale <= 8) {
$coordsRoundPrecision = 2;
} else if($scale <= 14) {
$coordsRoundPrecision = 3;
} else {
$coordsRoundPrecision = 4;
}
$city = $this->cityRepository->find($params['city_id']);
$profiles = $this->profileList->listForMap(
$city, null, $form->getData(), [new ProfileHasMapCoordinates()], true, null,
ProfileList::ORDER_NONE, [Genders::FEMALE], $coordsRoundPrecision,
);
$specs = Spec::andX(
$this->features->free_profiles() ? new SaloonIsNotHidden() : new SaloonIsActive(),
new PossibleSaloonPlacementHiding(),
new PossibleSaloonAdBoardPlacement(),
new SaloonThumbnail(),
ProfileIsLocated::withinCity($city),
new ProfileHasMapCoordinates(),
);
$saloons = $this->saloonRepository->listForMapMatchingSpec($specs, $coordsRoundPrecision);
$out = [
'profiles' => array_map('array_values', $profiles),
'saloons' => array_map('array_values', $saloons),
];
return $this->json($out);
}
public function detail(Request $request, TranslatorInterface $translator): Response
{
$services = $this->serviceRepository->allIndexedById();
$profileIds = json_decode($request->request->get('profiles'), true);
$saloonIds = json_decode($request->request->get('saloons'), true);
$profileIds = [121705,25486];
$saloonIds = [126,123];
$result = $this->profileRepository->fetchMapProfilesByIds(new ProfileIdINOrderedByINValues($profileIds));
$profiles = [];
foreach ($result as /** @var ProfileMapReadModel $profile */$profile) {
if(!$profile->mapLatitude || !$profile->mapLongitude)
continue;
$path = $profile->avatar['path'];
$path = str_starts_with($path, '/') ? $path : substr($path, 6, -4);
$hasApartment = $profile->apartmentOneHourPrice || $profile->apartmentTwoHoursPrice || $profile->apartmentNightPrice;
$hasTakeout = $profile->takeOutOneHourPrice || $profile->takeOutTwoHoursPrice || $profile->takeOutNightPrice;
$tags = [];
if($hasApartment && !$hasTakeout)
$tags[] = 1;
elseif(!$hasApartment && $hasTakeout)
$tags[] = 2;
elseif ($hasApartment && $hasTakeout)
$tags[] = 3;
foreach ($profile->services as $serviceId) {
$serviceName = mb_strtolower($services[$serviceId]->getName()->getTranslation('ru'));
switch($serviceName) {
case 'секс классический': $tags[] = 4; break;
case 'секс анальный': $tags[] = 5; break;
case 'минет без резинки': $tags[] = 6; break;
case 'куннилингус': $tags[] = 7; break;
case 'окончание в рот': $tags[] = 8; break;
case 'массаж': if(false === in_array(9, $tags)) $tags[] = 9; break;
}
}
$profiles[] = [
1,
(float)rtrim(substr($profile->mapLatitude, 0, 7), '0'),
(float)rtrim(substr($profile->mapLongitude, 0, 7), '0'),
$profile->uriIdentity,
$profile->name,
$path, //$profile->avatar['path'],
//$profile->avatar['type'] ? 'avatar' : 'photo',
str_replace(' ', '', $profile->phoneNumber),
$profile->station ?? 0,
$profile->apartmentOneHourPrice ?? $profile->takeOutOneHourPrice ?? 0,
$profile->apartmentTwoHoursPrice ?? $profile->takeOutTwoHoursPrice ?? 0,
$profile->apartmentNightPrice ?? $profile->takeOutNightPrice ?? 0,
(int)$profile->isApproved,
(int)$profile->isMasseur,
(int)$profile->hasComments,
(int)$profile->hasSelfies,
(int)$profile->hasVideos,
$profile->age ?? 0,
$profile->breastSize ?? 0,
$profile->height ?? 0,
$profile->weight ?? 0,
$tags,
$profile->id,
(int)$profile->isPaid,
];
}
$result = $this->saloonRepository->matchingSpecRaw(new ProfileIdINOrderedByINValues($saloonIds), null, false);
$saloons = [];
foreach ($result as /** @var Saloon $saloon */ $saloon) {
$photoPath = null !== ($mainPhoto = $saloon->getThumbnail()) ? $mainPhoto->getPath() : '';
$photoPath = str_starts_with($photoPath, '/') ? $photoPath : str_replace(".jpg", "", substr($photoPath, 6));
$saloons[] = [
2,
(float)rtrim(substr($saloon->getMapCoordinate()->getLatitude(), 0, 7), '0'),
(float)rtrim(substr($saloon->getMapCoordinate()->getLongitude(), 0, 7), '0'),
$saloon->getUriIdentity(),
$translator->trans($saloon->getName()),
$photoPath,
//'thumb',
str_replace(' ', '', $saloon->getPhoneNumber()),
$saloon->getStations()->count() ? $saloon->getStations()->first()->getId() : 0,
$saloon->getApartmentsPricing()->getOneHourPrice() ?? $saloon->getTakeOutPricing()->getOneHourPrice() ?? 0,
$saloon->getApartmentsPricing()->getTwoHoursPrice() ?? $saloon->getTakeOutPricing()->getTwoHoursPrice() ?? 0,
$saloon->getApartmentsPricing()->getNightPrice() ?? $saloon->getTakeOutPricing()->getNightPrice() ?? 0,
//$saloon->getExpressPricing()->isProvided() ? $saloon->getExpressPricing()->getPrice() ?? 0 : 0,
(int)($saloon?->getAdBoardPlacement() !== null),
];
}
return new JsonResponse([
'profiles' => $profiles,
'saloons' => $saloons,
]);
}
public function processProfileShows(Request $request, ProfileRepository $profileRepository): JsonResponse
{
$id = $request->query->get('id');
$profile = $profileRepository->find($id);
if($profile) {
$this->eventDispatcher->dispatch(new ProfilesShownEvent([$profile->getId()], 'map'), ProfilesShownEvent::NAME);
}
return $this->json([]);
}
public function cachedMapProfilesResultByIds(ProfileIdINOrderedByINValues $specification)
{
$key = sha1(self::MAP_PROFILES_CACHE_ITEM_NAME . implode(',', $specification->getIds()));
return $this->profilesFilterCache->get($key, function (ItemInterface $item) use ($specification) {
return $this->profileRepository->fetchMapProfilesByIds($specification);
});
}
}