PushNotificationService.php 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php
  2. namespace App\Services;
  3. use App\Models\DeviceToken;
  4. use App\Models\PushNotificationLog;
  5. use App\Models\User;
  6. use App\Notifications\Push\BasePushNotification;
  7. use Illuminate\Support\Collection;
  8. use Kreait\Firebase\Contract\Messaging;
  9. use Kreait\Firebase\Messaging\AndroidConfig;
  10. use Kreait\Firebase\Messaging\CloudMessage;
  11. use Kreait\Firebase\Messaging\Notification;
  12. class PushNotificationService
  13. {
  14. public function __construct(private Messaging $messaging) {}
  15. /**
  16. * Envia uma push notification para todos os tokens ativos de um usuário.
  17. * Registra o envio no log e desativa tokens inválidos automaticamente.
  18. */
  19. public function sendToUser(User $user, BasePushNotification $notification): void
  20. {
  21. if (! array_key_exists('push_notifications_enabled', $user->getAttributes())) {
  22. $user = $user->fresh() ?? $user;
  23. }
  24. if (! $user->push_notifications_enabled) {
  25. return;
  26. }
  27. $tokens = DeviceToken::where('user_id', $user->id)
  28. ->where('app_type', $notification->target()->value)
  29. ->where('active', true)
  30. ->pluck('token')
  31. ->toArray();
  32. if (empty($tokens)) {
  33. return;
  34. }
  35. $message = CloudMessage::new()
  36. ->withNotification(
  37. Notification::create(
  38. $notification->title(),
  39. $notification->body()
  40. )
  41. )
  42. ->withAndroidConfig(AndroidConfig::fromArray([
  43. 'notification' => ['channel_id' => $notification->androidChannelId()],
  44. 'priority' => 'high',
  45. ]));
  46. $report = $this->messaging->sendMulticast($message, $tokens);
  47. $this->deactivateInvalidTokens($report->invalidTokens());
  48. if ($report->successes()->count() > 0) {
  49. $this->log($user, $notification);
  50. }
  51. }
  52. /**
  53. * Envia para uma coleção de usuários, respeitando cooldowns.
  54. * Usuários sem tokens ativos são ignorados silenciosamente.
  55. */
  56. public function sendToUsers(Collection $users, BasePushNotification $notification): void
  57. {
  58. foreach ($users as $user) {
  59. $this->sendToUser($user, $notification);
  60. }
  61. }
  62. //
  63. private function deactivateInvalidTokens(array $tokens): void
  64. {
  65. if (empty($tokens)) {
  66. return;
  67. }
  68. DeviceToken::whereIn('token', $tokens)->update(['active' => false]);
  69. }
  70. private function log(User $user, BasePushNotification $notification): void
  71. {
  72. PushNotificationLog::create([
  73. 'label' => $notification->label(),
  74. 'title' => $notification->title(),
  75. 'body' => $notification->body(),
  76. 'user_id' => $user->id,
  77. 'target' => $notification->target()->value,
  78. 'category' => $notification->category()->value,
  79. 'sent_at' => now(),
  80. ]);
  81. }
  82. }