Files
intaleq_v3_pure_php/ride/rides/acceptRide.php
Hamza-Ayed 86de67a41d 8
2026-04-28 15:25:15 +03:00

185 lines
7.7 KiB
PHP
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// acceptRide.php
// 1. Include Database Connection
// This file connects to both the Main DB ($con) and the Ride DB ($con_ride).
require_once __DIR__ . '/../../connect.php';
// 2. Input Validation & Filtering
$rideId = filterRequest("id");
$driverId = filterRequest("driver_id");
$status = filterRequest("status"); // Expected: 'Apply' or 'accepted'
$passengerToken = filterRequest("passengerToken");
// Log incoming data for debugging
error_log(" [ACCEPT_RIDE_TRY] RideID: '$rideId' | DriverID: '$driverId' | Status: '$status' | PToken: '$passengerToken'");
// Check if critical data is missing
if (!$rideId || !$driverId) {
error_log("⛔ [ACCEPT_RIDE_FAIL] Missing parameters.");
jsonError("Missing required parameters.");
exit;
}
try {
// =================================================================================
// 3. 🔒 ATOMIC UPDATE (The Race Condition Solver)
// We attempt to update the ride status ONLY if it is currently 'waiting'.
// This prevents two drivers from accepting the same ride simultaneously.
// We execute this on the Remote/Ride Database first ($con_ride).
// =================================================================================
$stmtRemote = $con_ride->prepare("
UPDATE `ride`
SET `status` = ?, `driver_id` = ?, `rideTimeStart` = NOW()
WHERE `id` = ? AND `status` IN ('waiting', 'wait')
");
$stmtRemote->execute([$status, $driverId, $rideId]);
// Check if the update actually changed a row.
// If rowCount > 0, IT MEANS SUCCESS! This driver won the ride.
if ($stmtRemote->rowCount() > 0) {
// 4. Synchronization: Update Local Database
// Now that we secured the ride, we update the main server's DB ($con) to match.
if (isset($con)) {
$stmtLocal = $con->prepare("UPDATE `ride` SET `driver_id` = ?, `status` = ?, `rideTimeStart` = NOW() WHERE id = ?");
$stmtLocal->execute([$driverId, $status, $rideId]);
}
// 5. Update/Insert Driver Orders Table
// This tracks the driver's history or active orders.
$checkSql = "SELECT `order_id` FROM `driver_orders` WHERE `order_id` = ?";
$checkStmt = $con->prepare($checkSql);
$checkStmt->execute([$rideId]);
if ($checkStmt->rowCount() > 0) {
// If entry exists, update it
$updateSql = "UPDATE `driver_orders` SET `driver_id` = ?, `status` = ?, `created_at` = NOW() WHERE `order_id` = ?";
$con->prepare($updateSql)->execute([$driverId, $status, $rideId]);
} else {
// If not, insert new record
$insertSql = "INSERT INTO `driver_orders` (`driver_id`, `order_id`, `created_at`, `status`) VALUES (?, ?, NOW(), ?)";
$con->prepare($insertSql)->execute([$driverId, $rideId, $status]);
}
// =================================================================
// 6. 👤 GET DRIVER INFO (For the Passenger)
// We need to fetch driver details (Car, Name, Rating) to show to the passenger.
// =================================================================
$driverInfo = [];
$sqlDetails = "SELECT
d.id as driver_id,
d.first_name,
d.last_name,
d.gender,
d.phone,
c.make,
c.model,
c.car_plate,
c.year,
c.color,
c.color_hex,
(SELECT ROUND(AVG(rating), 2) FROM ratingDriver WHERE driver_id = d.id) AS ratingDriver,
dt.token
FROM driver d
LEFT JOIN CarRegistration c ON c.driverID = d.id
LEFT JOIN driverToken dt ON dt.captain_id = d.id
WHERE d.id = ?";
$stmtDetails = $con->prepare($sqlDetails);
$stmtDetails->execute([$driverId]);
$driverRawData = $stmtDetails->fetch(PDO::FETCH_ASSOC);
if ($driverRawData) {
// List of encrypted fields that need decryption
$fieldsToDecrypt = ['first_name', 'last_name', 'gender', 'phone', 'car_plate', 'token'];
foreach ($driverRawData as $key => $value) {
if (in_array($key, $fieldsToDecrypt) && !empty($value)) {
// Decrypt sensitive data
$driverInfo[$key] = $encryptionHelper->decryptData($value);
} else {
$driverInfo[$key] = $value;
}
}
// Format Full Name
$driverInfo['driverName'] = trim(($driverInfo['first_name'] ?? '') . ' ' . ($driverInfo['last_name'] ?? ''));
// Default rating if null
if (empty($driverInfo['ratingDriver'])) {
$driverInfo['ratingDriver'] = "5.0";
}
}
// =================================================================
// 7. 🔔 NOTIFY PASSENGER (Socket + FCM)
// Inform the passenger that a driver has been found.
// =================================================================
// Fetch Passenger ID based on Ride ID
$stmtPas = $con->prepare("SELECT passenger_id FROM ride WHERE id = ?");
$stmtPas->execute([$rideId]);
$passenger_id = $stmtPas->fetchColumn();
if ($passenger_id) {
// A. Send Socket Notification (Real-time update on map)
if (function_exists('notifyPassengerOnRideServer')) {
notifyPassengerOnRideServer($passenger_id, [
'status' => 'accepted',
'ride_id' => $rideId,
'driver_id' => $driverId,
'driver_info' => $driverInfo
]);
}
// B. Send FCM Notification (Push Notification)
if (!empty($passengerToken)) {
// Using the standardized FCM function
sendFCM_Internal(
$passengerToken,
"Ride Accepted 🚖", // Title
"Captain " . ($driverInfo['driverName'] ?? 'Driver') . " is coming to you.", // Body
['ride_id' => (string)$rideId, 'driver_info' => $driverInfo], // Data Payload
"Accepted Ride", // Category
false // Not a topic
);
}
}
// =================================================================
// 8. 🧹 MARKETPLACE CLEANUP (Notify Location Server)
// Crucial Step: We tell the Location Server that this ride is taken.
// The Location Server will:
// 1. Remove the ride from Redis (geo:rides:waiting).
// 2. Broadcast 'ride_taken' to other drivers to remove it from their screens.
// =================================================================
sendToLocationServer('ride_taken_event', [
'ride_id' => $rideId,
'taken_by_driver_id' => $driverId
]);
// 9. Final Response to the Driver App
echo json_encode([
"status" => "success",
"message" => "Ride Accepted",
"data" => $driverInfo
]);
} else {
// Failure: This means rowCount was 0.
// Reason: The ride status was NOT 'waiting' (another driver took it milliseconds ago).
error_log("⛔ [ACCEPT_RIDE_FAIL] Row count 0 for RideID: '$rideId'. Status wasn't 'waiting'/'wait' or ID is wrong.");
jsonError("Ride not available (Already taken)");
}
} catch (Exception $e) {
// Handle unexpected errors
error_log("⛔ [ACCEPT_RIDE_EXCEPTION] " . $e->getMessage());
jsonError("Error: " . $e->getMessage());
}
?>