phpvms/app/Services/AirportService.php
B.Fatih KOZ b4d5c0fbcd
Weather METAR/TAF enhancements (#964)
* Update AviationWeather.php

Added the ability to fetch latest TAF report of given icao from ADDS/NOAA

* Update Weather.php

Used updated Metar\AviationWeather service to improve the widget ability and provide raw TAF data for the view

* Style Fix 1

* Update weather.blade.php

Updated blade to match updated Metar\AviationWeather service and the Weather widget controller.

Also fixed the order of temp - dewpoint - humidity - visibility display according to aviation usage.

Widget now displays raw TAF data just below raw METAR data.

* Update Metar inferface and wrap TAF retrieval in cache

* Styles fix

* Add call to getTaf. Don't call AviationWeather directly

* Fix cache lookup strings

* Fix recursion error

* Update weather.blade.php

Used latest weather.blade , added $taf['raw'] after raw metar.

* Compatibility Update

Updated the widget controller to match latest dev (added raw_only to config)

* Update Weather Widget Blade

Made the widget blade compatible with the TAF reports, widget will display raw metar and taf after the decoder, if no metar or taf recieved it will be displayed in its own row. Also added the new option of raw_only to blade, if it is true, metar decoding will be skipped and only raw values will be displayed. ( Useful when displaying multiple wx widgets at the same page for departure, destination and alternate etc )

Co-authored-by: Nabeel Shahzad <nshahzad@live.com>
Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-02-19 12:45:39 -05:00

187 lines
4.5 KiB
PHP

<?php
namespace App\Services;
use App\Contracts\AirportLookup as AirportLookupProvider;
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
{
private $airportRepo;
private $lookupProvider;
private $metarProvider;
public function __construct(
AirportLookupProvider $lookupProvider,
AirportRepository $airportRepo,
MetarProvider $metarProvider
) {
$this->airportRepo = $airportRepo;
$this->lookupProvider = $lookupProvider;
$this->metarProvider = $metarProvider;
}
/**
* Return the METAR for a given airport
*
* @param $icao
*
* @return Metar|null
*/
public function getMetar($icao)
{
$icao = trim($icao);
if ($icao === '') {
return;
}
$raw_metar = $this->metarProvider->metar($icao);
if ($raw_metar && $raw_metar !== '') {
return new Metar($raw_metar);
}
}
/**
* 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);
}
}
/**
* 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
*
* @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;
}
/**
* 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;
}
}
}