em = $em; } public function locateUnlocatedVisits(callable $geolocateVisit, ?callable $notifyVisitWithLocation = null): void { /** @var VisitRepository $repo */ $repo = $this->em->getRepository(Visit::class); $results = $repo->findUnlocatedVisits(false); $count = 0; $persistBlock = 200; foreach ($results as $visit) { $count++; try { /** @var Location $location */ $location = $geolocateVisit($visit); } catch (IpCannotBeLocatedException $e) { if (!$e->isNonLocatableAddress()) { // Skip if the visit's IP could not be located because of an error continue; } // If the IP address is non-locatable, locate it as empty to prevent next processes to pick it again $location = Location::emptyInstance(); } $location = new VisitLocation($location); $this->locateVisit($visit, $location, $notifyVisitWithLocation); // Flush and clear after X iterations if ($count % $persistBlock === 0) { $this->em->flush(); $this->em->clear(); } } $this->em->flush(); $this->em->clear(); } private function locateVisit(Visit $visit, VisitLocation $location, ?callable $notifyVisitWithLocation): void { $visit->locate($location); $this->em->persist($visit); if ($notifyVisitWithLocation !== null) { $notifyVisitWithLocation($location, $visit); } } }