Update: 2026-07-02 16:52:25

This commit is contained in:
Hamza-Ayed
2026-07-02 16:52:25 +03:00
parent 75e6fc42d7
commit 5d14493ff4
9 changed files with 213 additions and 20 deletions
+82
View File
@@ -449,6 +449,86 @@ if (!empty($passenger_id)) {
}
}
// 🆕 المطابقة الذكية للوجهة (Destination Matching)
// Architecture: GEORADIUS (O(log N+K)) → detail fetch → SQL fallback
$isDestinationMatch = false;
$matchedDriverId = 0;
try {
$bestDriverId = 0;
$foundViaRedis = false;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 🟥 Step 1: Redis GEORADIUS — ultra-fast O(log N + K) search
// Finds all drivers whose destination is within 3.5 km of
// the passenger's drop-off point. No PHP math. No full scan.
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
if (isset($redis)) {
try {
// geoRadius(key, longitude, latitude, radius, unit, [options])
$nearbyDriverIds = $redis->geoRadius(
'geo:driver:destinations',
(float)$destLng,
(float)$destLat,
3.5,
'km',
['COUNT' => 1, 'ASC'] // closest first, stop after 1
);
if (!empty($nearbyDriverIds)) {
$candidateId = (string)$nearbyDriverIds[0];
// Verify destination is still active today (read detail JSON)
$detailJson = $redis->get("driver:destination:{$candidateId}");
$detail = $detailJson ? json_decode($detailJson, true) : null;
if ($detail
&& !empty($detail['is_active'])
&& ($detail['usage_date'] ?? '') === date('Y-m-d')
) {
$bestDriverId = $candidateId;
$foundViaRedis = true;
} else {
// Stale entry — clean up from geo index
$redis->zRem('geo:driver:destinations', $candidateId);
}
}
} catch (Exception $e) {
error_log("[Destination Matching] Redis GEORADIUS error: " . $e->getMessage());
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 🟦 Step 2: SQL Fallback (only if Redis unavailable or empty)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
if (!$foundViaRedis) {
$stmtDest = $con->prepare("
SELECT driver_id,
( 6371 * acos( cos( radians(:endLat) ) * cos( radians( target_latitude ) )
* cos( radians( target_longitude ) - radians(:endLng) ) + sin( radians(:endLat) )
* sin( radians( target_latitude ) ) ) ) AS dest_distance
FROM driver_destinations
WHERE is_active = 1 AND usage_date = CURDATE()
HAVING dest_distance <= 3.5
ORDER BY dest_distance ASC
LIMIT 1
");
$stmtDest->execute([':endLat' => $destLat, ':endLng' => $destLng]);
$destMatch = $stmtDest->fetch(PDO::FETCH_ASSOC);
if ($destMatch) {
$bestDriverId = $destMatch['driver_id'];
}
}
if ($bestDriverId) {
$isDestinationMatch = true;
$matchedDriverId = $bestDriverId;
// Passenger gets 14% discount for Destination Match
$discount = max((float)$discount, 14.0);
}
} catch (Exception $e) {
error_log("[Destination Matching] Error: " . $e->getMessage());
}
// Calculate prices for all categories
foreach ($categories as $key => $carType) {
$result = calculateDynamicPrice($country, $minFare, $distance, $duration, $kazanRow, $startNameAddress, $endNameAddress, $destLat, $destLng, $passengerLat, $passengerLng, $carType);
@@ -497,6 +577,8 @@ if (isset($encryptionHelper)) {
// ✅ FIX R6: تضمين distance و duration في الـ token لمنع التلاعب
'distance' => $distance,
'duration' => $duration,
'is_destination_match' => $isDestinationMatch ? 1 : 0,
'matched_driver_id' => $matchedDriverId,
'expires' => time() + 420, // Valid for 7 minutes
'prices' => $pricesRaw
];