<?php
namespace App\EventSubscriber;
use App\Entity\Info;
use App\Entity\Region;
use App\Manager\InfoManager;
use App\Manager\IpApiManager;
use App\Manager\LogIpApiManager;
use App\Manager\RegionManager;
use App\Service\LocationIP\Api;
use App\Service\LocationIP\LocationIpInterface as LocationIP;
use App\Service\Regionalization\CheckBot;
use App\Service\Regionalization\CheckController;
use App\Service\Regionalization\CheckParameter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\String\Slugger\SluggerInterface;
class CityEventSubscriber implements EventSubscriberInterface
{
private RequestStack $requestStack;
private Api $locationIP;
private RegionManager $regionManager;
private InfoManager $infoManager;
private LogIpApiManager $logIpApiManager;
private IpApiManager $ipApiManager;
private CheckController $checkController;
private CheckParameter $checkParameter;
private CheckBot $checkBot;
private SluggerInterface $slugger;
public function __construct(RequestStack $requestStack, Api $locationIP, RegionManager $regionManager, InfoManager $infoManager, LogIpApiManager $logIpApiManager, IpApiManager $ipApiManager, CheckController $checkController, CheckParameter $checkParameter, CheckBot $checkBot, SluggerInterface $slugger) {
$this->requestStack = $requestStack;
$this->locationIP = $locationIP;
$this->regionManager = $regionManager;
$this->infoManager = $infoManager;
$this->logIpApiManager = $logIpApiManager;
$this->ipApiManager = $ipApiManager;
$this->checkParameter = $checkParameter;
$this->checkController = $checkController;
$this->checkBot = $checkBot;
$this->slugger = $slugger;
}
public function onControllerEvent(ControllerEvent $event): void
{
return;
/** @var Info $info */
$info = $this->infoManager->find(1);
if (!$info->isRegionInfoShow()) {
$this->clearRegionCitySession();
return;
}
$session = $this->requestStack->getSession();
if ($session->get(LocationIP::CLEAR) === true or $session->get(LocationIP::INVALID) === true) {
$this->clearRegionCitySession();
return;
}
if (!is_null($this->getCitySession())) {
return;
}
$eventController = $event->getController();
$controller = $eventController;
$method = null;
if (is_array($eventController)) {
$controller = get_class($eventController[0]);
$method = $eventController[1];
}
if (!is_string($controller) or !(is_string($method) or is_null($method))) {
$this->clearRegionCitySession();
return;
}
if (!$this->checkController->isValid($controller, $method)) {
$this->clearRegionCitySession();
return;
}
$request = $event->getRequest();
if (is_null($request)) {
$this->clearRegionCitySession();
return;
}
$parameters = $request->query->all();
if (!$this->checkParameter->isValid($parameters)) {
$this->clearRegionCitySession();
return;
}
$userAgent = $request->headers->get('User-Agent');
if (!$this->checkBot->isValid($userAgent)) {
$this->clearRegionCitySession();
return;
}
$cityName = $this->getCityByRequest($request, $controller, $method);
if (is_null($cityName)) {
$this->clearRegionCitySession();
$session->set(LocationIP::INVALID, true);
return;
}
$slug = $this->slugger->slug($cityName)->lower()->toString();
$cities = $this->regionManager->listInMap('');
$cities = array_filter($cities, function (Region $region) use ($slug) {
if ($region->getSlug() == $slug) {
return true;
}
if (empty($values = $region->apiValuesArray())) {
return false;
}
$values = array_map(function ($item) {
return $this->slugger->slug($item)->lower()->toString();
}, $values);
return in_array($slug, $values);
});
$cities = array_values($cities);
/** @var Region $city */
$city = $cities[0] ?? null;
if (is_null($city)) {
$this->clearRegionCitySession();
$session->set(LocationIP::INVALID, true);
return;
}
if ($city->getPropertiesActive()->count() < 1) {
$this->clearRegionCitySession();
$session->set(LocationIP::INVALID, true);
return;
}
$session->set(LocationIP::REGION, $city);
}
public static function getSubscribedEvents(): array
{
return [
ControllerEvent::class => 'onControllerEvent',
];
}
protected function getCitySession(): ?Region
{
$session = $this->requestStack->getSession();
return $session->get(LocationIP::REGION);
}
protected function clearRegionCitySession(): void
{
$session = $this->requestStack->getSession();
$session->remove(LocationIP::REGION);
}
protected function getCityByRequest(Request $request, string $controller, ?string $method): ?string
{
$ip = $request->getClientIp();
$ipApi = $this->ipApiManager->last($ip);
if (!is_null($ipApi)) {
return $ipApi->getCity();
}
$ipApiResponse = $this->locationIP->fromRequest($request);
$ipApiResponse->setController($controller);
$ipApiResponse->setMethod($method);
$this->logIpApiManager->save($ipApiResponse);
$city = $ipApiResponse->getDepartment();
$ipApi = $this->ipApiManager->byIp($ip);
if (is_null($ipApi)) {
$ipApi = $this->ipApiManager->create();
$ipApi->setIp($ip);
}
$ipApi->setCity($city);
$this->ipApiManager->save($ipApi);
return $city;
}
}