Passed
Pull Request — master (#417)
by Alejandro
06:44
created

LocateShortUrlVisit   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 67
Duplicated Lines 0 %

Test Coverage

Coverage 96.88%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 8
eloc 36
c 2
b 0
f 0
dl 0
loc 67
ccs 31
cts 32
cp 0.9688
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
B __invoke() 0 44 7
A __construct() 0 10 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\Core\EventDispatcher;
5
6
use Doctrine\ORM\EntityManagerInterface;
7
use Psr\Log\LoggerInterface;
8
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
9
use Shlinkio\Shlink\CLI\Util\GeolocationDbUpdaterInterface;
10
use Shlinkio\Shlink\Common\Exception\WrongIpException;
11
use Shlinkio\Shlink\Common\IpGeolocation\IpLocationResolverInterface;
12
use Shlinkio\Shlink\Common\IpGeolocation\Model\Location;
13
use Shlinkio\Shlink\Core\Entity\Visit;
14
use Shlinkio\Shlink\Core\Entity\VisitLocation;
15
16
use function sprintf;
17
18
class LocateShortUrlVisit
19
{
20
    /** @var IpLocationResolverInterface */
21
    private $ipLocationResolver;
22
    /** @var EntityManagerInterface */
23
    private $em;
24
    /** @var LoggerInterface */
25
    private $logger;
26
    /** @var GeolocationDbUpdaterInterface */
27
    private $dbUpdater;
28
29 8
    public function __construct(
30
        IpLocationResolverInterface $ipLocationResolver,
31
        EntityManagerInterface $em,
32
        LoggerInterface $logger,
33
        GeolocationDbUpdaterInterface $dbUpdater
34
    ) {
35 8
        $this->ipLocationResolver = $ipLocationResolver;
36 8
        $this->em = $em;
37 8
        $this->logger = $logger;
38 8
        $this->dbUpdater = $dbUpdater;
39
    }
40
41 8
    public function __invoke(ShortUrlVisited $shortUrlVisited): void
42
    {
43 8
        $visitId = $shortUrlVisited->visitId();
44
45
        /** @var Visit|null $visit */
46 8
        $visit = $this->em->find(Visit::class, $visitId);
47 8
        if ($visit === null) {
48 1
            $this->logger->warning(sprintf('Tried to locate visit with id "%s", but it does not exist.', $visitId));
49 1
            return;
50
        }
51
52
        try {
53
            $this->dbUpdater->checkDbUpdate(function (bool $olderDbExists) {
54
                $this->logger->notice(sprintf('%s GeoLite2 database...', $olderDbExists ? 'Updating' : 'Downloading'));
55 7
            });
56 2
        } catch (GeolocationDbUpdateFailedException $e) {
57 2
            if (! $e->olderDbExists()) {
58 1
                $this->logger->error(
59 1
                    sprintf(
60 1
                        'GeoLite2 database download failed. It is not possible to locate visit with id %s. {e}',
61 1
                        $visitId
62
                    ),
63 1
                    ['e' => $e]
64
                );
65 1
                return;
66
            }
67
68 1
            $this->logger->warning('GeoLite2 database update failed. Proceeding with old version. {e}', ['e' => $e]);
69
        }
70
71
        try {
72 6
            $location = $visit->isLocatable()
73 3
                ? $this->ipLocationResolver->resolveIpLocation($visit->getRemoteAddr())
74 5
                : Location::emptyInstance();
75 1
        } catch (WrongIpException $e) {
76 1
            $this->logger->warning(
77 1
                sprintf('Tried to locate visit with id "%s", but its address seems to be wrong. {e}', $visitId),
78 1
                ['e' => $e]
79
            );
80 1
            return;
81
        }
82
83 5
        $visit->locate(new VisitLocation($location));
84 5
        $this->em->flush($visit);
85
    }
86
}
87