Complete port of all 163 API endpoints from Lucee/CFML to PHP 8.3. Shared helpers in api/helpers.php (DB, auth, request/response, security). PDO prepared statements throughout. Same JSON response shapes as CFML.
83 lines
2.6 KiB
PHP
83 lines
2.6 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../helpers.php';
|
|
runAuth();
|
|
|
|
/**
|
|
* List Businesses
|
|
* POST: { lat?: float, lng?: float }
|
|
* Returns nearest 50 businesses sorted by distance.
|
|
*/
|
|
|
|
function haversineDistance(float $lat1, float $lng1, float $lat2, float $lng2): float {
|
|
$R = 3959; // Earth radius in miles
|
|
$dLat = deg2rad($lat2 - $lat1);
|
|
$dLng = deg2rad($lng2 - $lng1);
|
|
$a = sin($dLat / 2) ** 2 +
|
|
cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
|
|
sin($dLng / 2) ** 2;
|
|
$a = max(0, min(1, $a));
|
|
$c = 2 * asin(sqrt($a));
|
|
return $R * $c;
|
|
}
|
|
|
|
try {
|
|
$data = readJsonBody();
|
|
$userLat = (float) ($data['lat'] ?? 0);
|
|
$userLng = (float) ($data['lng'] ?? 0);
|
|
$hasUserLocation = ($userLat != 0 && $userLng != 0);
|
|
|
|
$rows = queryTimed("
|
|
SELECT
|
|
b.ID, b.Name, b.ParentBusinessID,
|
|
(SELECT COUNT(*) FROM Businesses c WHERE c.ParentBusinessID = b.ID) AS ChildCount,
|
|
a.Latitude AS AddressLat, a.Longitude AS AddressLng,
|
|
a.City AS AddressCity, a.Line1 AS AddressLine1
|
|
FROM Businesses b
|
|
LEFT JOIN Addresses a ON b.AddressID = a.ID
|
|
WHERE (b.IsDemo = 0 OR b.IsDemo IS NULL)
|
|
AND (b.IsPrivate = 0 OR b.IsPrivate IS NULL)
|
|
AND (b.ParentBusinessID IS NULL OR b.ParentBusinessID = 0)
|
|
ORDER BY b.Name
|
|
");
|
|
|
|
$businesses = [];
|
|
foreach ($rows as $r) {
|
|
$bizLat = (float) ($r['AddressLat'] ?? 0);
|
|
$bizLng = (float) ($r['AddressLng'] ?? 0);
|
|
|
|
$distance = 99999;
|
|
if ($hasUserLocation && $bizLat != 0 && $bizLng != 0) {
|
|
$distance = haversineDistance($userLat, $userLng, $bizLat, $bizLng);
|
|
}
|
|
|
|
$businesses[] = [
|
|
'BusinessID' => (int) $r['ID'],
|
|
'Name' => $r['Name'],
|
|
'HasChildren' => ((int) $r['ChildCount']) > 0,
|
|
'City' => $r['AddressCity'] ?? '',
|
|
'Line1' => $r['AddressLine1'] ?? '',
|
|
'Latitude' => $bizLat,
|
|
'Longitude' => $bizLng,
|
|
'DistanceMiles' => $distance,
|
|
];
|
|
}
|
|
|
|
// Sort by distance if user location provided
|
|
if ($hasUserLocation) {
|
|
usort($businesses, fn($a, $b) => $a['DistanceMiles'] <=> $b['DistanceMiles']);
|
|
}
|
|
|
|
// Limit to 50
|
|
$businesses = array_slice($businesses, 0, 50);
|
|
|
|
jsonResponse([
|
|
'OK' => true,
|
|
'ERROR' => '',
|
|
'VERSION' => 'businesses_list_v5',
|
|
'BUSINESSES' => $businesses,
|
|
'Businesses' => $businesses,
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
apiAbort(['OK' => false, 'ERROR' => 'server_error', 'DETAIL' => $e->getMessage()]);
|
|
}
|