From 44db1255722faace727ed56a138c7ab02dc73a21 Mon Sep 17 00:00:00 2001 From: stevan Date: Tue, 7 Oct 2025 14:37:51 +0200 Subject: [PATCH] Make command re-geocodes from location for non event online --- .../Commands/FixNonOnlineCentroidEvents.php | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 app/Console/Commands/FixNonOnlineCentroidEvents.php diff --git a/app/Console/Commands/FixNonOnlineCentroidEvents.php b/app/Console/Commands/FixNonOnlineCentroidEvents.php new file mode 100644 index 000000000..92b18f9c1 --- /dev/null +++ b/app/Console/Commands/FixNonOnlineCentroidEvents.php @@ -0,0 +1,163 @@ +option('dry-run'); + $limit = (int) $this->option('limit'); + + $this->info(sprintf( + 'Starting NON-ONLINE fix (dry-run: %s, limit: %s, match geoposition: %s)', + $dryRun ? 'YES' : 'NO', + $limit > 0 ? $limit : '∞', + self::BAD_GEO + )); + + $query = Event::query() + ->where('activity_type', '!=', 'open-online') + ->whereNotNull('location') + ->whereRaw("NULLIF(TRIM(location), '') IS NOT NULL") + ->where('location', '<>', ',') + ->where('geoposition', self::BAD_GEO) + ->orderBy('id'); + + $total = (clone $query)->count(); + if ($total === 0) { + $this->info('No matching events found. Nothing to do.'); + return self::SUCCESS; + } + + $this->info("Found {$total} candidate event(s)."); + $toProcess = ($limit > 0) ? min($limit, $total) : $total; + + $bar = $this->output->createProgressBar($toProcess); + $bar->start(); + + $summary = [ + 'processed' => 0, + 'updated' => 0, + 'no_candidate' => 0, + 'errors' => 0, + ]; + + $rows = []; + + try { + $query->chunkById(100, function ($events) use (&$summary, $dryRun, $bar, &$rows, $toProcess) { + /** @var Event $event */ + foreach ($events as $event) { + if ($summary['processed'] >= $toProcess) { + return false; // stop chunking + } + + $summary['processed']++; + + $loc = trim((string) $event->location); + $oldGeo = $event->geoposition; + + try { + $candidate = GeolocationHelper::getCoordinates($loc); + + if ( + empty($candidate) + || empty($candidate['location']['y']) + || empty($candidate['location']['x']) + ) { + $summary['no_candidate']++; + $rows[] = [$event->id, $loc, $oldGeo, '—', '—', 'NO_CANDIDATE']; + $bar->advance(); + continue; + } + + $newLat = (float) $candidate['location']['y']; + $newLng = (float) $candidate['location']['x']; + $newGeo = sprintf('%F,%F', $newLat, $newLng); + + if ($dryRun) { + $summary['updated']++; + $rows[] = [$event->id, $loc, $oldGeo, $newLat, $newLng, 'WOULD_UPDATE']; + $bar->advance(); + continue; + } + + DB::transaction(function () use ($event, $newLat, $newLng, $newGeo) { + $event->latitude = $newLat; + $event->longitude = $newLng; + $event->geoposition = $newGeo; + $event->save(); + }); + + $summary['updated']++; + $rows[] = [$event->id, $loc, $oldGeo, $newLat, $newLng, 'UPDATED']; + } catch (\Throwable $e) { + $summary['errors']++; + Log::error('FixNonOnlineCentroidEvents error', [ + 'event_id' => $event->id, + 'location' => $loc, + 'exception' => $e->getMessage(), + ]); + $rows[] = [$event->id, $loc, $oldGeo, '—', '—', 'ERROR: '.$e->getMessage()]; + } finally { + $bar->advance(); + } + } + }); + } catch (\Throwable $e) { + $bar->finish(); + $this->error('Aborted due to an unexpected error: '.$e->getMessage()); + Log::error('FixNonOnlineCentroidEvents fatal', ['exception' => $e]); + return self::FAILURE; + } + + $bar->finish(); + $this->newLine(2); + + $this->info('Summary:'); + $this->line(sprintf( + 'Processed: %d | Updated: %d | No candidate: %d | Errors: %d', + $summary['processed'], + $summary['updated'], + $summary['no_candidate'], + $summary['errors'] + )); + + $this->table( + ['Event ID', 'Location (text)', 'Old geoposition', 'New lat', 'New lng', 'Result'], + $rows + ); + + return self::SUCCESS; + } +}