109 lines
3.4 KiB
PHP
109 lines
3.4 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Modules\RestaurantDelivery\DTOs;
|
||
|
|
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
|
||
|
|
readonly class RiderLocationDTO
|
||
|
|
{
|
||
|
|
public function __construct(
|
||
|
|
public float $latitude,
|
||
|
|
public float $longitude,
|
||
|
|
public ?float $speed = null,
|
||
|
|
public ?float $bearing = null,
|
||
|
|
public ?float $accuracy = null,
|
||
|
|
public ?float $altitude = null,
|
||
|
|
public ?\DateTimeInterface $timestamp = null,
|
||
|
|
) {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create DTO from request.
|
||
|
|
*/
|
||
|
|
public static function fromRequest(Request $request): self
|
||
|
|
{
|
||
|
|
return new self(
|
||
|
|
latitude: (float) $request->input('latitude'),
|
||
|
|
longitude: (float) $request->input('longitude'),
|
||
|
|
speed: $request->filled('speed') ? (float) $request->input('speed') : null,
|
||
|
|
bearing: $request->filled('bearing') ? (float) $request->input('bearing') : null,
|
||
|
|
accuracy: $request->filled('accuracy') ? (float) $request->input('accuracy') : null,
|
||
|
|
altitude: $request->filled('altitude') ? (float) $request->input('altitude') : null,
|
||
|
|
timestamp: $request->filled('timestamp') ? new \DateTime($request->input('timestamp')) : null,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create DTO from array.
|
||
|
|
*/
|
||
|
|
public static function fromArray(array $data): self
|
||
|
|
{
|
||
|
|
return new self(
|
||
|
|
latitude: (float) ($data['latitude'] ?? $data['lat'] ?? 0),
|
||
|
|
longitude: (float) ($data['longitude'] ?? $data['lng'] ?? 0),
|
||
|
|
speed: isset($data['speed']) ? (float) $data['speed'] : null,
|
||
|
|
bearing: isset($data['bearing']) ? (float) $data['bearing'] : null,
|
||
|
|
accuracy: isset($data['accuracy']) ? (float) $data['accuracy'] : null,
|
||
|
|
altitude: isset($data['altitude']) ? (float) $data['altitude'] : null,
|
||
|
|
timestamp: isset($data['timestamp']) ? new \DateTime($data['timestamp']) : null,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convert to array.
|
||
|
|
*/
|
||
|
|
public function toArray(): array
|
||
|
|
{
|
||
|
|
return array_filter([
|
||
|
|
'latitude' => $this->latitude,
|
||
|
|
'longitude' => $this->longitude,
|
||
|
|
'speed' => $this->speed,
|
||
|
|
'bearing' => $this->bearing,
|
||
|
|
'accuracy' => $this->accuracy,
|
||
|
|
'altitude' => $this->altitude,
|
||
|
|
'timestamp' => $this->timestamp?->format('Y-m-d H:i:s'),
|
||
|
|
], fn ($value) => $value !== null);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convert to Firebase format.
|
||
|
|
*/
|
||
|
|
public function toFirebaseFormat(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'lat' => $this->latitude,
|
||
|
|
'lng' => $this->longitude,
|
||
|
|
'speed' => $this->speed,
|
||
|
|
'bearing' => $this->bearing,
|
||
|
|
'accuracy' => $this->accuracy,
|
||
|
|
'timestamp' => ($this->timestamp ?? now())->getTimestamp() * 1000, // JavaScript timestamp
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if location is valid.
|
||
|
|
*/
|
||
|
|
public function isValid(): bool
|
||
|
|
{
|
||
|
|
return $this->latitude >= -90
|
||
|
|
&& $this->latitude <= 90
|
||
|
|
&& $this->longitude >= -180
|
||
|
|
&& $this->longitude <= 180;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if accuracy is acceptable.
|
||
|
|
*/
|
||
|
|
public function hasAcceptableAccuracy(?float $threshold = null): bool
|
||
|
|
{
|
||
|
|
if ($this->accuracy === null) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
$threshold = $threshold ?? config('restaurant-delivery.firebase.location.accuracy_threshold', 50);
|
||
|
|
|
||
|
|
return $this->accuracy <= $threshold;
|
||
|
|
}
|
||
|
|
}
|