886 lines
26 KiB
PHP
886 lines
26 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Modules\RestaurantDelivery\Services\Firebase;
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Kreait\Firebase\Database;
|
|
use Kreait\Firebase\Exception\FirebaseException;
|
|
use Kreait\Firebase\Factory;
|
|
use Kreait\Firebase\Messaging;
|
|
use Kreait\Firebase\Messaging\CloudMessage;
|
|
use Kreait\Firebase\Messaging\Notification;
|
|
|
|
class FirebaseService
|
|
{
|
|
protected ?Database $database = null;
|
|
|
|
protected ?Messaging $messaging = null;
|
|
|
|
protected ?Factory $factory = null; // nullable
|
|
|
|
protected array $config;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->config = config('restaurant-delivery');
|
|
$this->initializeFirebase();
|
|
}
|
|
|
|
protected function initializeFirebase(): void
|
|
{
|
|
if (! $this->config['enabled']) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$this->factory = (new Factory)
|
|
->withServiceAccount($this->config['credentials_path'])
|
|
->withDatabaseUri($this->config['database_url']);
|
|
} catch (\Exception $e) {
|
|
Log::error('Firebase initialization failed', [
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
}
|
|
|
|
public function getDatabase(): ?Database
|
|
{
|
|
if (! $this->database && $this->factory) {
|
|
$this->database = $this->factory->createDatabase();
|
|
}
|
|
|
|
return $this->database;
|
|
}
|
|
|
|
public function getMessaging(): ?Messaging
|
|
{
|
|
if (! $this->messaging && $this->factory) {
|
|
$this->messaging = $this->factory->createMessaging();
|
|
}
|
|
|
|
return $this->messaging;
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Rider Location Operations
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Update rider's live location in Firebase
|
|
*/
|
|
public function updateRiderLocation(
|
|
int|string $riderId,
|
|
float $latitude,
|
|
float $longitude,
|
|
?float $speed = null,
|
|
?float $bearing = null,
|
|
?float $accuracy = null
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['riders_location']);
|
|
|
|
$locationData = [
|
|
'lat' => $latitude,
|
|
'lng' => $longitude,
|
|
'speed' => $speed ?? 0,
|
|
'bearing' => $bearing ?? 0,
|
|
'accuracy' => $accuracy ?? 0,
|
|
'timestamp' => time() * 1000, // JavaScript timestamp
|
|
'updated_at' => now()->toIso8601String(),
|
|
];
|
|
|
|
$database->getReference($path)->set($locationData);
|
|
|
|
// Cache locally for quick access
|
|
Cache::put(
|
|
"rider_location_{$riderId}",
|
|
$locationData,
|
|
config('restaurant-delivery.cache.ttl.rider_location')
|
|
);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update rider location in Firebase', [
|
|
'rider_id' => $riderId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get rider's current location from Firebase
|
|
*/
|
|
public function getRiderLocation(int|string $riderId): ?array
|
|
{
|
|
// Try cache first
|
|
$cached = Cache::get("rider_location_{$riderId}");
|
|
if ($cached) {
|
|
return $cached;
|
|
}
|
|
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return null;
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['riders_location']);
|
|
$snapshot = $database->getReference($path)->getSnapshot();
|
|
|
|
return $snapshot->exists() ? $snapshot->getValue() : null;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to get rider location from Firebase', [
|
|
'rider_id' => $riderId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if rider location is stale
|
|
*/
|
|
public function isRiderLocationStale(int|string $riderId): bool
|
|
{
|
|
$location = $this->getRiderLocation($riderId);
|
|
|
|
if (! $location || ! isset($location['timestamp'])) {
|
|
return true;
|
|
}
|
|
|
|
$lastUpdate = (int) ($location['timestamp'] / 1000); // Convert from JS timestamp
|
|
$staleThreshold = $this->config['location']['stale_threshold'];
|
|
|
|
return (time() - $lastUpdate) > $staleThreshold;
|
|
}
|
|
|
|
/**
|
|
* Check if rider is considered offline
|
|
*/
|
|
public function isRiderOffline(int|string $riderId): bool
|
|
{
|
|
$location = $this->getRiderLocation($riderId);
|
|
|
|
if (! $location || ! isset($location['timestamp'])) {
|
|
return true;
|
|
}
|
|
|
|
$lastUpdate = (int) ($location['timestamp'] / 1000);
|
|
$offlineThreshold = $this->config['location']['offline_threshold'];
|
|
|
|
return (time() - $lastUpdate) > $offlineThreshold;
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Rider Status Operations
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Update rider online/offline status
|
|
*/
|
|
public function updateRiderStatus(
|
|
int|string $riderId,
|
|
string $status,
|
|
?array $metadata = null
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['rider_status']);
|
|
|
|
$statusData = [
|
|
'status' => $status, // online, offline, busy, on_delivery
|
|
'updated_at' => now()->toIso8601String(),
|
|
'timestamp' => time() * 1000,
|
|
];
|
|
|
|
if ($metadata) {
|
|
$statusData = array_merge($statusData, $metadata);
|
|
}
|
|
|
|
$database->getReference($path)->set($statusData);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update rider status in Firebase', [
|
|
'rider_id' => $riderId,
|
|
'status' => $status,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get rider's current status
|
|
*/
|
|
public function getRiderStatus(int|string $riderId): ?array
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return null;
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['rider_status']);
|
|
$snapshot = $database->getReference($path)->getSnapshot();
|
|
|
|
return $snapshot->exists() ? $snapshot->getValue() : null;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to get rider status from Firebase', [
|
|
'rider_id' => $riderId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Delivery Tracking Operations
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Initialize delivery tracking in Firebase
|
|
*/
|
|
public function initializeDeliveryTracking(
|
|
int|string $deliveryId,
|
|
array $deliveryData
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
|
|
$trackingData = [
|
|
'delivery_id' => $deliveryId,
|
|
'status' => $deliveryData['status'] ?? 'pending',
|
|
'rider_id' => $deliveryData['rider_id'] ?? null,
|
|
'restaurant' => [
|
|
'id' => $deliveryData['restaurant_id'] ?? null,
|
|
'name' => $deliveryData['restaurant_name'] ?? null,
|
|
'lat' => $deliveryData['pickup_latitude'],
|
|
'lng' => $deliveryData['pickup_longitude'],
|
|
'address' => $deliveryData['pickup_address'] ?? null,
|
|
],
|
|
'customer' => [
|
|
'lat' => $deliveryData['drop_latitude'],
|
|
'lng' => $deliveryData['drop_longitude'],
|
|
'address' => $deliveryData['drop_address'] ?? null,
|
|
],
|
|
'rider_location' => null,
|
|
'route' => $deliveryData['route'] ?? null,
|
|
'eta' => $deliveryData['eta'] ?? null,
|
|
'distance' => $deliveryData['distance'] ?? null,
|
|
'created_at' => now()->toIso8601String(),
|
|
'updated_at' => now()->toIso8601String(),
|
|
];
|
|
|
|
$database->getReference($path)->set($trackingData);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to initialize delivery tracking in Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update delivery tracking with rider location
|
|
*/
|
|
public function updateDeliveryTracking(
|
|
int|string $deliveryId,
|
|
array $updates
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
|
|
$updates['updated_at'] = now()->toIso8601String();
|
|
|
|
$database->getReference($path)->update($updates);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update delivery tracking in Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update delivery status in Firebase
|
|
*/
|
|
public function updateDeliveryStatus(
|
|
int|string $deliveryId,
|
|
string $status,
|
|
?array $metadata = null
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$statusPath = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_status']);
|
|
$trackingPath = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
|
|
$statusConfig = config("restaurant-delivery.delivery_flow.statuses.{$status}");
|
|
|
|
$statusData = [
|
|
'status' => $status,
|
|
'label' => $statusConfig['label'] ?? $status,
|
|
'description' => $statusConfig['description'] ?? null,
|
|
'color' => $statusConfig['color'] ?? '#6B7280',
|
|
'timestamp' => time() * 1000,
|
|
'updated_at' => now()->toIso8601String(),
|
|
];
|
|
|
|
if ($metadata) {
|
|
$statusData = array_merge($statusData, $metadata);
|
|
}
|
|
|
|
// Update both status and tracking paths
|
|
$database->getReference($statusPath)->set($statusData);
|
|
$database->getReference($trackingPath.'/status')->set($status);
|
|
$database->getReference($trackingPath.'/status_data')->set($statusData);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update delivery status in Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'status' => $status,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get delivery tracking data
|
|
*/
|
|
public function getDeliveryTracking(int|string $deliveryId): ?array
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return null;
|
|
}
|
|
|
|
$path = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
$snapshot = $database->getReference($path)->getSnapshot();
|
|
|
|
return $snapshot->exists() ? $snapshot->getValue() : null;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to get delivery tracking from Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update rider location for a specific delivery
|
|
*/
|
|
public function updateDeliveryRiderLocation(
|
|
int|string $deliveryId,
|
|
float $latitude,
|
|
float $longitude,
|
|
?float $speed = null,
|
|
?float $bearing = null,
|
|
?float $eta = null,
|
|
?float $remainingDistance = null
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
|
|
$locationData = [
|
|
'rider_location' => [
|
|
'lat' => $latitude,
|
|
'lng' => $longitude,
|
|
'speed' => $speed ?? 0,
|
|
'bearing' => $bearing ?? 0,
|
|
'timestamp' => time() * 1000,
|
|
],
|
|
'eta' => $eta,
|
|
'remaining_distance' => $remainingDistance,
|
|
'updated_at' => now()->toIso8601String(),
|
|
];
|
|
|
|
$database->getReference($path)->update($locationData);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update delivery rider location in Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Store route polyline for delivery
|
|
*/
|
|
public function updateDeliveryRoute(
|
|
int|string $deliveryId,
|
|
array $route
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
|
|
$database->getReference($path.'/route')->set($route);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update delivery route in Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove delivery tracking data (cleanup after delivery)
|
|
*/
|
|
public function removeDeliveryTracking(int|string $deliveryId): bool
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$trackingPath = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_tracking']);
|
|
$statusPath = str_replace('{delivery_id}', (string) $deliveryId, $this->config['paths']['delivery_status']);
|
|
|
|
$database->getReference($trackingPath)->remove();
|
|
$database->getReference($statusPath)->remove();
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to remove delivery tracking from Firebase', [
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Rider Assignment Operations
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Add delivery to rider's assignment list
|
|
*/
|
|
public function addRiderAssignment(
|
|
int|string $riderId,
|
|
int|string $deliveryId,
|
|
array $deliveryInfo
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['rider_assignments']);
|
|
|
|
$assignmentData = [
|
|
'delivery_id' => $deliveryId,
|
|
'status' => 'assigned',
|
|
'restaurant' => $deliveryInfo['restaurant'] ?? null,
|
|
'customer_address' => $deliveryInfo['customer_address'] ?? null,
|
|
'pickup_location' => $deliveryInfo['pickup_location'] ?? null,
|
|
'drop_location' => $deliveryInfo['drop_location'] ?? null,
|
|
'assigned_at' => now()->toIso8601String(),
|
|
'timestamp' => time() * 1000,
|
|
];
|
|
|
|
$database->getReference($path.'/'.$deliveryId)->set($assignmentData);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to add rider assignment in Firebase', [
|
|
'rider_id' => $riderId,
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove delivery from rider's assignment list
|
|
*/
|
|
public function removeRiderAssignment(
|
|
int|string $riderId,
|
|
int|string $deliveryId
|
|
): bool {
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['rider_assignments']);
|
|
|
|
$database->getReference($path.'/'.$deliveryId)->remove();
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to remove rider assignment from Firebase', [
|
|
'rider_id' => $riderId,
|
|
'delivery_id' => $deliveryId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all active assignments for a rider
|
|
*/
|
|
public function getRiderAssignments(int|string $riderId): array
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return [];
|
|
}
|
|
|
|
$path = str_replace('{rider_id}', (string) $riderId, $this->config['paths']['rider_assignments']);
|
|
$snapshot = $database->getReference($path)->getSnapshot();
|
|
|
|
return $snapshot->exists() ? $snapshot->getValue() : [];
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to get rider assignments from Firebase', [
|
|
'rider_id' => $riderId,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Push Notifications
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Send push notification to a device
|
|
*/
|
|
public function sendPushNotification(
|
|
string $token,
|
|
string $title,
|
|
string $body,
|
|
?array $data = null
|
|
): bool {
|
|
try {
|
|
$messaging = $this->getMessaging();
|
|
if (! $messaging) {
|
|
return false;
|
|
}
|
|
|
|
$message = CloudMessage::withTarget('token', $token)
|
|
->withNotification(Notification::create($title, $body));
|
|
|
|
if ($data) {
|
|
$message = $message->withData($data);
|
|
}
|
|
|
|
$messaging->send($message);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to send push notification', [
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send push notification to multiple devices
|
|
*/
|
|
public function sendMulticastNotification(
|
|
array $tokens,
|
|
string $title,
|
|
string $body,
|
|
?array $data = null
|
|
): array {
|
|
try {
|
|
$messaging = $this->getMessaging();
|
|
if (! $messaging) {
|
|
return ['success' => 0, 'failure' => count($tokens)];
|
|
}
|
|
|
|
$message = CloudMessage::new()
|
|
->withNotification(Notification::create($title, $body));
|
|
|
|
if ($data) {
|
|
$message = $message->withData($data);
|
|
}
|
|
|
|
$report = $messaging->sendMulticast($message, $tokens);
|
|
|
|
return [
|
|
'success' => $report->successes()->count(),
|
|
'failure' => $report->failures()->count(),
|
|
'invalid_tokens' => $report->invalidTokens(),
|
|
];
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to send multicast notification', [
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return ['success' => 0, 'failure' => count($tokens)];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send notification to a topic
|
|
*/
|
|
public function sendTopicNotification(
|
|
string $topic,
|
|
string $title,
|
|
string $body,
|
|
?array $data = null
|
|
): bool {
|
|
try {
|
|
$messaging = $this->getMessaging();
|
|
if (! $messaging) {
|
|
return false;
|
|
}
|
|
|
|
$message = CloudMessage::withTarget('topic', $topic)
|
|
->withNotification(Notification::create($title, $body));
|
|
|
|
if ($data) {
|
|
$message = $message->withData($data);
|
|
}
|
|
|
|
$messaging->send($message);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to send topic notification', [
|
|
'topic' => $topic,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Subscribe device to a topic
|
|
*/
|
|
public function subscribeToTopic(string $token, string $topic): bool
|
|
{
|
|
try {
|
|
$messaging = $this->getMessaging();
|
|
if (! $messaging) {
|
|
return false;
|
|
}
|
|
|
|
$messaging->subscribeToTopic($topic, [$token]);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to subscribe to topic', [
|
|
'topic' => $topic,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unsubscribe device from a topic
|
|
*/
|
|
public function unsubscribeFromTopic(string $token, string $topic): bool
|
|
{
|
|
try {
|
|
$messaging = $this->getMessaging();
|
|
if (! $messaging) {
|
|
return false;
|
|
}
|
|
|
|
$messaging->unsubscribeFromTopic($topic, [$token]);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to unsubscribe from topic', [
|
|
'topic' => $topic,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Utility Methods
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Set a value at a custom path
|
|
*/
|
|
public function set(string $path, mixed $value): bool
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$database->getReference($path)->set($value);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to set value in Firebase', [
|
|
'path' => $path,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update values at a custom path
|
|
*/
|
|
public function update(string $path, array $values): bool
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$database->getReference($path)->update($values);
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to update value in Firebase', [
|
|
'path' => $path,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get value from a custom path
|
|
*/
|
|
public function get(string $path): mixed
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return null;
|
|
}
|
|
|
|
$snapshot = $database->getReference($path)->getSnapshot();
|
|
|
|
return $snapshot->exists() ? $snapshot->getValue() : null;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to get value from Firebase', [
|
|
'path' => $path,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete value at a custom path
|
|
*/
|
|
public function delete(string $path): bool
|
|
{
|
|
try {
|
|
$database = $this->getDatabase();
|
|
if (! $database) {
|
|
return false;
|
|
}
|
|
|
|
$database->getReference($path)->remove();
|
|
|
|
return true;
|
|
} catch (FirebaseException $e) {
|
|
Log::error('Failed to delete value from Firebase', [
|
|
'path' => $path,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|