visitService = $visitService;
$this->ipLocationResolver = $ipLocationResolver;
$this->locker = $locker;
}
protected function configure(): void
{
$this
->setName(self::NAME)
->setDescription('Processes visits where location is not set yet');
}
protected function execute(InputInterface $input, OutputInterface $output): ?int
{
$this->output = $output;
$io = new SymfonyStyle($input, $output);
$lock = $this->locker->createLock(self::NAME);
if (! $lock->acquire()) {
$io->warning(sprintf('There is already an instance of the "%s" command in execution', self::NAME));
return ExitCodes::EXIT_WARNING;
}
try {
$this->visitService->locateUnlocatedVisits(
[$this, 'getGeolocationDataForVisit'],
function (VisitLocation $location) use ($output) {
if (! $location->isEmpty()) {
$output->writeln(
sprintf(' [Address located at "%s"]', $location->getCountryName())
);
}
}
);
$io->success('Finished processing all IPs');
} finally {
$lock->release();
return ExitCodes::EXIT_SUCCESS;
}
}
public function getGeolocationDataForVisit(Visit $visit): Location
{
if (! $visit->hasRemoteAddr()) {
$this->output->writeln(
'Ignored visit with no IP address',
OutputInterface::VERBOSITY_VERBOSE
);
throw IpCannotBeLocatedException::forEmptyAddress();
}
$ipAddr = $visit->getRemoteAddr();
$this->output->write(sprintf('Processing IP %s>', $ipAddr));
if ($ipAddr === IpAddress::LOCALHOST) {
$this->output->writeln(' [Ignored localhost address]');
throw IpCannotBeLocatedException::forLocalhost();
}
try {
return $this->ipLocationResolver->resolveIpLocation($ipAddr);
} catch (WrongIpException $e) {
$this->output->writeln(' [An error occurred while locating IP. Skipped>]');
if ($this->output->isVerbose()) {
$this->getApplication()->renderException($e, $this->output);
}
throw IpCannotBeLocatedException::forError($e);
}
}
}