* #355 Calculate distance button in add/edit Flight page * Styling * Move add/edit flight logic out of controller and into service layer * Styling * Formatting * Run styleci against modules dir * Styleci config * Style fixes in /modules
This commit is contained in:
41
app/Exceptions/AirportNotFound.php
Normal file
41
app/Exceptions/AirportNotFound.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
class AirportNotFound extends HttpException
|
||||
{
|
||||
private $icao;
|
||||
|
||||
public function __construct($icao)
|
||||
{
|
||||
$this->icao = $icao;
|
||||
parent::__construct(
|
||||
404,
|
||||
'Airport '.$icao.' not found'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RFC 7807 error type (without the URL root)
|
||||
*/
|
||||
public function getErrorType(): string
|
||||
{
|
||||
return 'airport-not-found';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detailed error string
|
||||
*/
|
||||
public function getErrorDetails(): string
|
||||
{
|
||||
return $this->getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with the error details, merged with the RFC7807 response
|
||||
*/
|
||||
public function getErrorMetadata(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
45
app/Exceptions/DuplicateFlight.php
Normal file
45
app/Exceptions/DuplicateFlight.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use App\Models\Flight;
|
||||
|
||||
class DuplicateFlight extends HttpException
|
||||
{
|
||||
private $flight;
|
||||
|
||||
public function __construct(Flight $flight)
|
||||
{
|
||||
$this->flight = $flight;
|
||||
parent::__construct(
|
||||
409,
|
||||
'Duplicate flight with same number/code/leg found'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RFC 7807 error type (without the URL root)
|
||||
*/
|
||||
public function getErrorType(): string
|
||||
{
|
||||
return 'duplicate-flight';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the detailed error string
|
||||
*/
|
||||
public function getErrorDetails(): string
|
||||
{
|
||||
return $this->getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with the error details, merged with the RFC7807 response
|
||||
*/
|
||||
public function getErrorMetadata(): array
|
||||
{
|
||||
return [
|
||||
'flight_id' => $this->flight->id,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin;
|
||||
use App\Contracts\Controller;
|
||||
use App\Http\Requests\CreateFlightRequest;
|
||||
use App\Http\Requests\UpdateFlightRequest;
|
||||
use App\Models\Enums\Days;
|
||||
use App\Models\Enums\FlightType;
|
||||
use App\Models\Flight;
|
||||
use App\Models\FlightField;
|
||||
@@ -22,11 +21,9 @@ use App\Services\FleetService;
|
||||
use App\Services\FlightService;
|
||||
use App\Services\ImportService;
|
||||
use App\Support\Units\Time;
|
||||
use Flash;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Response;
|
||||
use Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Laracasts\Flash\Flash;
|
||||
|
||||
/**
|
||||
* Class FlightController
|
||||
@@ -172,28 +169,15 @@ class FlightController extends Controller
|
||||
*/
|
||||
public function store(CreateFlightRequest $request)
|
||||
{
|
||||
$input = $request->all();
|
||||
try {
|
||||
$flight = $this->flightSvc->createFlight($request->all());
|
||||
Flash::success('Flight saved successfully.');
|
||||
|
||||
// Create a temporary flight so we can validate
|
||||
$flight = new Flight($input);
|
||||
if ($this->flightSvc->isFlightDuplicate($flight)) {
|
||||
Flash::error('Duplicate flight with same number/code/leg found, please change to proceed');
|
||||
return redirect(route('admin.flights.edit', $flight->id));
|
||||
} catch (\Exception $e) {
|
||||
Flash::error($e->getMessage());
|
||||
return redirect()->back()->withInput($request->all());
|
||||
}
|
||||
|
||||
if (array_key_exists('days', $input) && filled($input['days'])) {
|
||||
$input['days'] = Days::getDaysMask($input['days']);
|
||||
}
|
||||
|
||||
$input['active'] = get_truth_state($input['active']);
|
||||
|
||||
$time = new Time($input['minutes'], $input['hours']);
|
||||
$input['flight_time'] = $time->getMinutes();
|
||||
|
||||
$flight = $this->flightRepo->create($input);
|
||||
|
||||
Flash::success('Flight saved successfully.');
|
||||
return redirect(route('admin.flights.edit', $flight->id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,32 +252,16 @@ class FlightController extends Controller
|
||||
return redirect(route('admin.flights.index'));
|
||||
}
|
||||
|
||||
$input = $request->all();
|
||||
try {
|
||||
$this->flightSvc->updateFlight($flight, $request->all());
|
||||
Flash::success('Flight updated successfully.');
|
||||
|
||||
// apply the updates here temporarily, don't save
|
||||
// the repo->update() call will actually do it
|
||||
$flight->fill($input);
|
||||
return redirect(route('admin.flights.index'));
|
||||
} catch (\Exception $e) {
|
||||
Flash::error($e->getMessage());
|
||||
|
||||
if ($this->flightSvc->isFlightDuplicate($flight)) {
|
||||
Flash::error('Duplicate flight with same number/code/leg found, please change to proceed');
|
||||
return redirect()->back()->withInput($request->all());
|
||||
}
|
||||
|
||||
if (array_key_exists('days', $input) && filled($input['days'])) {
|
||||
$input['days'] = Days::getDaysMask($input['days']);
|
||||
}
|
||||
|
||||
$input['flight_time'] = Time::init(
|
||||
$input['minutes'],
|
||||
$input['hours']
|
||||
)->getMinutes();
|
||||
|
||||
$input['active'] = get_truth_state($input['active']);
|
||||
|
||||
$this->flightRepo->update($input, $id);
|
||||
|
||||
Flash::success('Flight updated successfully.');
|
||||
return redirect(route('admin.flights.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Contracts\Controller;
|
||||
use App\Http\Resources\Airport as AirportResource;
|
||||
use App\Http\Resources\AirportDistance as AirportDistanceResource;
|
||||
use App\Repositories\AirportRepository;
|
||||
use App\Services\AirportService;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -93,4 +94,22 @@ class AirportController extends Controller
|
||||
$airport = $this->airportSvc->lookupAirport($id);
|
||||
return new AirportResource(collect($airport));
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a lookup, via vaCentral, for the airport information
|
||||
*
|
||||
* @param $fromIcao
|
||||
* @param $toIcao
|
||||
*
|
||||
* @return AirportDistanceResource
|
||||
*/
|
||||
public function distance($fromIcao, $toIcao)
|
||||
{
|
||||
$distance = $this->airportSvc->calculateDistance($fromIcao, $toIcao);
|
||||
return new AirportDistanceResource([
|
||||
'fromIcao' => $fromIcao,
|
||||
'toIcao' => $toIcao,
|
||||
'distance' => $distance,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ class Kernel extends HttpKernel
|
||||
//\Spatie\Pjax\Middleware\FilterIfPjax::class,
|
||||
],
|
||||
];
|
||||
|
||||
protected $routeMiddleware = [
|
||||
'api.auth' => ApiAuth::class,
|
||||
'auth' => Authenticate::class,
|
||||
|
||||
14
app/Http/Resources/AirportDistance.php
Normal file
14
app/Http/Resources/AirportDistance.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
class AirportDistance extends Response
|
||||
{
|
||||
public function toArray($request)
|
||||
{
|
||||
$res = parent::toArray($request);
|
||||
$res['distance'] = $res['distance']->getResponseUnits();
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ Route::group(['middleware' => ['api.auth']], function () {
|
||||
Route::get('airports/hubs', 'AirportController@index_hubs');
|
||||
Route::get('airports/{id}', 'AirportController@get');
|
||||
Route::get('airports/{id}/lookup', 'AirportController@lookup');
|
||||
Route::get('airports/{id}/distance/{to}', 'AirportController@distance');
|
||||
|
||||
Route::get('fleet', 'FleetController@index');
|
||||
Route::get('fleet/aircraft/{id}', 'FleetController@get_aircraft');
|
||||
|
||||
@@ -5,8 +5,15 @@ 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\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;
|
||||
use VaCentral\Airport;
|
||||
|
||||
/**
|
||||
@@ -14,14 +21,17 @@ use VaCentral\Airport;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -76,4 +86,42 @@ class AirportService extends Service
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,19 +4,23 @@ namespace App\Services;
|
||||
|
||||
use App\Contracts\Service;
|
||||
use App\Exceptions\BidExistsForFlight;
|
||||
use App\Exceptions\DuplicateFlight;
|
||||
use App\Models\Bid;
|
||||
use App\Models\Enums\Days;
|
||||
use App\Models\Flight;
|
||||
use App\Models\FlightFieldValue;
|
||||
use App\Models\User;
|
||||
use App\Repositories\FlightRepository;
|
||||
use App\Repositories\NavdataRepository;
|
||||
use Log;
|
||||
use App\Support\Units\Time;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class FlightService
|
||||
*/
|
||||
class FlightService extends Service
|
||||
{
|
||||
private $airportSvc;
|
||||
private $flightRepo;
|
||||
private $navDataRepo;
|
||||
private $userSvc;
|
||||
@@ -24,20 +28,98 @@ class FlightService extends Service
|
||||
/**
|
||||
* FlightService constructor.
|
||||
*
|
||||
* @param AirportService $airportSvc
|
||||
* @param FlightRepository $flightRepo
|
||||
* @param NavdataRepository $navdataRepo
|
||||
* @param UserService $userSvc
|
||||
*/
|
||||
public function __construct(
|
||||
AirportService $airportSvc,
|
||||
FlightRepository $flightRepo,
|
||||
NavdataRepository $navdataRepo,
|
||||
UserService $userSvc
|
||||
) {
|
||||
$this->airportSvc = $airportSvc;
|
||||
$this->flightRepo = $flightRepo;
|
||||
$this->navDataRepo = $navdataRepo;
|
||||
$this->userSvc = $userSvc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new flight
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function createFlight($fields)
|
||||
{
|
||||
$flightTmp = new Flight($fields);
|
||||
if ($this->isFlightDuplicate($flightTmp)) {
|
||||
throw new DuplicateFlight($flightTmp);
|
||||
}
|
||||
|
||||
$fields = $this->transformFlightFields($fields);
|
||||
$flight = $this->flightRepo->create($fields);
|
||||
|
||||
return $flight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a flight with values from the given fields
|
||||
*
|
||||
* @param Flight $flight
|
||||
* @param array $fields
|
||||
*
|
||||
* @throws \Prettus\Validator\Exceptions\ValidatorException
|
||||
*
|
||||
* @return \App\Models\Flight|mixed
|
||||
*/
|
||||
public function updateFlight($flight, $fields)
|
||||
{
|
||||
// apply the updates here temporarily, don't save
|
||||
// the repo->update() call will actually do it
|
||||
$flight->fill($fields);
|
||||
|
||||
if ($this->isFlightDuplicate($flight)) {
|
||||
throw new DuplicateFlight($flight);
|
||||
}
|
||||
|
||||
$fields = $this->transformFlightFields($fields);
|
||||
$flight = $this->flightRepo->update($fields, $flight->id);
|
||||
|
||||
return $flight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the fields for a flight and transform them
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function transformFlightFields($fields)
|
||||
{
|
||||
if (array_key_exists('days', $fields) && filled($fields['days'])) {
|
||||
$fields['days'] = Days::getDaysMask($fields['days']);
|
||||
}
|
||||
|
||||
$fields['flight_time'] = Time::init($fields['minutes'], $fields['hours'])->getMinutes();
|
||||
$fields['active'] = get_truth_state($fields['active']);
|
||||
|
||||
// Figure out a distance if not found
|
||||
if (empty($fields['distance'])) {
|
||||
$fields['distance'] = $this->airportSvc->calculateDistance(
|
||||
$fields['dpt_airport_id'],
|
||||
$fields['arr_airport_id']
|
||||
);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out any flights according to different settings
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user