2019-08-09 02:52:34 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
2021-03-30 03:49:34 +08:00
|
|
|
use App\Contracts\AirportLookup;
|
2019-08-09 02:52:34 +08:00
|
|
|
use App\Contracts\Metar as MetarProvider;
|
|
|
|
use App\Contracts\Service;
|
2019-08-27 00:32:46 +08:00
|
|
|
use App\Exceptions\AirportNotFound;
|
2019-10-24 00:01:31 +08:00
|
|
|
use App\Models\Airport;
|
2019-08-27 00:32:46 +08:00
|
|
|
use App\Repositories\AirportRepository;
|
2019-08-09 02:52:34 +08:00
|
|
|
use App\Support\Metar;
|
2019-08-27 00:32:46 +08:00
|
|
|
use App\Support\Units\Distance;
|
2019-08-23 02:32:49 +08:00
|
|
|
use Illuminate\Support\Facades\Cache;
|
2019-08-27 00:32:46 +08:00
|
|
|
use League\Geotools\Coordinate\Coordinate;
|
|
|
|
use League\Geotools\Geotools;
|
|
|
|
use PhpUnitsOfMeasure\Exception\NonNumericValue;
|
|
|
|
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
|
2019-08-09 02:52:34 +08:00
|
|
|
|
|
|
|
class AirportService extends Service
|
|
|
|
{
|
2019-08-27 00:32:46 +08:00
|
|
|
private $airportRepo;
|
2019-08-23 02:32:49 +08:00
|
|
|
private $lookupProvider;
|
2019-08-09 02:52:34 +08:00
|
|
|
private $metarProvider;
|
|
|
|
|
|
|
|
public function __construct(
|
2021-03-30 03:49:34 +08:00
|
|
|
AirportLookup $lookupProvider,
|
2019-08-27 00:32:46 +08:00
|
|
|
AirportRepository $airportRepo,
|
2019-08-09 02:52:34 +08:00
|
|
|
MetarProvider $metarProvider
|
|
|
|
) {
|
2019-08-27 00:32:46 +08:00
|
|
|
$this->airportRepo = $airportRepo;
|
2019-08-23 02:32:49 +08:00
|
|
|
$this->lookupProvider = $lookupProvider;
|
2019-08-09 02:52:34 +08:00
|
|
|
$this->metarProvider = $metarProvider;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the METAR for a given airport
|
|
|
|
*
|
|
|
|
* @param $icao
|
|
|
|
*
|
|
|
|
* @return Metar|null
|
|
|
|
*/
|
2019-08-09 05:41:53 +08:00
|
|
|
public function getMetar($icao)
|
2019-08-09 02:52:34 +08:00
|
|
|
{
|
2019-08-09 05:41:53 +08:00
|
|
|
$icao = trim($icao);
|
|
|
|
if ($icao === '') {
|
|
|
|
return;
|
|
|
|
}
|
2019-08-09 02:52:34 +08:00
|
|
|
|
2021-02-20 01:45:39 +08:00
|
|
|
$raw_metar = $this->metarProvider->metar($icao);
|
2019-08-09 02:52:34 +08:00
|
|
|
if ($raw_metar && $raw_metar !== '') {
|
|
|
|
return new Metar($raw_metar);
|
|
|
|
}
|
|
|
|
}
|
2019-08-23 02:32:49 +08:00
|
|
|
|
2021-02-20 01:45:39 +08:00
|
|
|
/**
|
|
|
|
* Return the METAR for a given airport
|
|
|
|
*
|
|
|
|
* @param $icao
|
|
|
|
*
|
|
|
|
* @return Metar|null
|
|
|
|
*/
|
|
|
|
public function getTaf($icao)
|
|
|
|
{
|
|
|
|
$icao = trim($icao);
|
|
|
|
if ($icao === '') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$raw_taf = $this->metarProvider->taf($icao);
|
|
|
|
if ($raw_taf && $raw_taf !== '') {
|
|
|
|
return new Metar($raw_taf, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-23 02:32:49 +08:00
|
|
|
/**
|
|
|
|
* Lookup an airport's information from a remote provider. This handles caching
|
|
|
|
* the data internally
|
|
|
|
*
|
|
|
|
* @param string $icao ICAO
|
|
|
|
*
|
2019-09-06 04:55:51 +08:00
|
|
|
* @return mixed
|
2019-08-23 02:32:49 +08:00
|
|
|
*/
|
|
|
|
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 [];
|
|
|
|
}
|
|
|
|
|
2019-10-24 00:01:31 +08:00
|
|
|
$airport = (array) $airport;
|
|
|
|
|
2019-08-23 02:32:49 +08:00
|
|
|
Cache::add(
|
|
|
|
$key,
|
|
|
|
$airport,
|
|
|
|
config('cache.keys.AIRPORT_VACENTRAL_LOOKUP.time')
|
|
|
|
);
|
|
|
|
|
|
|
|
return $airport;
|
|
|
|
}
|
2019-08-27 00:32:46 +08:00
|
|
|
|
2019-10-24 00:01:31 +08:00
|
|
|
/**
|
|
|
|
* Lookup an airport and save it if it hasn't been found
|
|
|
|
*
|
|
|
|
* @param string $icao
|
|
|
|
*
|
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null
|
|
|
|
*/
|
|
|
|
public function lookupAirportIfNotFound($icao)
|
|
|
|
{
|
|
|
|
$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;
|
|
|
|
}
|
|
|
|
|
|
|
|
$airport = new Airport($lookup);
|
|
|
|
$airport->save();
|
|
|
|
|
|
|
|
return $airport;
|
|
|
|
}
|
|
|
|
|
2019-08-27 00:32:46 +08:00
|
|
|
/**
|
|
|
|
* Calculate the distance from one airport to another
|
|
|
|
*
|
|
|
|
* @param string $fromIcao
|
|
|
|
* @param string $toIcao
|
|
|
|
*
|
|
|
|
* @return Distance
|
|
|
|
*/
|
|
|
|
public function calculateDistance($fromIcao, $toIcao)
|
|
|
|
{
|
|
|
|
$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]);
|
|
|
|
$dist = $geotools->distance()->setFrom($start)->setTo($end);
|
|
|
|
|
|
|
|
// Convert into a Distance object
|
|
|
|
try {
|
|
|
|
$distance = new Distance($dist->in('mi')->greatCircle(), 'mi');
|
|
|
|
return $distance;
|
|
|
|
} catch (NonNumericValue $e) {
|
|
|
|
return;
|
|
|
|
} catch (NonStringUnitName $e) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-08-09 02:52:34 +08:00
|
|
|
}
|