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