mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-06 23:33:13 +08:00
Extract logic to send visits to Matomo to its own service
This commit is contained in:
@@ -40,7 +40,7 @@ class ShortUrlMethodsProcessor
|
||||
$redirectStatus = RedirectStatus::tryFrom(
|
||||
$config['redirects']['redirect_status_code'] ?? 0,
|
||||
) ?? DEFAULT_REDIRECT_STATUS_CODE;
|
||||
$redirectRoute['allowed_methods'] = $redirectStatus->isLegacyStatus()
|
||||
$redirectRoute['allowed_methods'] = $redirectStatus->isGetOnlyStatus()
|
||||
? [RequestMethodInterface::METHOD_GET]
|
||||
: Route::HTTP_METHOD_ANY;
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Shlinkio\Shlink\Core\EventDispatcher\Event\VisitLocated;
|
||||
use Shlinkio\Shlink\Core\Matomo\MatomoOptions;
|
||||
use Shlinkio\Shlink\Core\Matomo\MatomoTrackerBuilderInterface;
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifier;
|
||||
use Shlinkio\Shlink\Core\Matomo\MatomoVisitSenderInterface;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
use Throwable;
|
||||
|
||||
@@ -18,9 +17,8 @@ readonly class SendVisitToMatomo
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
private LoggerInterface $logger,
|
||||
private ShortUrlStringifier $shortUrlStringifier,
|
||||
private MatomoOptions $matomoOptions,
|
||||
private MatomoTrackerBuilderInterface $trackerBuilder,
|
||||
private MatomoVisitSenderInterface $visitSender,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -42,48 +40,10 @@ readonly class SendVisitToMatomo
|
||||
}
|
||||
|
||||
try {
|
||||
$tracker = $this->trackerBuilder->buildMatomoTracker();
|
||||
|
||||
$tracker
|
||||
->setUrl($this->resolveUrlToTrack($visit))
|
||||
->setCustomTrackingParameter('type', $visit->type->value)
|
||||
->setUserAgent($visit->userAgent)
|
||||
->setUrlReferrer($visit->referer);
|
||||
|
||||
$location = $visit->getVisitLocation();
|
||||
if ($location !== null) {
|
||||
$tracker
|
||||
->setCity($location->cityName)
|
||||
->setCountry($location->countryName)
|
||||
->setLatitude($location->latitude)
|
||||
->setLongitude($location->longitude);
|
||||
}
|
||||
|
||||
// Set not obfuscated IP if possible, as matomo handles obfuscation itself
|
||||
$ip = $visitLocated->originalIpAddress ?? $visit->remoteAddr;
|
||||
if ($ip !== null) {
|
||||
$tracker->setIp($ip);
|
||||
}
|
||||
|
||||
if ($visit->isOrphan()) {
|
||||
$tracker->setCustomTrackingParameter('orphan', 'true');
|
||||
}
|
||||
|
||||
// Send the short URL title or an empty document title to avoid different actions to be created by matomo
|
||||
$tracker->doTrackPageView($visit->shortUrl?->title() ?? '');
|
||||
$this->visitSender->sendVisitToMatomo($visit, $visitLocated->originalIpAddress);
|
||||
} catch (Throwable $e) {
|
||||
// Capture all exceptions to make sure this does not interfere with the regular execution
|
||||
$this->logger->error('An error occurred while trying to send visit to Matomo. {e}', ['e' => $e]);
|
||||
}
|
||||
}
|
||||
|
||||
public function resolveUrlToTrack(Visit $visit): string
|
||||
{
|
||||
$shortUrl = $visit->shortUrl;
|
||||
if ($shortUrl === null) {
|
||||
return $visit->visitedUrl ?? '';
|
||||
}
|
||||
|
||||
return $this->shortUrlStringifier->stringify($shortUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ namespace Shlinkio\Shlink\Core\Matomo;
|
||||
use MatomoTracker;
|
||||
use Shlinkio\Shlink\Core\Exception\RuntimeException;
|
||||
|
||||
class MatomoTrackerBuilder implements MatomoTrackerBuilderInterface
|
||||
readonly class MatomoTrackerBuilder implements MatomoTrackerBuilderInterface
|
||||
{
|
||||
public const MATOMO_DEFAULT_TIMEOUT = 10; // Time in seconds
|
||||
|
||||
public function __construct(private readonly MatomoOptions $options)
|
||||
public function __construct(private MatomoOptions $options)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
60
module/Core/src/Matomo/MatomoVisitSender.php
Normal file
60
module/Core/src/Matomo/MatomoVisitSender.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Matomo;
|
||||
|
||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifier;
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
|
||||
readonly class MatomoVisitSender implements MatomoVisitSenderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MatomoTrackerBuilderInterface $trackerBuilder,
|
||||
private ShortUrlStringifier $shortUrlStringifier,
|
||||
) {
|
||||
}
|
||||
|
||||
public function sendVisitToMatomo(Visit $visit, ?string $originalIpAddress = null): void
|
||||
{
|
||||
$tracker = $this->trackerBuilder->buildMatomoTracker();
|
||||
|
||||
$tracker
|
||||
->setUrl($this->resolveUrlToTrack($visit))
|
||||
->setCustomTrackingParameter('type', $visit->type->value)
|
||||
->setUserAgent($visit->userAgent)
|
||||
->setUrlReferrer($visit->referer);
|
||||
|
||||
$location = $visit->getVisitLocation();
|
||||
if ($location !== null) {
|
||||
$tracker
|
||||
->setCity($location->cityName)
|
||||
->setCountry($location->countryName)
|
||||
->setLatitude($location->latitude)
|
||||
->setLongitude($location->longitude);
|
||||
}
|
||||
|
||||
// Set not obfuscated IP if possible, as matomo handles obfuscation itself
|
||||
$ip = $originalIpAddress ?? $visit->remoteAddr;
|
||||
if ($ip !== null) {
|
||||
$tracker->setIp($ip);
|
||||
}
|
||||
|
||||
if ($visit->isOrphan()) {
|
||||
$tracker->setCustomTrackingParameter('orphan', 'true');
|
||||
}
|
||||
|
||||
// Send the short URL title or an empty document title to avoid different actions to be created by matomo
|
||||
$tracker->doTrackPageView($visit->shortUrl?->title() ?? '');
|
||||
}
|
||||
|
||||
private function resolveUrlToTrack(Visit $visit): string
|
||||
{
|
||||
$shortUrl = $visit->shortUrl;
|
||||
if ($shortUrl === null) {
|
||||
return $visit->visitedUrl ?? '';
|
||||
}
|
||||
|
||||
return $this->shortUrlStringifier->stringify($shortUrl);
|
||||
}
|
||||
}
|
||||
12
module/Core/src/Matomo/MatomoVisitSenderInterface.php
Normal file
12
module/Core/src/Matomo/MatomoVisitSenderInterface.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\Core\Matomo;
|
||||
|
||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||
|
||||
interface MatomoVisitSenderInterface
|
||||
{
|
||||
public function sendVisitToMatomo(Visit $visit, ?string $originalIpAddress = null): void;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ enum RedirectStatus: int
|
||||
return contains($this, [self::STATUS_301, self::STATUS_308]);
|
||||
}
|
||||
|
||||
public function isLegacyStatus(): bool
|
||||
public function isGetOnlyStatus(): bool
|
||||
{
|
||||
return contains($this, [self::STATUS_301, self::STATUS_302]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user