phpvms/app/Services/AirportService.php
Arthur Parienté acd38c9fa8
[8.x] feat: Filament Import Export (#2136)
* add migrations

* add setting to choose which importers to use

* bump filament

* enable database notifications

* add AirportImporter and AirportExporter

* move the untrash code to beforeUpdate

* fix validation rules

* add AircraftImporter and AircraftExporter

* fix phpstan

* add ExpenseImporter and ExpenseExporter

* add FareImporter and FareExporter

* add FlightImporter and FlightExporter

* add SubfleetImporter and SubfleetExporter

* change how relationships are processed in FlightImporter

* restore records if they are trashed after import

* phpstan and types

* fix packages

* remove foreign keys

* apply some of the fixes suggested by CodeRabbit

* fix docstring

* re add the fk

* bump filament
2026-01-09 16:10:53 -06:00

169 lines
4.2 KiB
PHP

<?php
namespace App\Services;
use App\Contracts\AirportLookup;
use App\Contracts\Metar as MetarProvider;
use App\Contracts\Service;
use App\Exceptions\AirportNotFound;
use App\Models\Airport;
use App\Repositories\AirportRepository;
use App\Support\Metar;
use App\Support\Units\Distance;
use Illuminate\Support\Facades\Cache;
use League\Geotools\Coordinate\Coordinate;
use League\Geotools\Geotools;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
class AirportService extends Service
{
public function __construct(
private readonly AirportLookup $lookupProvider,
private readonly AirportRepository $airportRepo,
private readonly MetarProvider $metarProvider
) {}
/**
* Return the METAR for a given airport
*/
public function getMetar($icao): ?Metar
{
$icao = trim($icao);
if ($icao === '') {
return null;
}
$raw_metar = $this->metarProvider->metar($icao);
if ($raw_metar !== '' && $raw_metar !== '0') {
return new Metar($raw_metar);
}
return null;
}
/**
* Return the METAR for a given airport
*/
public function getTaf($icao): ?Metar
{
$icao = trim($icao);
if ($icao === '') {
return null;
}
$raw_taf = $this->metarProvider->taf($icao);
if ($raw_taf !== '' && $raw_taf !== '0') {
return new Metar($raw_taf, true);
}
return null;
}
/**
* Lookup an airport's information from a remote provider. This handles caching
* the data internally
*
* @param string $icao ICAO
* @return mixed
*/
public function lookupAirport($icao)
{
$key = config('cache.keys.AIRPORT_VACENTRAL_LOOKUP.key').$icao;
$airport = Cache::get($key);
if ($airport) {
return $airport;
}
$airport = $this->lookupProvider->getAirport($icao);
if ($airport === null) {
return [];
}
$airport = (array) $airport;
Cache::add(
$key,
$airport,
config('cache.keys.AIRPORT_VACENTRAL_LOOKUP.time')
);
return $airport;
}
/**
* Lookup an airport and save it if it hasn't been found
*
* @param string $icao
*/
public function lookupAirportIfNotFound($icao): ?Airport
{
$icao = strtoupper($icao);
$airport = $this->airportRepo->findWithoutFail($icao);
if ($airport !== null) {
return $airport;
}
// Don't lookup the airport, so just add in something generic
if (!setting('general.auto_airport_lookup')) {
$airport = new Airport([
'id' => $icao,
'icao' => $icao,
'name' => $icao,
'lat' => 0,
'lon' => 0,
]);
$airport->save();
return $airport;
}
$lookup = $this->lookupAirport($icao);
if (empty($lookup)) {
return null;
}
$airport = new Airport($lookup);
$airport->save();
return $airport;
}
/**
* Calculate the distance from one airport to another
*/
public function calculateDistance(string $fromIcao, string $toIcao): ?Distance
{
$from = $this->airportRepo->find($fromIcao, ['lat', 'lon']);
$to = $this->airportRepo->find($toIcao, ['lat', 'lon']);
if (!$from) {
throw new AirportNotFound($fromIcao);
}
if (!$to) {
throw new AirportNotFound($toIcao);
}
// Calculate the distance
$geotools = new Geotools();
$start = new Coordinate([$from->lat, $from->lon]);
$end = new Coordinate([$to->lat, $to->lon]);
/** @var \League\Geotools\Distance\Distance $dist */
$dist = $geotools->distance()->setFrom($start)->setTo($end)->in('mi');
// Convert into a Distance object
try {
$distance = new Distance($dist->greatCircle(), 'mi');
return $distance;
} catch (NonNumericValue $e) {
return null;
} catch (NonStringUnitName $e) {
return null;
}
}
}