diff --git a/module/CLI/src/Command/Visit/ProcessVisitsCommand.php b/module/CLI/src/Command/Visit/ProcessVisitsCommand.php
index a5a33fcb..117ad80f 100644
--- a/module/CLI/src/Command/Visit/ProcessVisitsCommand.php
+++ b/module/CLI/src/Command/Visit/ProcessVisitsCommand.php
@@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Visit;
use Shlinkio\Shlink\Common\Exception\WrongIpException;
use Shlinkio\Shlink\Common\IpGeolocation\IpLocationResolverInterface;
use Shlinkio\Shlink\Common\Util\IpAddress;
+use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Entity\VisitLocation;
use Shlinkio\Shlink\Core\Service\VisitServiceInterface;
use Symfony\Component\Console\Command\Command;
@@ -57,47 +58,52 @@ class ProcessVisitsCommand extends Command
$visits = $this->visitService->getUnlocatedVisits();
foreach ($visits as $visit) {
- if (! $visit->hasRemoteAddr()) {
- $io->writeln(
- sprintf('%s', $this->translator->translate('Ignored visit with no IP address')),
- OutputInterface::VERBOSITY_VERBOSE
- );
- continue;
- }
-
- $ipAddr = $visit->getRemoteAddr();
- $io->write(sprintf('%s %s>', $this->translator->translate('Processing IP'), $ipAddr));
- if ($ipAddr === IpAddress::LOCALHOST) {
- $io->writeln(
- sprintf(' [%s]', $this->translator->translate('Ignored localhost address'))
- );
- continue;
- }
-
- try {
- $result = $this->ipLocationResolver->resolveIpLocation($ipAddr);
-
- $location = new VisitLocation($result);
- $visit->setVisitLocation($location);
- $this->visitService->saveVisit($visit);
-
- $io->writeln(sprintf(
- ' [' . $this->translator->translate('Address located at "%s"') . ']',
- $location->getCountryName()
- ));
- } catch (WrongIpException $e) {
- $io->writeln(
- sprintf(
- ' [%s>]',
- $this->translator->translate('An error occurred while locating IP. Skipped')
- )
- );
- if ($io->isVerbose()) {
- $this->getApplication()->renderException($e, $output);
- }
- }
+ $this->processVisit($io, $visit, false);
}
$io->success($this->translator->translate('Finished processing all IPs'));
}
+
+ private function processVisit(SymfonyStyle $io, Visit $visit, bool $clear): void
+ {
+ if (! $visit->hasRemoteAddr()) {
+ $io->writeln(
+ sprintf('%s', $this->translator->translate('Ignored visit with no IP address')),
+ OutputInterface::VERBOSITY_VERBOSE
+ );
+ return;
+ }
+
+ $ipAddr = $visit->getRemoteAddr();
+ $io->write(sprintf('%s %s>', $this->translator->translate('Processing IP'), $ipAddr));
+ if ($ipAddr === IpAddress::LOCALHOST) {
+ $io->writeln(
+ sprintf(' [%s]', $this->translator->translate('Ignored localhost address'))
+ );
+ return;
+ }
+
+ try {
+ $result = $this->ipLocationResolver->resolveIpLocation($ipAddr);
+ } catch (WrongIpException $e) {
+ $io->writeln(
+ sprintf(
+ ' [%s>]',
+ $this->translator->translate('An error occurred while locating IP. Skipped')
+ )
+ );
+ if ($io->isVerbose()) {
+ $this->getApplication()->renderException($e, $output);
+ }
+
+ return;
+ }
+
+ $location = new VisitLocation($result);
+ $this->visitService->locateVisit($visit, $location, $clear);
+ $io->writeln(sprintf(
+ ' [' . $this->translator->translate('Address located at "%s"') . ']',
+ $location->getCountryName()
+ ));
+ }
}
diff --git a/module/CLI/test/Command/ShortUrl/GetVisitsCommandTest.php b/module/CLI/test/Command/ShortUrl/GetVisitsCommandTest.php
index f7523d78..d36c798a 100644
--- a/module/CLI/test/Command/ShortUrl/GetVisitsCommandTest.php
+++ b/module/CLI/test/Command/ShortUrl/GetVisitsCommandTest.php
@@ -81,7 +81,7 @@ class GetVisitsCommandTest extends TestCase
{
$shortCode = 'abc123';
$this->visitsTracker->info($shortCode, Argument::any())->willReturn([
- (new Visit(new ShortUrl(''), new Visitor('bar', 'foo', '')))->setVisitLocation(
+ (new Visit(new ShortUrl(''), new Visitor('bar', 'foo', '')))->locate(
new VisitLocation(['country_name' => 'Spain'])
),
])->shouldBeCalledOnce();
diff --git a/module/CLI/test/Command/Visit/ProcessVisitsCommandTest.php b/module/CLI/test/Command/Visit/ProcessVisitsCommandTest.php
index 5a28e5ab..a0266d4e 100644
--- a/module/CLI/test/Command/Visit/ProcessVisitsCommandTest.php
+++ b/module/CLI/test/Command/Visit/ProcessVisitsCommandTest.php
@@ -64,7 +64,7 @@ class ProcessVisitsCommandTest extends TestCase
$this->visitService->getUnlocatedVisits()->willReturn($visits)
->shouldBeCalledOnce();
- $this->visitService->saveVisit(Argument::any())->shouldBeCalledTimes(count($visits));
+ $this->visitService->locateVisit(Argument::cetera())->shouldBeCalledTimes(count($visits));
$this->ipResolver->resolveIpLocation(Argument::any())->willReturn([])
->shouldBeCalledTimes(count($visits));
@@ -96,7 +96,7 @@ class ProcessVisitsCommandTest extends TestCase
$this->visitService->getUnlocatedVisits()->willReturn($visits)
->shouldBeCalledOnce();
- $this->visitService->saveVisit(Argument::any())->shouldBeCalledTimes(count($visits) - 4);
+ $this->visitService->locateVisit(Argument::cetera())->shouldBeCalledTimes(count($visits) - 4);
$this->ipResolver->resolveIpLocation(Argument::any())->willReturn([])
->shouldBeCalledTimes(count($visits) - 4);
diff --git a/module/Core/src/Entity/Visit.php b/module/Core/src/Entity/Visit.php
index 54926e9e..3fd98db0 100644
--- a/module/Core/src/Entity/Visit.php
+++ b/module/Core/src/Entity/Visit.php
@@ -93,7 +93,7 @@ class Visit extends AbstractEntity implements JsonSerializable
return $this->visitLocation;
}
- public function setVisitLocation(VisitLocation $visitLocation): self
+ public function locate(VisitLocation $visitLocation): self
{
$this->visitLocation = $visitLocation;
return $this;
diff --git a/module/Core/src/Service/VisitService.php b/module/Core/src/Service/VisitService.php
index ab18ce1c..9aea80cb 100644
--- a/module/Core/src/Service/VisitService.php
+++ b/module/Core/src/Service/VisitService.php
@@ -5,6 +5,7 @@ namespace Shlinkio\Shlink\Core\Service;
use Doctrine\ORM\EntityManagerInterface;
use Shlinkio\Shlink\Core\Entity\Visit;
+use Shlinkio\Shlink\Core\Entity\VisitLocation;
use Shlinkio\Shlink\Core\Repository\VisitRepository;
class VisitService implements VisitServiceInterface
@@ -22,19 +23,23 @@ class VisitService implements VisitServiceInterface
/**
* @return Visit[]
*/
- public function getUnlocatedVisits()
+ public function getUnlocatedVisits(): array
{
/** @var VisitRepository $repo */
$repo = $this->em->getRepository(Visit::class);
return $repo->findUnlocatedVisits();
}
- /**
- * @param Visit $visit
- */
- public function saveVisit(Visit $visit)
+ public function locateVisit(Visit $visit, VisitLocation $location, bool $clear = false): void
{
+ $visit->locate($location);
+
$this->em->persist($visit);
$this->em->flush();
+
+ if ($clear) {
+ $this->em->clear(VisitLocation::class);
+ $this->em->clear(Visit::class);
+ }
}
}
diff --git a/module/Core/src/Service/VisitServiceInterface.php b/module/Core/src/Service/VisitServiceInterface.php
index 46f6ceb7..2b5d5811 100644
--- a/module/Core/src/Service/VisitServiceInterface.php
+++ b/module/Core/src/Service/VisitServiceInterface.php
@@ -4,16 +4,14 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Service;
use Shlinkio\Shlink\Core\Entity\Visit;
+use Shlinkio\Shlink\Core\Entity\VisitLocation;
interface VisitServiceInterface
{
/**
* @return Visit[]
*/
- public function getUnlocatedVisits();
+ public function getUnlocatedVisits(): array;
- /**
- * @param Visit $visit
- */
- public function saveVisit(Visit $visit);
+ public function locateVisit(Visit $visit, VisitLocation $location, bool $clear = false): void;
}
diff --git a/module/Core/test-func/Repository/VisitRepositoryTest.php b/module/Core/test-func/Repository/VisitRepositoryTest.php
index 886cce70..683009cd 100644
--- a/module/Core/test-func/Repository/VisitRepositoryTest.php
+++ b/module/Core/test-func/Repository/VisitRepositoryTest.php
@@ -45,7 +45,7 @@ class VisitRepositoryTest extends DatabaseTestCase
if ($i % 2 === 0) {
$location = new VisitLocation([]);
$this->getEntityManager()->persist($location);
- $visit->setVisitLocation($location);
+ $visit->locate($location);
}
$this->getEntityManager()->persist($visit);
diff --git a/module/Core/test/Service/VisitServiceTest.php b/module/Core/test/Service/VisitServiceTest.php
index 728d18ee..cc8193be 100644
--- a/module/Core/test/Service/VisitServiceTest.php
+++ b/module/Core/test/Service/VisitServiceTest.php
@@ -8,6 +8,7 @@ use PHPUnit\Framework\TestCase;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Core\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Entity\Visit;
+use Shlinkio\Shlink\Core\Entity\VisitLocation;
use Shlinkio\Shlink\Core\Model\Visitor;
use Shlinkio\Shlink\Core\Repository\VisitRepository;
use Shlinkio\Shlink\Core\Service\VisitService;
@@ -32,12 +33,12 @@ class VisitServiceTest extends TestCase
/**
* @test
*/
- public function saveVisitsPersistsProvidedVisit()
+ public function locateVisitPersistsProvidedVisit()
{
$visit = new Visit(new ShortUrl(''), Visitor::emptyInstance());
$this->em->persist($visit)->shouldBeCalledOnce();
$this->em->flush()->shouldBeCalledOnce();
- $this->visitService->saveVisit($visit);
+ $this->visitService->locateVisit($visit, new VisitLocation([]));
}
/**