PushNotificationService.php 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  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\CloudMessage;
  10. use Kreait\Firebase\Messaging\Notification;
  11. class PushNotificationService
  12. {
  13. public function __construct(private Messaging $messaging) {}
  14. /**
  15. * Envia uma push notification para todos os tokens ativos de um usuário.
  16. * Registra o envio no log e desativa tokens inválidos automaticamente.
  17. */
  18. public function sendToUser(User $user, BasePushNotification $notification): void
  19. {
  20. $tokens = DeviceToken::where('user_id', $user->id)
  21. ->where('app_type', $notification->target()->value)
  22. ->where('active', true)
  23. ->pluck('token')
  24. ->toArray();
  25. if (empty($tokens)) {
  26. return;
  27. }
  28. $message = CloudMessage::new()->withNotification(
  29. Notification::create($notification->title(), $notification->body())
  30. );
  31. $report = $this->messaging->sendMulticast($message, $tokens);
  32. $this->deactivateInvalidTokens($report->invalidTokens());
  33. if ($report->successes()->count() > 0) {
  34. $this->log($user, $notification);
  35. }
  36. }
  37. /**
  38. * Envia para uma coleção de usuários, respeitando cooldowns.
  39. * Usuários sem tokens ativos são ignorados silenciosamente.
  40. */
  41. public function sendToUsers(Collection $users, BasePushNotification $notification): void
  42. {
  43. foreach ($users as $user) {
  44. $this->sendToUser($user, $notification);
  45. }
  46. }
  47. private function log(User $user, BasePushNotification $notification): void
  48. {
  49. PushNotificationLog::create([
  50. 'label' => $notification->label(),
  51. 'user_id' => $user->id,
  52. 'target' => $notification->target()->value,
  53. 'category' => $notification->category()->value,
  54. 'sent_at' => now(),
  55. ]);
  56. }
  57. private function deactivateInvalidTokens(array $tokens): void
  58. {
  59. if (empty($tokens)) {
  60. return;
  61. }
  62. DeviceToken::whereIn('token', $tokens)->update(['active' => false]);
  63. }
  64. }