diff --git a/module/Core/src/Visit/VisitsTracker.php b/module/Core/src/Visit/VisitsTracker.php index 9e4b88df..dd520e8f 100644 --- a/module/Core/src/Visit/VisitsTracker.php +++ b/module/Core/src/Visit/VisitsTracker.php @@ -12,12 +12,12 @@ use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\Visit\Entity\Visit; use Shlinkio\Shlink\Core\Visit\Model\Visitor; -class VisitsTracker implements VisitsTrackerInterface +readonly class VisitsTracker implements VisitsTrackerInterface { public function __construct( - private readonly ORM\EntityManagerInterface $em, - private readonly EventDispatcherInterface $eventDispatcher, - private readonly TrackingOptions $options, + private ORM\EntityManagerInterface $em, + private EventDispatcherInterface $eventDispatcher, + private TrackingOptions $options, ) { } @@ -71,10 +71,12 @@ class VisitsTracker implements VisitsTrackerInterface return; } - $visit = $createVisit($visitor->normalizeForTrackingOptions($this->options)); - $this->em->persist($visit); - $this->em->flush(); + $this->em->wrapInTransaction(function () use ($createVisit, $visitor): void { + $visit = $createVisit($visitor->normalizeForTrackingOptions($this->options)); + $this->em->persist($visit); + $this->em->flush(); - $this->eventDispatcher->dispatch(new UrlVisited($visit->getId(), $visitor->remoteAddress)); + $this->eventDispatcher->dispatch(new UrlVisited($visit->getId(), $visitor->remoteAddress)); + }); } } diff --git a/module/Core/test/Visit/VisitsTrackerTest.php b/module/Core/test/Visit/VisitsTrackerTest.php index 32cd10a8..d6cbf4bf 100644 --- a/module/Core/test/Visit/VisitsTrackerTest.php +++ b/module/Core/test/Visit/VisitsTrackerTest.php @@ -25,6 +25,8 @@ class VisitsTrackerTest extends TestCase protected function setUp(): void { $this->em = $this->createMock(EntityManager::class); + $this->em->method('wrapInTransaction')->willReturnCallback(fn (callable $callback) => $callback()); + $this->eventDispatcher = $this->createMock(EventDispatcherInterface::class); }