@fleetbase/fleetops-engine 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +14 -0
- package/.php-cs-fixer.cache +1 -0
- package/.php-cs-fixer.php +29 -0
- package/LICENSE.md +16 -4
- package/README.md +103 -13
- package/composer.json +85 -0
- package/extension.json +10 -0
- package/package.json +3 -3
- package/phpstan.neon.dist +8 -0
- package/phpunit.xml.dist +16 -0
- package/server/config/api.php +765 -0
- package/server/config/cache.stores.php +18 -0
- package/server/config/dompdf.php +242 -0
- package/server/config/fleetops.php +19 -0
- package/server/config/geocoder.php +108 -0
- package/server/data/globe.json +261 -0
- package/server/migrations/2023_04_27_053456_create_contacts_table.php +49 -0
- package/server/migrations/2023_04_27_053456_create_drivers_table.php +62 -0
- package/server/migrations/2023_04_27_053456_create_entities_table.php +67 -0
- package/server/migrations/2023_04_27_053456_create_fleet_drivers_table.php +39 -0
- package/server/migrations/2023_04_27_053456_create_fleets_table.php +47 -0
- package/server/migrations/2023_04_27_053456_create_fuel_reports_table.php +50 -0
- package/server/migrations/2023_04_27_053456_create_integrated_vendors_table.php +44 -0
- package/server/migrations/2023_04_27_053456_create_issues_table.php +53 -0
- package/server/migrations/2023_04_27_053456_create_orders_table.php +70 -0
- package/server/migrations/2023_04_27_053456_create_payloads_table.php +51 -0
- package/server/migrations/2023_04_27_053456_create_places_table.php +62 -0
- package/server/migrations/2023_04_27_053456_create_positions_table.php +46 -0
- package/server/migrations/2023_04_27_053456_create_proofs_table.php +44 -0
- package/server/migrations/2023_04_27_053456_create_purchase_rates_table.php +46 -0
- package/server/migrations/2023_04_27_053456_create_routes_table.php +40 -0
- package/server/migrations/2023_04_27_053456_create_service_areas_table.php +47 -0
- package/server/migrations/2023_04_27_053456_create_service_quote_items_table.php +42 -0
- package/server/migrations/2023_04_27_053456_create_service_quotes_table.php +47 -0
- package/server/migrations/2023_04_27_053456_create_service_rate_fees_table.php +45 -0
- package/server/migrations/2023_04_27_053456_create_service_rate_parcel_fees_table.php +47 -0
- package/server/migrations/2023_04_27_053456_create_service_rates_table.php +61 -0
- package/server/migrations/2023_04_27_053456_create_tracking_numbers_table.php +46 -0
- package/server/migrations/2023_04_27_053456_create_tracking_statuses_table.php +54 -0
- package/server/migrations/2023_04_27_053456_create_vehicles_table.php +84 -0
- package/server/migrations/2023_04_27_053456_create_vendors_table.php +56 -0
- package/server/migrations/2023_04_27_053456_create_waypoints_table.php +45 -0
- package/server/migrations/2023_04_27_053456_create_zones_table.php +46 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_companies_table.php +32 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_contacts_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_drivers_table.php +40 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_entities_table.php +40 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleet_drivers_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fleets_table.php +36 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_fuel_reports_table.php +36 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_integrated_vendors_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_issues_table.php +38 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_orders_table.php +48 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_payloads_table.php +40 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_places_table.php +32 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_positions_table.php +36 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_proofs_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_purchase_rates_table.php +38 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_routes_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_areas_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quote_items_table.php +32 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_quotes_table.php +38 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_fees_table.php +32 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rate_parcel_fees_table.php +32 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_service_rates_table.php +36 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_numbers_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_tracking_statuses_table.php +34 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vehicles_table.php +36 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_vendors_table.php +40 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_waypoints_table.php +38 -0
- package/server/migrations/2023_04_27_053459_add_foreign_keys_to_zones_table.php +34 -0
- package/server/migrations/2023_09_14_074512_update_vehicles_table.php +100 -0
- package/server/migrations/2023_09_14_074619_create_vehicle_devices_table.php +44 -0
- package/server/migrations/2023_09_26_071205_add_online_column_to_vehicles_table.php +32 -0
- package/server/migrations/2023_09_26_083957_create_fleet_vehicles_table.php +45 -0
- package/server/migrations/2023_09_27_023757_add_column_to_fleets_table.php +46 -0
- package/server/migrations/2023_10_05_074811_update_vehicle.php +42 -0
- package/server/resources/views/labels/default.php +165 -0
- package/server/src/Auth/Schemas/FleetOps.php +75 -0
- package/server/src/Casts/MultiPolygon.php +50 -0
- package/server/src/Casts/Point.php +109 -0
- package/server/src/Casts/Polygon.php +46 -0
- package/server/src/Console/Commands/DispatchAdhocOrders.php +137 -0
- package/server/src/Console/Commands/DispatchOrders.php +71 -0
- package/server/src/Console/Commands/TrackOrderDistanceAndTime.php +62 -0
- package/server/src/Events/DriverLocationChanged.php +174 -0
- package/server/src/Events/DriverSimulatedLocationChanged.php +183 -0
- package/server/src/Events/EntityDriverAssigned.php +36 -0
- package/server/src/Events/OrderCanceled.php +15 -0
- package/server/src/Events/OrderCompleted.php +15 -0
- package/server/src/Events/OrderDispatchFailed.php +42 -0
- package/server/src/Events/OrderDispatched.php +15 -0
- package/server/src/Events/OrderDriverAssigned.php +15 -0
- package/server/src/Events/OrderReady.php +15 -0
- package/server/src/Events/OrderStarted.php +15 -0
- package/server/src/Exceptions/IntegratedVendorException.php +18 -0
- package/server/src/Expansions/UserExpansion.php +63 -0
- package/server/src/Exports/ContactExport.php +56 -0
- package/server/src/Exports/DriverExport.php +61 -0
- package/server/src/Exports/FleetExport.php +53 -0
- package/server/src/Exports/PlaceExport.php +55 -0
- package/server/src/Exports/ServiceAreaExport.php +58 -0
- package/server/src/Exports/VehicleExport.php +57 -0
- package/server/src/Exports/VendorExport.php +57 -0
- package/server/src/Http/Controllers/Api/v1/ContactController.php +133 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +691 -0
- package/server/src/Http/Controllers/Api/v1/EntityController.php +230 -0
- package/server/src/Http/Controllers/Api/v1/FleetController.php +146 -0
- package/server/src/Http/Controllers/Api/v1/LabelController.php +63 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +1114 -0
- package/server/src/Http/Controllers/Api/v1/PayloadController.php +195 -0
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +333 -0
- package/server/src/Http/Controllers/Api/v1/PurchaseRateController.php +199 -0
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +133 -0
- package/server/src/Http/Controllers/Api/v1/ServiceQuoteController.php +381 -0
- package/server/src/Http/Controllers/Api/v1/ServiceRateController.php +223 -0
- package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +146 -0
- package/server/src/Http/Controllers/Api/v1/TrackingStatusController.php +138 -0
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +191 -0
- package/server/src/Http/Controllers/Api/v1/VendorController.php +159 -0
- package/server/src/Http/Controllers/Api/v1/ZoneController.php +146 -0
- package/server/src/Http/Controllers/FleetOpsController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +69 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +261 -0
- package/server/src/Http/Controllers/Internal/v1/EntityController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/FleetController.php +152 -0
- package/server/src/Http/Controllers/Internal/v1/FleetOpsLookupController.php +80 -0
- package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/GeocoderController.php +96 -0
- package/server/src/Http/Controllers/Internal/v1/IntegratedVendorController.php +63 -0
- package/server/src/Http/Controllers/Internal/v1/IssueController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +127 -0
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +75 -0
- package/server/src/Http/Controllers/Internal/v1/MorphController.php +77 -0
- package/server/src/Http/Controllers/Internal/v1/OrderConfigController.php +269 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +564 -0
- package/server/src/Http/Controllers/Internal/v1/PayloadController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/PlaceController.php +163 -0
- package/server/src/Http/Controllers/Internal/v1/ProofController.php +139 -0
- package/server/src/Http/Controllers/Internal/v1/PurchaseRateController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/RouteController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +32 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +345 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceRateController.php +47 -0
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +30 -0
- package/server/src/Http/Controllers/Internal/v1/TrackingNumberController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/TrackingStatusController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +65 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleDeviceController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +120 -0
- package/server/src/Http/Controllers/Internal/v1/ZoneController.php +15 -0
- package/server/src/Http/Filter/ContactFilter.php +86 -0
- package/server/src/Http/Filter/DriverFilter.php +148 -0
- package/server/src/Http/Filter/FleetFilter.php +108 -0
- package/server/src/Http/Filter/IntegratedVendorFilter.php +13 -0
- package/server/src/Http/Filter/OrderFilter.php +242 -0
- package/server/src/Http/Filter/PlaceFilter.php +111 -0
- package/server/src/Http/Filter/ServiceAreaFilter.php +13 -0
- package/server/src/Http/Filter/ServiceQuoteFilter.php +13 -0
- package/server/src/Http/Filter/ServiceRateFilter.php +33 -0
- package/server/src/Http/Filter/TrackingStatusFilter.php +43 -0
- package/server/src/Http/Filter/VehicleFilter.php +91 -0
- package/server/src/Http/Filter/VendorFilter.php +83 -0
- package/server/src/Http/Filter/ZoneFilter.php +13 -0
- package/server/src/Http/Requests/CancelOrderRequest.php +31 -0
- package/server/src/Http/Requests/CreateContactRequest.php +33 -0
- package/server/src/Http/Requests/CreateDriverRequest.php +55 -0
- package/server/src/Http/Requests/CreateEntityRequest.php +43 -0
- package/server/src/Http/Requests/CreateFleetRequest.php +32 -0
- package/server/src/Http/Requests/CreateOrderRequest.php +66 -0
- package/server/src/Http/Requests/CreatePayloadRequest.php +37 -0
- package/server/src/Http/Requests/CreatePlaceRequest.php +38 -0
- package/server/src/Http/Requests/CreatePurchaseRateRequest.php +33 -0
- package/server/src/Http/Requests/CreateServiceAreaRequest.php +35 -0
- package/server/src/Http/Requests/CreateServiceQuoteRequest.php +29 -0
- package/server/src/Http/Requests/CreateServiceRateRequest.php +56 -0
- package/server/src/Http/Requests/CreateTrackingNumberRequest.php +34 -0
- package/server/src/Http/Requests/CreateTrackingStatusRequest.php +42 -0
- package/server/src/Http/Requests/CreateVehicleRequest.php +32 -0
- package/server/src/Http/Requests/CreateVendorRequest.php +35 -0
- package/server/src/Http/Requests/CreateZoneRequest.php +35 -0
- package/server/src/Http/Requests/DecodeTrackingNumberQR.php +30 -0
- package/server/src/Http/Requests/DriverSimulationRequest.php +46 -0
- package/server/src/Http/Requests/Internal/AssignOrderRequest.php +31 -0
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +42 -0
- package/server/src/Http/Requests/Internal/FleetActionRequest.php +32 -0
- package/server/src/Http/Requests/Internal/UpdateDriverRequest.php +7 -0
- package/server/src/Http/Requests/QueryServiceQuotesRequest.php +41 -0
- package/server/src/Http/Requests/UpdateContactRequest.php +20 -0
- package/server/src/Http/Requests/UpdateDriverRequest.php +7 -0
- package/server/src/Http/Requests/UpdateEntityRequest.php +7 -0
- package/server/src/Http/Requests/UpdateFleetRequest.php +7 -0
- package/server/src/Http/Requests/UpdateOrderRequest.php +7 -0
- package/server/src/Http/Requests/UpdatePayloadRequest.php +7 -0
- package/server/src/Http/Requests/UpdatePlaceRequest.php +7 -0
- package/server/src/Http/Requests/UpdatePurchaseRateRequest.php +7 -0
- package/server/src/Http/Requests/UpdateServiceAreaRequest.php +29 -0
- package/server/src/Http/Requests/UpdateServiceQuoteRequest.php +29 -0
- package/server/src/Http/Requests/UpdateServiceRateRequest.php +29 -0
- package/server/src/Http/Requests/UpdateTrackingNumberRequest.php +7 -0
- package/server/src/Http/Requests/UpdateTrackingStatusRequest.php +32 -0
- package/server/src/Http/Requests/UpdateVehicleRequest.php +7 -0
- package/server/src/Http/Requests/UpdateVendorRequest.php +7 -0
- package/server/src/Http/Requests/UpdateZoneRequest.php +7 -0
- package/server/src/Http/Resources/Internal/v1/IntegratedVendorFacilitator.php +37 -0
- package/server/src/Http/Resources/Internal/v1/Vehicle.php +33 -0
- package/server/src/Http/Resources/Internal/v1/Waypoint.php +34 -0
- package/server/src/Http/Resources/v1/Contact.php +62 -0
- package/server/src/Http/Resources/v1/CurrentJob.php +36 -0
- package/server/src/Http/Resources/v1/DeletedResource.php +61 -0
- package/server/src/Http/Resources/v1/Driver.php +89 -0
- package/server/src/Http/Resources/v1/Entity.php +107 -0
- package/server/src/Http/Resources/v1/Fleet.php +60 -0
- package/server/src/Http/Resources/v1/FuelReport.php +67 -0
- package/server/src/Http/Resources/v1/Order.php +131 -0
- package/server/src/Http/Resources/v1/Payload.php +94 -0
- package/server/src/Http/Resources/v1/Place.php +84 -0
- package/server/src/Http/Resources/v1/Proof.php +36 -0
- package/server/src/Http/Resources/v1/PurchaseRate.php +77 -0
- package/server/src/Http/Resources/v1/ServiceArea.php +55 -0
- package/server/src/Http/Resources/v1/ServiceQuote.php +57 -0
- package/server/src/Http/Resources/v1/ServiceRate.php +94 -0
- package/server/src/Http/Resources/v1/ServiceRateFee.php +58 -0
- package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +48 -0
- package/server/src/Http/Resources/v1/TrackingNumber.php +62 -0
- package/server/src/Http/Resources/v1/TrackingStatus.php +84 -0
- package/server/src/Http/Resources/v1/Vehicle.php +75 -0
- package/server/src/Http/Resources/v1/VehicleDevice.php +44 -0
- package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +72 -0
- package/server/src/Http/Resources/v1/Vendor.php +72 -0
- package/server/src/Http/Resources/v1/Zone.php +60 -0
- package/server/src/Imports/OrdersImport.php +18 -0
- package/server/src/Integrations/Lalamove/Lalamove.php +678 -0
- package/server/src/Integrations/Lalamove/LalamoveDeliveryStop.php +97 -0
- package/server/src/Integrations/Lalamove/LalamoveMarket.php +123 -0
- package/server/src/Integrations/Lalamove/LalamoveServiceType.php +161 -0
- package/server/src/Jobs/SimulateDrivingRoute.php +81 -0
- package/server/src/Jobs/SimulateWaypointReached.php +79 -0
- package/server/src/Listeners/HandleOrderCanceled.php +46 -0
- package/server/src/Listeners/HandleOrderCreated.php +23 -0
- package/server/src/Listeners/HandleOrderDispatchFailed.php +35 -0
- package/server/src/Listeners/HandleOrderDispatched.php +108 -0
- package/server/src/Listeners/HandleOrderDriverAssigned.php +42 -0
- package/server/src/Listeners/HandleOrderReady.php +27 -0
- package/server/src/Listeners/HandleUserRemovedFromCompany.php +31 -0
- package/server/src/Models/Contact.php +239 -0
- package/server/src/Models/Driver.php +543 -0
- package/server/src/Models/Entity.php +416 -0
- package/server/src/Models/Fleet.php +203 -0
- package/server/src/Models/FleetDriver.php +73 -0
- package/server/src/Models/FleetVehicle.php +73 -0
- package/server/src/Models/FuelReport.php +125 -0
- package/server/src/Models/IntegratedVendor.php +219 -0
- package/server/src/Models/Issue.php +111 -0
- package/server/src/Models/Order.php +1132 -0
- package/server/src/Models/Payload.php +699 -0
- package/server/src/Models/Place.php +656 -0
- package/server/src/Models/Position.php +119 -0
- package/server/src/Models/Proof.php +94 -0
- package/server/src/Models/PurchaseRate.php +208 -0
- package/server/src/Models/Route.php +128 -0
- package/server/src/Models/ServiceArea.php +161 -0
- package/server/src/Models/ServiceQuote.php +207 -0
- package/server/src/Models/ServiceQuoteItem.php +46 -0
- package/server/src/Models/ServiceRate.php +953 -0
- package/server/src/Models/ServiceRateFee.php +96 -0
- package/server/src/Models/ServiceRateParcelFee.php +116 -0
- package/server/src/Models/TrackingNumber.php +310 -0
- package/server/src/Models/TrackingStatus.php +177 -0
- package/server/src/Models/Vehicle.php +452 -0
- package/server/src/Models/VehicleDevice.php +79 -0
- package/server/src/Models/Vendor.php +244 -0
- package/server/src/Models/Waypoint.php +226 -0
- package/server/src/Models/Zone.php +95 -0
- package/server/src/Notifications/OrderAssigned.php +140 -0
- package/server/src/Notifications/OrderCanceled.php +129 -0
- package/server/src/Notifications/OrderDispatchFailed.php +81 -0
- package/server/src/Notifications/OrderDispatched.php +173 -0
- package/server/src/Notifications/OrderPing.php +162 -0
- package/server/src/Notifications/OrderSplit.php +56 -0
- package/server/src/Observers/DriverObserver.php +34 -0
- package/server/src/Observers/OrderObserver.php +34 -0
- package/server/src/Observers/PayloadObserver.php +30 -0
- package/server/src/Observers/PlaceObserver.php +26 -0
- package/server/src/Observers/PurchaseRateObserver.php +61 -0
- package/server/src/Observers/ServiceAreaObserver.php +35 -0
- package/server/src/Observers/ServiceRateObserver.php +78 -0
- package/server/src/Observers/TrackingNumberObserver.php +44 -0
- package/server/src/Observers/UserObserver.php +20 -0
- package/server/src/Observers/VehicleObserver.php +66 -0
- package/server/src/Providers/EventServiceProvider.php +30 -0
- package/server/src/Providers/FleetOpsServiceProvider.php +94 -0
- package/server/src/Rules/ResolvablePoint.php +37 -0
- package/server/src/Scopes/DriverScope.php +21 -0
- package/server/src/Support/Algo.php +55 -0
- package/server/src/Support/DistanceMatrix.php +27 -0
- package/server/src/Support/Encoding/Polyline.php +168 -0
- package/server/src/Support/Flow.php +622 -0
- package/server/src/Support/Geocoding.php +216 -0
- package/server/src/Support/IntegratedVendors.php +287 -0
- package/server/src/Support/Metrics.php +305 -0
- package/server/src/Support/OSRM.php +191 -0
- package/server/src/Support/ParsePhone.php +21 -0
- package/server/src/Support/Utils.php +1145 -0
- package/server/src/Traits/HasTrackingNumber.php +185 -0
- package/server/src/routes.php +381 -0
- package/server/tests/Feature.php +5 -0
|
@@ -0,0 +1,1145 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\FleetOps\Support;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Support\Utils as FleetbaseUtils;
|
|
6
|
+
use Illuminate\Support\Arr;
|
|
7
|
+
use Illuminate\Support\Facades\DB;
|
|
8
|
+
use Illuminate\Support\Facades\Http;
|
|
9
|
+
use Illuminate\Support\Facades\Redis;
|
|
10
|
+
use Illuminate\Support\Str;
|
|
11
|
+
|
|
12
|
+
class Utils extends FleetbaseUtils
|
|
13
|
+
{
|
|
14
|
+
/**
|
|
15
|
+
* A constant multiplier used to calculate driving time from distance.
|
|
16
|
+
*
|
|
17
|
+
* @var float
|
|
18
|
+
*/
|
|
19
|
+
public const DRIVING_TIME_MULTIPLIER = 7.2;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get a formatted string representation of a place's address.
|
|
23
|
+
*
|
|
24
|
+
* @param \Fleetbase\FleetOps\Models\Place $place the place object to retrieve the address from
|
|
25
|
+
* @param bool $useHtml whether to format the address as HTML (default is false)
|
|
26
|
+
* @param array|string $except an array of keys to exclude from the address (default is an empty array)
|
|
27
|
+
*
|
|
28
|
+
* @return string the formatted address string
|
|
29
|
+
*/
|
|
30
|
+
public static function getAddressStringForPlace(\Fleetbase\FleetOps\Models\Place $place, $useHtml = false, $except = [])
|
|
31
|
+
{
|
|
32
|
+
$address = $useHtml ? '<address>' : '';
|
|
33
|
+
$parts = collect([
|
|
34
|
+
'name',
|
|
35
|
+
'street1',
|
|
36
|
+
'street2',
|
|
37
|
+
'city',
|
|
38
|
+
'province',
|
|
39
|
+
'postal_code',
|
|
40
|
+
'country_name',
|
|
41
|
+
])->filter(function ($part) use ($except) {
|
|
42
|
+
return is_array($except) ? !in_array($part, $except) : true;
|
|
43
|
+
})->values();
|
|
44
|
+
$numberOfParts = $parts->count();
|
|
45
|
+
$addressValues = [];
|
|
46
|
+
$seperator = $useHtml ? '<br>' : ' - ';
|
|
47
|
+
|
|
48
|
+
for ($i = 0; $i < $numberOfParts; $i++) {
|
|
49
|
+
$key = $parts[$i];
|
|
50
|
+
$value = data_get($place, $key);
|
|
51
|
+
|
|
52
|
+
if (is_string($value)) {
|
|
53
|
+
$value = strtoupper($value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// if value empty skip or value equal to last value skip
|
|
57
|
+
if (empty($value) || in_array($value, $addressValues) || (Str::contains(data_get($place, 'street1'), $value) && $key !== 'street1')) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
$addressValues[$key] = $value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
foreach ($addressValues as $key => $value) {
|
|
65
|
+
if ($key === array_key_last($addressValues)) {
|
|
66
|
+
$seperator = '';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if ($useHtml && in_array($key, ['street1', 'street2', 'postal_code'])) {
|
|
70
|
+
$seperator = '<br>';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
$address .= strtoupper($value) . $seperator;
|
|
74
|
+
$seperator = ', ';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if ($useHtml) {
|
|
78
|
+
$address .= '</address>';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return $address;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Unpack a binary string representing a geographic point into an array of values.
|
|
86
|
+
*
|
|
87
|
+
* @return array an array of values representing the geographic point, with keys for 'order', 'type', 'lat', and 'lon'
|
|
88
|
+
*/
|
|
89
|
+
public static function unpackPoint(string $bindaryString): array
|
|
90
|
+
{
|
|
91
|
+
return unpack('x/x/x/x/corder/Ltype/dlat/dlon', $bindaryString);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Unpacks a mysql POINT column from binary to array.
|
|
96
|
+
*/
|
|
97
|
+
public static function mysqlPointAsGeometry(string $rawPoint): \Grimzy\LaravelMysqlSpatial\Types\Point
|
|
98
|
+
{
|
|
99
|
+
$coordinates = static::unpackPoint($rawPoint);
|
|
100
|
+
|
|
101
|
+
return new \Grimzy\LaravelMysqlSpatial\Types\Point($coordinates['lon'], $coordinates['lat']);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Determines if a given number is a valid latitude value in the range of -90 to 90 degrees.
|
|
106
|
+
*
|
|
107
|
+
* @param mixed $num the number to check for latitude validity
|
|
108
|
+
*
|
|
109
|
+
* @return bool true if the number is a valid latitude value, false otherwise
|
|
110
|
+
*/
|
|
111
|
+
public static function isLatitude($num): bool
|
|
112
|
+
{
|
|
113
|
+
if (!is_numeric($num) || $num === null) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// cast to float
|
|
118
|
+
$num = (float) $num;
|
|
119
|
+
|
|
120
|
+
return is_finite($num) && $num >= -90 && $num <= 90;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Determines if a given number is a valid longitude value in the range of -180 to 180 degrees.
|
|
125
|
+
*
|
|
126
|
+
* @param mixed $num the number to check for longitude validity
|
|
127
|
+
*
|
|
128
|
+
* @return bool true if the number is a valid longitude value, false otherwise
|
|
129
|
+
*/
|
|
130
|
+
public static function isLongitude($num): bool
|
|
131
|
+
{
|
|
132
|
+
if (!is_numeric($num) || is_null($num)) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// cast to float
|
|
137
|
+
$num = (float) $num;
|
|
138
|
+
|
|
139
|
+
return is_finite($num) && $num >= -180 && $num <= 180;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Cleans a string containing a coordinate value by removing all non-numeric and non-period characters.
|
|
144
|
+
*
|
|
145
|
+
* @param string $string the string to clean
|
|
146
|
+
*
|
|
147
|
+
* @return string the cleaned string containing only numeric and period characters
|
|
148
|
+
*/
|
|
149
|
+
public static function cleanCoordinateString($string)
|
|
150
|
+
{
|
|
151
|
+
return str_replace([' ', ',', ';', ':', '-', '+', '/', '\\', '(', ')', '[', ']', '{', '}', '_', '|', '@', '#', '$', '%', '^', '&', '*', '=', '?', '!', '<', '>', '~', '`', '"', "'", '“', '”'], '', $string);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Determines whether the given input represents valid coordinates.
|
|
156
|
+
*
|
|
157
|
+
* @param mixed $coordinates the input to check for coordinates validity
|
|
158
|
+
*
|
|
159
|
+
* @return bool true if the input represents valid coordinates, false otherwise
|
|
160
|
+
*/
|
|
161
|
+
public static function isCoordinates($coordinates): bool
|
|
162
|
+
{
|
|
163
|
+
try {
|
|
164
|
+
return static::getPointFromMixed($coordinates) instanceof \Grimzy\LaravelMysqlSpatial\Types\Point;
|
|
165
|
+
} catch (\Throwable $e) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Gets a Point object from coordinates.
|
|
174
|
+
*
|
|
175
|
+
* @param mixed $coordinates the coordinates input value to extract a coordinate from
|
|
176
|
+
*
|
|
177
|
+
* @return \Grimzy\LaravelMysqlSpatial\Types\Point the extracted Point object
|
|
178
|
+
*/
|
|
179
|
+
public static function getPointFromMixed($coordinates): ?\Grimzy\LaravelMysqlSpatial\Types\Point
|
|
180
|
+
{
|
|
181
|
+
$latitude = null;
|
|
182
|
+
$longitude = null;
|
|
183
|
+
|
|
184
|
+
if ($coordinates instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
185
|
+
$coordinates = $coordinates->location;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if ($coordinates instanceof \Fleetbase\FleetOps\Models\Driver) {
|
|
189
|
+
$coordinates = $coordinates->location;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// any model with spatial location point
|
|
193
|
+
if ($coordinates instanceof \Illuminate\Database\Eloquent\Model && $coordinates->isFillable('location')) {
|
|
194
|
+
$coordinates = $coordinates->location;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression) {
|
|
198
|
+
$coordinates = $coordinates->getSpatialValue();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
202
|
+
$latitude = $coordinates->getLat();
|
|
203
|
+
$longitude = $coordinates->getLng();
|
|
204
|
+
} elseif (static::isGeoJson($coordinates)) {
|
|
205
|
+
$coordinatesJson = null;
|
|
206
|
+
|
|
207
|
+
if (is_array($coordinates) || is_object($coordinates)) {
|
|
208
|
+
$coordinatesJson = json_encode($coordinates);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (static::isJson($coordinatesJson)) {
|
|
212
|
+
$coordinates = \Grimzy\LaravelMysqlSpatial\Types\Point::fromJson($coordinatesJson);
|
|
213
|
+
}
|
|
214
|
+
} elseif (is_array($coordinates) || is_object($coordinates)) {
|
|
215
|
+
// if known location based record
|
|
216
|
+
if (static::exists($coordinates, 'public_id')) {
|
|
217
|
+
if (Str::startsWith(data_get($coordinates, 'public_id'), ['place', 'driver'])) {
|
|
218
|
+
return static::getPointFromMixed(data_get($coordinates, 'public_id'));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// if is a object/array model with location property
|
|
223
|
+
if (static::exists($coordinates, 'location')) {
|
|
224
|
+
return static::getPointFromMixed(data_get($coordinates, 'location'));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
$latitude = static::or($coordinates, ['_lat', 'lat', '_latitude', 'latitude', 'x', '0']);
|
|
228
|
+
$longitude = static::or($coordinates, ['lon', '_lon', 'long', 'lng', '_lng', '_longitude', 'longitude', 'y', '1']);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (is_string($coordinates)) {
|
|
232
|
+
$coords = [];
|
|
233
|
+
|
|
234
|
+
if (Str::startsWith($coordinates, 'place_')) {
|
|
235
|
+
$resolvedPlace = \Fleetbase\FleetOps\Models\Place::where('public_id', $coordinates)->first();
|
|
236
|
+
if ($resolvedPlace instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
237
|
+
return static::getPointFromMixed($resolvedPlace);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (Str::startsWith($coordinates, 'driver_')) {
|
|
244
|
+
$resolvedDriver = \Fleetbase\FleetOps\Models\Driver::where('public_id', $coordinates)->first();
|
|
245
|
+
if ($resolvedDriver instanceof \Fleetbase\FleetOps\Models\Driver) {
|
|
246
|
+
return static::getPointFromMixed($resolvedDriver);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (Str::isUuid($coordinates)) {
|
|
253
|
+
$resolvedPlace = \Fleetbase\FleetOps\Models\Place::where('uuid', $coordinates)->first();
|
|
254
|
+
if ($resolvedPlace instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
255
|
+
return static::getPointFromMixed($resolvedPlace);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
$resolvedDriver = \Fleetbase\FleetOps\Models\Driver::where('uuid', $coordinates)->first();
|
|
259
|
+
if ($resolvedDriver instanceof \Fleetbase\FleetOps\Models\Driver) {
|
|
260
|
+
return static::getPointFromMixed($resolvedDriver);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (Str::startsWith($coordinates, 'POINT(')) {
|
|
267
|
+
$coordinates = Str::replaceFirst('POINT(', '', $coordinates);
|
|
268
|
+
$coordinates = Str::replace(')', '', $coordinates);
|
|
269
|
+
$coords = explode(' ', $coordinates);
|
|
270
|
+
$coords = array_reverse($coords);
|
|
271
|
+
$coordinates = null;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (preg_match('/LatLng\(([^,]+),\s*([^)]+)\)/', $coordinates, $matches)) {
|
|
275
|
+
$coords = [
|
|
276
|
+
floatval($matches[1]),
|
|
277
|
+
floatval($matches[2]),
|
|
278
|
+
];
|
|
279
|
+
|
|
280
|
+
$coordinates = null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (Str::contains($coordinates, ',')) {
|
|
284
|
+
$coords = explode(',', $coordinates);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (Str::contains($coordinates, '|')) {
|
|
288
|
+
$coords = explode('|', $coordinates);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (Str::contains($coordinates, ' ')) {
|
|
292
|
+
$coords = explode(' ', $coordinates);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
$latitude = $coords[0];
|
|
296
|
+
$longitude = $coords[1];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
300
|
+
return $coordinates;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// if longitude and latitude is invalide throw exception
|
|
304
|
+
if ($latitude === null && $longitude === null) {
|
|
305
|
+
throw new \Exception('Attempted to resolve Point from invalid location.');
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return new \Grimzy\LaravelMysqlSpatial\Types\Point((float) $latitude, (float) $longitude);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Determines if the given coordinates strictly represent a Point object.
|
|
313
|
+
* These will explude resolvable coordinates from records.
|
|
314
|
+
*
|
|
315
|
+
* @param mixed $coordinates the coordinates, which can be an array, object, or string
|
|
316
|
+
*
|
|
317
|
+
* @return bool returns true if $coordinates represents a Point object, false otherwise
|
|
318
|
+
*/
|
|
319
|
+
public static function isCoordinatesStrict($coordinates)
|
|
320
|
+
{
|
|
321
|
+
return static::getPointFromCoordinatesStrict($coordinates) instanceof \Grimzy\LaravelMysqlSpatial\Types\Point;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Resolves a GeoJson/array/object or string representing a point to a Point object.
|
|
326
|
+
* These will explude resolvable coordinates from records.
|
|
327
|
+
*
|
|
328
|
+
* @param mixed $coordinates the coordinates, which can be an array, object, or string
|
|
329
|
+
*
|
|
330
|
+
* @return \Grimzy\LaravelMysqlSpatial\Types\Point Returns the Point instance
|
|
331
|
+
*/
|
|
332
|
+
public static function getPointFromCoordinatesStrict($coordinates): ?\Grimzy\LaravelMysqlSpatial\Types\Point
|
|
333
|
+
{
|
|
334
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression) {
|
|
335
|
+
$coordinates = $coordinates->getSpatialValue();
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
339
|
+
return $coordinates;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (static::isGeoJson($coordinates)) {
|
|
343
|
+
$coordinatesJson = null;
|
|
344
|
+
|
|
345
|
+
if (is_array($coordinates) || is_object($coordinates)) {
|
|
346
|
+
$coordinatesJson = json_encode($coordinates);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (static::isJson($coordinatesJson)) {
|
|
350
|
+
$coordinates = \Grimzy\LaravelMysqlSpatial\Types\Point::fromJson($coordinatesJson);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (is_array($coordinates) || is_object($coordinates)) {
|
|
355
|
+
$latitude = static::or($coordinates, ['_lat', 'lat', '_latitude', 'latitude', 'x', '0']);
|
|
356
|
+
$longitude = static::or($coordinates, ['lon', '_lon', 'long', 'lng', '_lng', '_longitude', 'longitude', 'y', '1']);
|
|
357
|
+
|
|
358
|
+
if (is_numeric($latitude) && is_numeric($longitude)) {
|
|
359
|
+
$coordinates = new \Grimzy\LaravelMysqlSpatial\Types\Point((float) $latitude, (float) $longitude);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (is_string($coordinates)) {
|
|
364
|
+
$coords = [];
|
|
365
|
+
|
|
366
|
+
if (Str::startsWith($coordinates, 'POINT(')) {
|
|
367
|
+
$coordinates = Str::replaceFirst('POINT(', '', $coordinates);
|
|
368
|
+
$coordinates = Str::replace(')', '', $coordinates);
|
|
369
|
+
$coords = explode(' ', $coordinates);
|
|
370
|
+
$coords = array_reverse($coords);
|
|
371
|
+
$coordinates = null;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (preg_match('/LatLng\(([^,]+),\s*([^)]+)\)/', $coordinates, $matches)) {
|
|
375
|
+
$coords = [
|
|
376
|
+
floatval($matches[1]),
|
|
377
|
+
floatval($matches[2]),
|
|
378
|
+
];
|
|
379
|
+
|
|
380
|
+
$coordinates = null;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (Str::contains($coordinates, ',')) {
|
|
384
|
+
$coords = explode(',', $coordinates);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (Str::contains($coordinates, '|')) {
|
|
388
|
+
$coords = explode('|', $coordinates);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (Str::contains($coordinates, ' ')) {
|
|
392
|
+
$coords = explode(' ', $coordinates);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
$latitude = $coords[0];
|
|
396
|
+
$longitude = $coords[1];
|
|
397
|
+
|
|
398
|
+
if (is_numeric($latitude) && is_numeric($longitude)) {
|
|
399
|
+
$coordinates = new \Grimzy\LaravelMysqlSpatial\Types\Point((float) $latitude, (float) $longitude);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
404
|
+
return $coordinates;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Gets a coordinate property from coordinates.
|
|
412
|
+
*
|
|
413
|
+
* @param mixed $coordinates the coordinates input value to extract a coordinate from
|
|
414
|
+
* @param string $prop the coordinate property to extract ('latitude' or 'longitude')
|
|
415
|
+
*
|
|
416
|
+
* @return float the extracted coordinate value as a float
|
|
417
|
+
*/
|
|
418
|
+
public static function getCoordinateFromCoordinates($coordinates, $prop = 'latitude'): float
|
|
419
|
+
{
|
|
420
|
+
$latitude = null;
|
|
421
|
+
$longitude = null;
|
|
422
|
+
|
|
423
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression) {
|
|
424
|
+
$coordinates = $coordinates->getSpatialValue();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if ($coordinates instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
428
|
+
$coordinates = $coordinates->location;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
432
|
+
$latitude = $coordinates->getLat();
|
|
433
|
+
$longitude = $coordinates->getLng();
|
|
434
|
+
} elseif (is_array($coordinates) || is_object($coordinates)) {
|
|
435
|
+
$latitude = static::or($coordinates, ['_lat', 'lat', '_latitude', 'latitude', 'x', '0']);
|
|
436
|
+
$longitude = static::or($coordinates, ['lon', '_lon', 'long', 'lng', '_lng', '_longitude', 'longitude', 'y', '1']);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (is_string($coordinates)) {
|
|
440
|
+
$coords = [];
|
|
441
|
+
|
|
442
|
+
if (Str::startsWith($coordinates, 'place_')) {
|
|
443
|
+
$resolvedPlace = \Fleetbase\FleetOps\Models\Place::where('public_id', $coordinates)->first();
|
|
444
|
+
if ($resolvedPlace instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
445
|
+
return static::getCoordinateFromCoordinates($resolvedPlace);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (Str::isUuid($coordinates)) {
|
|
450
|
+
$resolvedPlace = \Fleetbase\FleetOps\Models\Place::where('uuid', $coordinates)->first();
|
|
451
|
+
if ($resolvedPlace instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
452
|
+
return static::getCoordinateFromCoordinates($resolvedPlace);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (Str::startsWith($coordinates, 'POINT(')) {
|
|
457
|
+
$coordinates = Str::replaceFirst('POINT(', '', $coordinates);
|
|
458
|
+
$coordinates = Str::replace(')', '', $coordinates);
|
|
459
|
+
$coords = explode(' ', $coordinates);
|
|
460
|
+
$coords = array_reverse($coords);
|
|
461
|
+
$coordinates = null;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (preg_match('/LatLng\(([^,]+),\s*([^)]+)\)/', $coordinates, $matches)) {
|
|
465
|
+
$coords = [
|
|
466
|
+
floatval($matches[1]),
|
|
467
|
+
floatval($matches[2]),
|
|
468
|
+
];
|
|
469
|
+
|
|
470
|
+
$coordinates = null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (Str::contains($coordinates, ',')) {
|
|
474
|
+
$coords = explode(',', $coordinates);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (Str::contains($coordinates, '|')) {
|
|
478
|
+
$coords = explode('|', $coordinates);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (Str::contains($coordinates, ' ')) {
|
|
482
|
+
$coords = explode(' ', $coordinates);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
$latitude = $coords[0];
|
|
486
|
+
$longitude = $coords[1];
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return $prop === 'latitude' ? (float) $latitude : (float) $longitude;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Extracts the latitude coordinate value from a given input value representing a location or set of coordinates.
|
|
494
|
+
*
|
|
495
|
+
* @param mixed $coordinates the input value representing a location or set of coordinates
|
|
496
|
+
*
|
|
497
|
+
* @return float the extracted latitude coordinate value as a float
|
|
498
|
+
*/
|
|
499
|
+
public static function getLatitudeFromCoordinates($coordinates): float
|
|
500
|
+
{
|
|
501
|
+
return static::getCoordinateFromCoordinates($coordinates);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Extracts the longitude coordinate value from a given input value representing a location or set of coordinates.
|
|
506
|
+
*
|
|
507
|
+
* @param mixed $coordinates the input value representing a location or set of coordinates
|
|
508
|
+
*
|
|
509
|
+
* @return float the extracted longitude coordinate value as a float
|
|
510
|
+
*/
|
|
511
|
+
public static function getLongitudeFromCoordinates($coordinates): float
|
|
512
|
+
{
|
|
513
|
+
return static::getCoordinateFromCoordinates($coordinates, 'longitude');
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Extracts a point value from a given input value representing a location or set of coordinates.
|
|
518
|
+
*
|
|
519
|
+
* @param mixed $coordinates the input value representing a location or set of coordinates
|
|
520
|
+
*
|
|
521
|
+
* @return \Grimzy\LaravelMysqlSpatial\Types\Point the extracted point value
|
|
522
|
+
*/
|
|
523
|
+
public static function getPointFromCoordinates($coordinates): \Grimzy\LaravelMysqlSpatial\Types\Point
|
|
524
|
+
{
|
|
525
|
+
if ($coordinates instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
526
|
+
return $coordinates;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (is_null($coordinates) || !static::isCoordinates($coordinates)) {
|
|
530
|
+
return new \Grimzy\LaravelMysqlSpatial\Types\Point(0, 0);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
$latitude = static::getLatitudeFromCoordinates($coordinates);
|
|
534
|
+
$longitude = static::getLongitudeFromCoordinates($coordinates);
|
|
535
|
+
|
|
536
|
+
return new \Grimzy\LaravelMysqlSpatial\Types\Point($latitude, $longitude);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Converts a point to a WKT (Well-Known Text) representation for SQL insert.
|
|
541
|
+
*
|
|
542
|
+
* @param mixed $point the input value representing a point
|
|
543
|
+
*
|
|
544
|
+
* @return \Illuminate\Database\Query\Expression the WKT representation of the point as a raw SQL expression
|
|
545
|
+
*/
|
|
546
|
+
public static function parsePointToWkt($point): \Illuminate\Database\Query\Expression
|
|
547
|
+
{
|
|
548
|
+
$wkt = 'POINT(0 0)';
|
|
549
|
+
|
|
550
|
+
if ($point instanceof \Grimzy\LaravelMysqlSpatial\Types\Point) {
|
|
551
|
+
$wkt = $point->toWKT();
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (is_array($point)) {
|
|
555
|
+
$json = json_encode($point);
|
|
556
|
+
$p = \Grimzy\LaravelMysqlSpatial\Types\Point::fromJson($json);
|
|
557
|
+
|
|
558
|
+
$wkt = $p->toWkt();
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (is_string($point)) {
|
|
562
|
+
$p = \Grimzy\LaravelMysqlSpatial\Types\Point::fromString($point);
|
|
563
|
+
|
|
564
|
+
$wkt = $p->toWKT();
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Use the `ST_PointFromText` function to convert the WKT representation to a SQL expression.
|
|
568
|
+
return DB::raw("(ST_PointFromText('$wkt', 0, 'axis-order=long-lat'))");
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Converts a raw point binary string to a float pair representing the point's coordinates.
|
|
573
|
+
*
|
|
574
|
+
* @param string $data the binary string representing the point
|
|
575
|
+
*
|
|
576
|
+
* @return array the float pair representing the point's coordinates
|
|
577
|
+
*/
|
|
578
|
+
public static function rawPointToFloatPair(string $data): array
|
|
579
|
+
{
|
|
580
|
+
// Use the `unpack` function to extract the X and Y coordinates from the binary string.
|
|
581
|
+
$res = unpack('lSRID/CByteOrder/lTypeInfo/dX/dY', $data);
|
|
582
|
+
|
|
583
|
+
// Return the float pair representing the point's coordinates.
|
|
584
|
+
return [$res['X'], $res['Y']];
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Converts a raw point binary string to a Laravel MySQL Spatial Point instance.
|
|
589
|
+
*
|
|
590
|
+
* @param string $data the binary string representing the point
|
|
591
|
+
*
|
|
592
|
+
* @return \Grimzy\LaravelMysqlSpatial\Types\Point the Laravel MySQL Spatial Point instance
|
|
593
|
+
*/
|
|
594
|
+
public static function rawPointToPoint(string $data): \Grimzy\LaravelMysqlSpatial\Types\Point
|
|
595
|
+
{
|
|
596
|
+
// Use the `unpack` function to extract the X, Y, and SRID values from the binary string.
|
|
597
|
+
$res = unpack('lSRID/CByteOrder/lTypeInfo/dX/dY', $data);
|
|
598
|
+
|
|
599
|
+
// Return a new Laravel MySQL Spatial Point instance with the X, Y, and SRID values.
|
|
600
|
+
return new \Grimzy\LaravelMysqlSpatial\Types\Point($res['X'], $res['Y'], $res['SRID']);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Calculates driving distance and time using Google distance matrix.
|
|
605
|
+
* Returns distance in meters and time in seconds.
|
|
606
|
+
*
|
|
607
|
+
* @param \Fleetbase\FleetOps\Models\Place|\Grimzy\LaravelMysqlSpatial\Types\Point|array $origin
|
|
608
|
+
* @param \Fleetbase\FleetOps\Models\Place|\Grimzy\LaravelMysqlSpatial\Types\Point|array $destination
|
|
609
|
+
*/
|
|
610
|
+
public static function getDrivingDistanceAndTime($origin, $destination): DistanceMatrix
|
|
611
|
+
{
|
|
612
|
+
if ($origin instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
613
|
+
$origin = static::createObject(
|
|
614
|
+
[
|
|
615
|
+
'latitude' => $origin->location->getLat(),
|
|
616
|
+
'longitude' => $origin->location->getLng(),
|
|
617
|
+
]
|
|
618
|
+
);
|
|
619
|
+
} else {
|
|
620
|
+
$point = static::getPointFromMixed($origin);
|
|
621
|
+
$origin = static::createObject(
|
|
622
|
+
[
|
|
623
|
+
'latitude' => $point->getLat(),
|
|
624
|
+
'longitude' => $point->getLng(),
|
|
625
|
+
]
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if ($destination instanceof \Fleetbase\FleetOps\Models\Place) {
|
|
630
|
+
$destination = static::createObject(
|
|
631
|
+
[
|
|
632
|
+
'latitude' => $destination->location->getLat(),
|
|
633
|
+
'longitude' => $destination->location->getLng(),
|
|
634
|
+
]
|
|
635
|
+
);
|
|
636
|
+
} else {
|
|
637
|
+
$point = static::getPointFromMixed($destination);
|
|
638
|
+
$destination = static::createObject(
|
|
639
|
+
[
|
|
640
|
+
'latitude' => $point->getLat(),
|
|
641
|
+
'longitude' => $point->getLng(),
|
|
642
|
+
]
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
$cacheKey = $origin->latitude . ':' . $origin->longitude . ':' . $destination->latitude . ':' . $destination->longitude;
|
|
647
|
+
|
|
648
|
+
// check cache for results
|
|
649
|
+
$cachedResult = Redis::get($cacheKey);
|
|
650
|
+
|
|
651
|
+
if ($cachedResult) {
|
|
652
|
+
$json = json_decode($cachedResult);
|
|
653
|
+
|
|
654
|
+
if (!empty($json->distance) && !empty($json->time)) {
|
|
655
|
+
return new DistanceMatrix($json->distance, $json->time);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
$response = Http::get(
|
|
660
|
+
'https://maps.googleapis.com/maps/api/distancematrix/json',
|
|
661
|
+
[
|
|
662
|
+
'origins' => $origin->latitude . ',' . $origin->longitude,
|
|
663
|
+
'destinations' => $destination->latitude . ',' . $destination->longitude,
|
|
664
|
+
'mode' => 'driving',
|
|
665
|
+
'key' => env('GOOGLE_MAPS_API_KEY'),
|
|
666
|
+
]
|
|
667
|
+
)->json();
|
|
668
|
+
|
|
669
|
+
$distance = data_get($response, 'rows.0.elements.0.distance.value');
|
|
670
|
+
$time = data_get($response, 'rows.0.elements.0.duration.value');
|
|
671
|
+
|
|
672
|
+
$result = static::createObject(
|
|
673
|
+
[
|
|
674
|
+
'distance' => $distance,
|
|
675
|
+
'time' => $time,
|
|
676
|
+
]
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
// cache result
|
|
680
|
+
Redis::set($cacheKey, json_encode($result));
|
|
681
|
+
|
|
682
|
+
return new DistanceMatrix($distance, $time);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Calculates driving distance and time using Google distance matrix for multiple origins or destinations.
|
|
687
|
+
* Returns distance in meters and time in seconds.
|
|
688
|
+
*
|
|
689
|
+
* @param Place|Point|array $origins
|
|
690
|
+
* @param Place|Point|array $destinations
|
|
691
|
+
*/
|
|
692
|
+
public static function distanceMatrix($origins = [], $destinations = []): DistanceMatrix
|
|
693
|
+
{
|
|
694
|
+
if ($origins instanceof \Illuminate\Support\Collection) {
|
|
695
|
+
$origins = $origins->all();
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if ($destinations instanceof \Illuminate\Support\Collection) {
|
|
699
|
+
$destinations = $destinations->all();
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
$origins = array_map(
|
|
703
|
+
function ($origin) {
|
|
704
|
+
$point = static::getPointFromMixed($origin);
|
|
705
|
+
$origin = static::createObject(
|
|
706
|
+
[
|
|
707
|
+
'latitude' => $point->getLat(),
|
|
708
|
+
'longitude' => $point->getLng(),
|
|
709
|
+
]
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
return $origin;
|
|
713
|
+
},
|
|
714
|
+
$origins
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
$destinations = array_map(
|
|
718
|
+
function ($destination) {
|
|
719
|
+
$point = static::getPointFromMixed($destination);
|
|
720
|
+
$destination = static::createObject(
|
|
721
|
+
[
|
|
722
|
+
'latitude' => $point->getLat(),
|
|
723
|
+
'longitude' => $point->getLng(),
|
|
724
|
+
]
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
return $destination;
|
|
728
|
+
},
|
|
729
|
+
$destinations
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
// get url ready string for origins
|
|
733
|
+
$originsString = implode('|', array_map(
|
|
734
|
+
function ($origin) {
|
|
735
|
+
return $origin->latitude . ',' . $origin->longitude;
|
|
736
|
+
},
|
|
737
|
+
$origins
|
|
738
|
+
));
|
|
739
|
+
|
|
740
|
+
// get url ready string for origins
|
|
741
|
+
$destinationString = implode('|', array_map(
|
|
742
|
+
function ($destination) {
|
|
743
|
+
return $destination->latitude . ',' . $destination->longitude;
|
|
744
|
+
},
|
|
745
|
+
$destinations
|
|
746
|
+
));
|
|
747
|
+
|
|
748
|
+
$cacheKey = md5($originsString . '_' . $destinationString);
|
|
749
|
+
|
|
750
|
+
// check cache for results
|
|
751
|
+
$cachedResult = Redis::get($cacheKey);
|
|
752
|
+
|
|
753
|
+
if ($cachedResult) {
|
|
754
|
+
$json = json_decode($cachedResult);
|
|
755
|
+
|
|
756
|
+
if (!empty($json->distance) && !empty($json->time)) {
|
|
757
|
+
return new DistanceMatrix($json->distance, $json->time);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
$response = Http::get(
|
|
762
|
+
'https://maps.googleapis.com/maps/api/distancematrix/json',
|
|
763
|
+
[
|
|
764
|
+
'origins' => $originsString,
|
|
765
|
+
'destinations' => $destinationString,
|
|
766
|
+
'mode' => 'driving',
|
|
767
|
+
'key' => env('GOOGLE_MAPS_API_KEY'),
|
|
768
|
+
]
|
|
769
|
+
)->json();
|
|
770
|
+
|
|
771
|
+
$distance = data_get($response, 'rows.0.elements.0.distance.value');
|
|
772
|
+
$time = data_get($response, 'rows.0.elements.0.duration.value');
|
|
773
|
+
|
|
774
|
+
$result = static::createObject(
|
|
775
|
+
[
|
|
776
|
+
'distance' => $distance,
|
|
777
|
+
'time' => $time,
|
|
778
|
+
]
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
// cache result
|
|
782
|
+
Redis::set($cacheKey, json_encode($result));
|
|
783
|
+
|
|
784
|
+
return new DistanceMatrix($distance, $time);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Calculates driving distance and time between two points using Vincenty's formula.
|
|
789
|
+
* Returns distance in meters and time in seconds.
|
|
790
|
+
*
|
|
791
|
+
* @param \Fleetbase\FleetOps\Models\Place|\Grimzy\LaravelMysqlSpatial\Types\Point|array $origin
|
|
792
|
+
* @param \Fleetbase\FleetOps\Models\Place|\Grimzy\LaravelMysqlSpatial\Types\Point|array $destination
|
|
793
|
+
*/
|
|
794
|
+
public static function calculateDrivingDistanceAndTime($origin, $destination): DistanceMatrix
|
|
795
|
+
{
|
|
796
|
+
$origin = static::getPointFromMixed($origin);
|
|
797
|
+
$destination = static::getPointFromMixed($destination);
|
|
798
|
+
|
|
799
|
+
$distance = Utils::vincentyGreatCircleDistance($origin, $destination);
|
|
800
|
+
$time = round($distance / 100) * self::DRIVING_TIME_MULTIPLIER;
|
|
801
|
+
|
|
802
|
+
return new DistanceMatrix($distance, $time);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Alias for `calculateDrivingDistanceAndTime`
|
|
807
|
+
* Calculates driving distance and time between two points using Vincenty's formula.
|
|
808
|
+
* Returns distance in meters and time in seconds.
|
|
809
|
+
*
|
|
810
|
+
* @param \Fleetbase\FleetOps\Models\Place|\Grimzy\LaravelMysqlSpatial\Types\Point|array $origin
|
|
811
|
+
* @param \Fleetbase\FleetOps\Models\Place|\Grimzy\LaravelMysqlSpatial\Types\Point|array $destination
|
|
812
|
+
*/
|
|
813
|
+
public static function getPreliminaryDistanceMatrix($origin, $destination): DistanceMatrix
|
|
814
|
+
{
|
|
815
|
+
return static::calculateDrivingDistanceAndTime($origin, $destination);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Format distance in meters to kilometers or meters.
|
|
820
|
+
*
|
|
821
|
+
* @param float $meters Distance in meters
|
|
822
|
+
* @param bool $abbreviate Whether to use abbreviated unit or not
|
|
823
|
+
*/
|
|
824
|
+
public static function formatMeters(float $meters, bool $abbreviate = true): string
|
|
825
|
+
{
|
|
826
|
+
if ($meters > 1000) {
|
|
827
|
+
$distance = round($meters / 1000, 2);
|
|
828
|
+
$unit = $abbreviate ? 'km' : 'kilometers';
|
|
829
|
+
} else {
|
|
830
|
+
$distance = round($meters);
|
|
831
|
+
$unit = $abbreviate ? 'm' : 'meters';
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
return $distance . ' ' . $unit;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Calculates the great-circle distance between two points, with
|
|
839
|
+
* the Vincenty formula. (Using over haversine tdue to antipodal point issues).
|
|
840
|
+
*
|
|
841
|
+
* https://en.wikipedia.org/wiki/Great-circle_distance#Formulas
|
|
842
|
+
* https://en.wikipedia.org/wiki/Antipodal_point
|
|
843
|
+
*
|
|
844
|
+
* @param \Grimzy\LaravelMysqlSpatial\Types\Point Starting point
|
|
845
|
+
* @param \Grimzy\LaravelMysqlSpatial\Types\Point Ending point
|
|
846
|
+
* @param float $earthRadius Mean earth radius in [m]
|
|
847
|
+
*
|
|
848
|
+
* @return float Distance between points in [m] (same as earthRadius)
|
|
849
|
+
*/
|
|
850
|
+
public static function vincentyGreatCircleDistance(\Grimzy\LaravelMysqlSpatial\Types\Point $from, \Grimzy\LaravelMysqlSpatial\Types\Point $to, float $earthRadius = 6371000): float
|
|
851
|
+
{
|
|
852
|
+
// convert from degrees to radians
|
|
853
|
+
$latFrom = deg2rad($from->getLat());
|
|
854
|
+
$lonFrom = deg2rad($from->getLng());
|
|
855
|
+
$latTo = deg2rad($to->getLat());
|
|
856
|
+
$lonTo = deg2rad($to->getLng());
|
|
857
|
+
|
|
858
|
+
$lonDelta = $lonTo - $lonFrom;
|
|
859
|
+
$a = pow(cos($latTo) * sin($lonDelta), 2) +
|
|
860
|
+
pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2);
|
|
861
|
+
$b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta);
|
|
862
|
+
|
|
863
|
+
$angle = atan2(sqrt($a), $b);
|
|
864
|
+
|
|
865
|
+
return $angle * $earthRadius;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Finds the nearest timezone for a given coordinate point.
|
|
870
|
+
*/
|
|
871
|
+
public static function getNearestTimezone(\Grimzy\LaravelMysqlSpatial\Types\Point $location, string $countryCode = ''): string
|
|
872
|
+
{
|
|
873
|
+
$timezoneIds = \DateTimeZone::listIdentifiers(\DateTimeZone::PER_COUNTRY, $countryCode);
|
|
874
|
+
$lat = $location->getLat();
|
|
875
|
+
$long = $location->getLng();
|
|
876
|
+
$minDistance = INF;
|
|
877
|
+
$timezone = 'unknown';
|
|
878
|
+
|
|
879
|
+
foreach ($timezoneIds as $timezoneId) {
|
|
880
|
+
$tz = new \DateTimeZone($timezoneId);
|
|
881
|
+
$location = $tz->getLocation();
|
|
882
|
+
$tzLat = $location['latitude'];
|
|
883
|
+
$tzLong = $location['longitude'];
|
|
884
|
+
|
|
885
|
+
$theta = $long - $tzLong;
|
|
886
|
+
$distance = sin(deg2rad($lat)) * sin(deg2rad($tzLat)) + cos(deg2rad($lat)) * cos(deg2rad($tzLat)) * cos(deg2rad($theta));
|
|
887
|
+
$distance = acos($distance);
|
|
888
|
+
$distance = abs(rad2deg($distance));
|
|
889
|
+
|
|
890
|
+
if ($distance < $minDistance) {
|
|
891
|
+
$minDistance = $distance;
|
|
892
|
+
$timezone = $timezoneId;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
return $timezone;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
* Determines whether a given vendor ID is an integrated vendor ID or not.
|
|
901
|
+
*
|
|
902
|
+
* @param string $id the vendor ID to check
|
|
903
|
+
*
|
|
904
|
+
* @return bool returns true if the given ID is an integrated vendor ID or is present in the "integrated_vendors" database table for the current company session, false otherwise
|
|
905
|
+
*/
|
|
906
|
+
public static function isIntegratedVendorId(string $id): bool
|
|
907
|
+
{
|
|
908
|
+
if (Str::startsWith($id, 'integrated_vendor_')) {
|
|
909
|
+
return true;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
$providerIds = DB::table('integrated_vendors')
|
|
913
|
+
->select('provider')
|
|
914
|
+
->where('company_uuid', session('company'))
|
|
915
|
+
->distinct()
|
|
916
|
+
->get()
|
|
917
|
+
->map(function ($result) {
|
|
918
|
+
return $result->provider;
|
|
919
|
+
})
|
|
920
|
+
->toArray();
|
|
921
|
+
|
|
922
|
+
return in_array($id, $providerIds);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Gets data from a JSON file containing globe data and decodes it into a PHP object.
|
|
927
|
+
*
|
|
928
|
+
* @return object the decoded JSON object containing globe data
|
|
929
|
+
*/
|
|
930
|
+
public static function getGlobeData()
|
|
931
|
+
{
|
|
932
|
+
ini_set('memory_limit', '-1');
|
|
933
|
+
|
|
934
|
+
$data = file_get_contents(resource_path('data/globe.json'));
|
|
935
|
+
$geoJson = json_decode($data);
|
|
936
|
+
|
|
937
|
+
return $geoJson;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Creates a MultiPolygon object from the provided country's ISO code.
|
|
942
|
+
*
|
|
943
|
+
* @param string $country the ISO_A3 or ISO_A2 code of the country
|
|
944
|
+
*
|
|
945
|
+
* @return \Grimzy\LaravelMysqlSpatial\Types\MultiPolygon|null the MultiPolygon object or null if not found
|
|
946
|
+
*/
|
|
947
|
+
public static function createPolygonFromCountry(string $country): ?\Grimzy\LaravelMysqlSpatial\Types\MultiPolygon
|
|
948
|
+
{
|
|
949
|
+
$globe = static::getGlobeData();
|
|
950
|
+
$country = strtolower($country);
|
|
951
|
+
|
|
952
|
+
$feature = collect($globe->features)->first(
|
|
953
|
+
function ($feature) use ($country) {
|
|
954
|
+
if (!isset($feature->properties->ISO_A3) || !isset($feature->properties->ISO_A2)) {
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
return strtolower($feature->properties->ISO_A3) === $country || strtolower($feature->properties->ISO_A2) === $country;
|
|
959
|
+
}
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
if ($feature) {
|
|
963
|
+
return \Grimzy\LaravelMysqlSpatial\Types\MultiPolygon::fromJson(json_encode($feature->geometry));
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
public static function isPoint($point): bool
|
|
970
|
+
{
|
|
971
|
+
return $point instanceof \Grimzy\LaravelMysqlSpatial\Types\Point;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Converts latitude, longitude, and radius to an array of circle coordinates.
|
|
976
|
+
*
|
|
977
|
+
* @param float $latitude the latitude in degrees
|
|
978
|
+
* @param float $longitude the longitude in degrees
|
|
979
|
+
* @param float $meters the radius in meters
|
|
980
|
+
*
|
|
981
|
+
* @return array an array of circle coordinates
|
|
982
|
+
*/
|
|
983
|
+
public static function coordsToCircle($latitude, $longitude, $meters)
|
|
984
|
+
{
|
|
985
|
+
$latitude = deg2rad($latitude);
|
|
986
|
+
$longitude = deg2rad($longitude);
|
|
987
|
+
// convert meters to km
|
|
988
|
+
$radius = ($meters * 1000) / 6378137;
|
|
989
|
+
// create circle coordinates
|
|
990
|
+
$coords = collect();
|
|
991
|
+
// loop through the array and write path linestrings
|
|
992
|
+
for ($i = 0; $i <= 360; $i += 3) {
|
|
993
|
+
$radial = deg2rad($i);
|
|
994
|
+
$lat_rad = asin(sin($latitude) * cos($radius) + cos($latitude) * sin($radius) * cos($radial));
|
|
995
|
+
$dlon_rad = atan2(sin($radial) * sin($radius) * cos($latitude), cos($radius) - sin($latitude) * sin($lat_rad));
|
|
996
|
+
$lon_rad = fmod($longitude + $dlon_rad + M_PI, 2 * M_PI) - M_PI;
|
|
997
|
+
$coords->push([rad2deg($lat_rad), rad2deg($lon_rad)]);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
return $coords->toArray();
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Calculates the centroid (geometric center) of the provided coordinates.
|
|
1005
|
+
*
|
|
1006
|
+
* @param array $coord an array of coordinates
|
|
1007
|
+
*
|
|
1008
|
+
* @return array the centroid of the coordinates as an array [latitude, longitude]
|
|
1009
|
+
*/
|
|
1010
|
+
public static function getCentroid($coord)
|
|
1011
|
+
{
|
|
1012
|
+
$centroid = array_reduce($coord, function ($x, $y) use ($coord) {
|
|
1013
|
+
$len = count($coord);
|
|
1014
|
+
|
|
1015
|
+
return [$x[0] + $y[0] / $len, $x[1] + $y[1] / $len];
|
|
1016
|
+
}, [0, 0]);
|
|
1017
|
+
|
|
1018
|
+
return $centroid;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
public static function getCoordinatesFromPolygon(?\Grimzy\LaravelMysqlSpatial\Types\Polygon $polygon): array
|
|
1022
|
+
{
|
|
1023
|
+
return Arr::first($polygon->jsonSerialize()->getCoordinates());
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/**
|
|
1027
|
+
* Alias function to `getModelClassName` but uses FleetOps namespace.
|
|
1028
|
+
*
|
|
1029
|
+
* @param string|object $table the table name or an object instance to derive the class name from
|
|
1030
|
+
* @param string|array $namespaceSegments a string representing the namespace or an array of segments to be appended to the model class name
|
|
1031
|
+
*
|
|
1032
|
+
* @return string the fully qualified class name, including the namespace
|
|
1033
|
+
*
|
|
1034
|
+
* @throws InvalidArgumentException if the provided $namespaceSegments is not a string or an array
|
|
1035
|
+
*/
|
|
1036
|
+
public static function getModelClassName($table, $namespaceSegments = '\\Fleetbase\\FleetOps\\'): string
|
|
1037
|
+
{
|
|
1038
|
+
return parent::getModelClassName($table, $namespaceSegments);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Determines if the given variable is a valid GeoJSON.
|
|
1043
|
+
*
|
|
1044
|
+
* This function accepts a GeoJSON string, array, or object and checks for the required
|
|
1045
|
+
* GeoJSON properties: 'type' and either 'coordinates' or 'geometries', depending on the type.
|
|
1046
|
+
*
|
|
1047
|
+
* @param string|array|object $geoJson the GeoJSON input, which can be a JSON string, an array, or an object
|
|
1048
|
+
*
|
|
1049
|
+
* @return bool returns true if the input is valid GeoJSON, false otherwise
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* $geoJsonString = '{"type":"Point","coordinates":[106.9338169,47.9131423]}';
|
|
1053
|
+
* isGeoJson($geoJsonString); // true
|
|
1054
|
+
*/
|
|
1055
|
+
public static function isGeoJson($geoJson)
|
|
1056
|
+
{
|
|
1057
|
+
// If the input is a JSON string, decode it
|
|
1058
|
+
if (is_string($geoJson) && static::isJson($geoJson)) {
|
|
1059
|
+
$geoJson = json_decode($geoJson, true);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// Check if the input is an array or an object
|
|
1063
|
+
if (is_array($geoJson) || is_object($geoJson)) {
|
|
1064
|
+
// Convert to array if it's an object
|
|
1065
|
+
if (is_object($geoJson)) {
|
|
1066
|
+
$geoJson = (array) $geoJson;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// Check for required GeoJSON properties: 'type' and 'coordinates' or 'geometries'
|
|
1070
|
+
if (isset($geoJson['type'])) {
|
|
1071
|
+
if ($geoJson['type'] === 'GeometryCollection' && isset($geoJson['geometries'])) {
|
|
1072
|
+
return true;
|
|
1073
|
+
} elseif (in_array($geoJson['type'], ['Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon']) && isset($geoJson['coordinates'])) {
|
|
1074
|
+
return true;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
return false;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
* Creates a SpatialExpression object from a valid GeoJSON input.
|
|
1084
|
+
*
|
|
1085
|
+
* @param mixed $geoJson the GeoJSON input, which can be an array, object, or JSON string representing a valid GeoJSON object
|
|
1086
|
+
*
|
|
1087
|
+
* @return \Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression|null returns a SpatialExpression object if the input is a valid GeoJSON, or null if the input is not valid
|
|
1088
|
+
*
|
|
1089
|
+
* @throws \InvalidArgumentException if the input is not a valid GeoJSON object
|
|
1090
|
+
*/
|
|
1091
|
+
public static function createSpatialExpressionFromGeoJson($geoJson): ?\Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression
|
|
1092
|
+
{
|
|
1093
|
+
if (!static::isGeoJson($geoJson)) {
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
if (is_string($geoJson) && static::isJson($geoJson)) {
|
|
1098
|
+
$geoJson = json_decode($geoJson, true);
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
// Convert the value to JSON and create a Geometry object
|
|
1102
|
+
$json = json_encode($geoJson);
|
|
1103
|
+
$geo = \Grimzy\LaravelMysqlSpatial\Types\Geometry::fromJson($json);
|
|
1104
|
+
|
|
1105
|
+
// Return a new SpatialExpression object
|
|
1106
|
+
return new \Grimzy\LaravelMysqlSpatial\Eloquent\SpatialExpression($geo);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Calculate the heading between two geographical points.
|
|
1111
|
+
*
|
|
1112
|
+
* @param Point $point1 the starting point with latitude and longitude
|
|
1113
|
+
* @param Point $point2 the ending point with latitude and longitude
|
|
1114
|
+
*
|
|
1115
|
+
* @return float the heading in degrees from the starting point to the ending point
|
|
1116
|
+
*/
|
|
1117
|
+
public static function calculateHeading(\Grimzy\LaravelMysqlSpatial\Types\Point $point1, \Grimzy\LaravelMysqlSpatial\Types\Point $point2): float
|
|
1118
|
+
{
|
|
1119
|
+
// Extract latitude and longitude from Point objects
|
|
1120
|
+
$lat1 = $point1->getLat();
|
|
1121
|
+
$lon1 = $point1->getLng();
|
|
1122
|
+
$lat2 = $point2->getLat();
|
|
1123
|
+
$lon2 = $point2->getLng();
|
|
1124
|
+
|
|
1125
|
+
// Convert latitude and longitude from degrees to radians
|
|
1126
|
+
$lat1 = deg2rad($lat1);
|
|
1127
|
+
$lat2 = deg2rad($lat2);
|
|
1128
|
+
$delta_lon = deg2rad($lon2 - $lon1);
|
|
1129
|
+
|
|
1130
|
+
// Calculate X and Y differences
|
|
1131
|
+
$x = cos($lat2) * sin($delta_lon);
|
|
1132
|
+
$y = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($delta_lon);
|
|
1133
|
+
|
|
1134
|
+
// Calculate the angle
|
|
1135
|
+
$theta_rad = atan2($x, $y);
|
|
1136
|
+
|
|
1137
|
+
// Convert the angle from radians to degrees
|
|
1138
|
+
$theta_deg = rad2deg($theta_rad);
|
|
1139
|
+
|
|
1140
|
+
// Normalize the degree to be between 0 and 360
|
|
1141
|
+
$theta_deg = fmod($theta_deg + 360, 360);
|
|
1142
|
+
|
|
1143
|
+
return $theta_deg;
|
|
1144
|
+
}
|
|
1145
|
+
}
|