trackVisit( fn (Visitor $v) => Visit::forValidShortUrl($shortUrl, $v, $this->options->anonymizeRemoteAddr), $visitor, ); } public function trackInvalidShortUrlVisit(Visitor $visitor): void { $this->trackOrphanVisit( fn (Visitor $v) => Visit::forInvalidShortUrl($v, $this->options->anonymizeRemoteAddr), $visitor, ); } public function trackBaseUrlVisit(Visitor $visitor): void { $this->trackOrphanVisit( fn (Visitor $v) => Visit::forBasePath($v, $this->options->anonymizeRemoteAddr), $visitor, ); } public function trackRegularNotFoundVisit(Visitor $visitor): void { $this->trackOrphanVisit( fn (Visitor $v) => Visit::forRegularNotFound($v, $this->options->anonymizeRemoteAddr), $visitor, ); } private function trackOrphanVisit(callable $createVisit, Visitor $visitor): void { if (! $this->options->trackOrphanVisits) { return; } $this->trackVisit($createVisit, $visitor); } /** * @param callable(Visitor $visitor): Visit $createVisit */ private function trackVisit(callable $createVisit, Visitor $visitor): void { if ($this->options->disableTracking) { return; } $visit = $createVisit($visitor->normalizeForTrackingOptions($this->options)); // Wrap persisting and flushing the visit in a transaction, so that the ShortUrlVisitsCountTracker performs // changes inside that very same transaction atomically $this->em->wrapInTransaction(function () use ($visit): void { $this->em->persist($visit); $this->em->flush(); }); $this->eventDispatcher->dispatch(new UrlVisited($visit->getId(), $visitor->remoteAddress)); } }