Audit item #8. StationController::index was ~100 lines doing the haversine join, in-PHP filter/sort/group, search-row write, and prediction call — well past the "thin orchestrator" line in .claude/rules/architecture.md. - App\Services\StationSearch\SearchCriteria — DTO (lat/lng/fuelType/ radiusKm/sort) - App\Services\StationSearch\SearchResult — DTO (stations, prices summary, reliability counts, prediction payload) - App\Services\StationSearch\StationSearchService::search(criteria, ?user, ?ipHash) — owns the haversine query, the per-row reliability memoisation, sort, count, search-row logging, and the tier-gated prediction. The controller now resolves coordinates, builds a SearchCriteria, calls the service, and shapes the JSON response. Down from 154 → 71 lines. Public API contract unchanged — all 15 StationController tests pass without modification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
22 lines
661 B
PHP
22 lines
661 B
PHP
<?php
|
|
|
|
namespace App\Services\StationSearch;
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
final readonly class SearchResult
|
|
{
|
|
/**
|
|
* @param Collection<int, mixed> $stations Sorted station rows with _updated_at/_reliability/_classification cached
|
|
* @param array{lowest: ?int, highest: ?int, avg: ?float} $pricesSummary
|
|
* @param array{reliable: int, stale: int, outdated: int} $reliabilityCounts
|
|
* @param array<string, mixed> $prediction
|
|
*/
|
|
public function __construct(
|
|
public Collection $stations,
|
|
public array $pricesSummary,
|
|
public array $reliabilityCounts,
|
|
public array $prediction,
|
|
) {}
|
|
}
|