Files
FlightsAPI/app/Models/UserFlight.php
T
2026-06-20 22:21:17 +10:00

287 lines
8.1 KiB
PHP

<?php
namespace App\Models;
use App\Http\Controllers\Api\AirlineApiController;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Storage;
class UserFlight extends Model
{
protected $table = 'user_flights';
protected $fillable = [
'user_id',
'departure_date',
'arrival_date',
'flight_number',
'departure_airport_id',
'arrival_airport_id',
'airline_id',
'aircraft_id',
'aircraft_registration',
'seat_number',
'seat_type_id',
'flight_class_id',
'flight_reason_id',
'crew_type_id',
'note',
'auto_update',
];
protected $casts = [
'departure_date' => 'immutable_datetime',
'arrival_date' => 'immutable_datetime',
'auto_update' => 'boolean',
];
protected $appends = [
'departure_date_display',
'departure_time_display',
'arrival_date_display',
'arrival_time_display',
'arrival_day_difference',
'duration',
'duration_display',
'distance',
'livery_url',
'scope',
'range',
'region_range'
];
public function calculateGreatCircleDistance(): float{
$earthRadiusKm = 6371;
[$depLat, $depLong] = [$this->departureAirport->latitude_deg, $this->departureAirport->longitude_deg];
[$arrLat, $arrLong] = [$this->arrivalAirport->latitude_deg, $this->arrivalAirport->longitude_deg];
$latDelta = deg2rad($arrLat - $depLat);
$longDelta = deg2rad($arrLong - $depLong);
$a = sin($latDelta / 2) * sin($latDelta / 2)
+ cos(deg2rad($depLat)) * cos(deg2rad($arrLat))
* sin($longDelta / 2) * sin($longDelta / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
return $earthRadiusKm * $c;
}
protected function departureDateDisplay(): Attribute
{
return Attribute::make(
get: fn() => $this->departure_date
->toMutable()
->setTimezone($this->departureAirport->timezone)
->format('j M Y')
);
}
protected function departureTimeDisplay(): Attribute
{
return Attribute::make(
get: fn() => $this->departure_date
->toMutable()
->setTimezone($this->departureAirport->timezone)
->format('g:iA')
);
}
protected function arrivalDateDisplay(): Attribute
{
return Attribute::make(
get: fn() => $this->arrival_date
?->copy()
->setTimezone($this->arrivalAirport->timezone)
->format('j M Y')
);
}
protected function arrivalTimeDisplay(): Attribute
{
return Attribute::make(
get: fn() => $this->arrival_date
?->copy()
->setTimezone($this->arrivalAirport->timezone)
->format('g:iA')
);
}
protected function scope(): Attribute
{
return Attribute::make(
get: fn() => $this->departureAirport->region->country_id == $this->arrivalAirport->region->country_id ? 'domestic' : 'international'
);
}
protected function range(): Attribute
{
return Attribute::make(
get: fn() => $this->departureAirport->region->continent_id == $this->arrivalAirport->region->continent_id ? 'intracontinental' : 'intercontinental'
);
}
protected function regionRange(): Attribute
{
return Attribute::make(
get: fn() => $this->departureAirport->region_id == $this->arrivalAirport->region_id ? 'intraregional' : 'interregional'
);
}
protected function arrivalDayDifference(): Attribute
{
return Attribute::make(
get: function () {
if (!$this->arrival_date) return 0;
$departureLocal = $this->departure_date->copy()->setTimezone($this->departureAirport->timezone);
$arrivalLocal = $this->arrival_date->copy()->setTimezone($this->arrivalAirport->timezone);
return (int) abs(
Carbon::parse($arrivalLocal->toDateString())
->diffInDays(Carbon::parse($departureLocal->toDateString()))
);
}
);
}
protected function duration(): Attribute
{
return Attribute::make(
get: fn() => $this->departure_date->diffInMinutes($this->arrival_date)
);
}
protected function durationDisplay(): Attribute
{
return Attribute::make(
get: function () {
$hours = intdiv($this->duration, 60);
$minutes = $this->duration % 60;
return $hours . 'h ' . str_pad($minutes, 2, '0', STR_PAD_LEFT) . 'm';
}
);
}
protected function distance(): Attribute
{
return Attribute::make(
get: fn() => round($this->calculateGreatCircleDistance())
);
}
public function isDomestic() : bool{
return $this->departureAirport->region->country_id == $this->arrivalAirport->region->country_id;
}
public function isInternational() : bool{
return !$this->isDomestic();
}
public static function snapshot($userFlightId): array
{
return UserFlight::with([
'departureAirport',
'departureAirport.region.country',
'arrivalAirport',
'arrivalAirport.region.country',
'aircraft',
'airline',
'airline.country',
'airline.alliance',
'flightClass',
'seatType',
'flightReason',
'crewType',
])->find($userFlightId)->toArray();
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function departureAirport(): BelongsTo
{
return $this->belongsTo(Airport::class, 'departure_airport_id');
}
public function arrivalAirport(): BelongsTo
{
return $this->belongsTo(Airport::class, 'arrival_airport_id');
}
public function crewType(): BelongsTo
{
return $this->belongsTo(CrewType::class);
}
public function airline(): BelongsTo
{
return $this->belongsTo(Airline::class);
}
public function aircraft(): BelongsTo
{
return $this->belongsTo(Aircraft::class);
}
public function seatType(): BelongsTo
{
return $this->belongsTo(SeatType::class);
}
public function flightClass(): BelongsTo
{
return $this->belongsTo(FlightClass::class);
}
public function flightReason(): BelongsTo
{
return $this->belongsTo(FlightReason::class);
}
public function liveryUrl(): Attribute{
return Attribute::make(
get: function () {
$user = auth()?->user();
$useAi = !$user || $user->getSetting('ai_liveries');
$apiUrl = config('app.logo_api_url');
if (!$this->aircraft) {
return null;
}
if ($this->airline && $useAi){
$path = "images/liveries/{$this->airline->internal_name}_{$this->aircraft->designator}.png";
if (Storage::disk('local')->exists($path)) {
$finalPath = $apiUrl."/airline/{$this->airline->internal_name}/livery/{$this->aircraft->designator}";
}
}
if(empty($finalPath)){
$path = "images/livery_templates/{$this->aircraft->designator}.png";
if (Storage::disk('local')->exists($path)) {
$finalPath = $apiUrl."/aircraft/{$this->aircraft->designator}/livery";
}
}
if(empty($finalPath)){
return null;
}
return $finalPath;
}
);
}
}