# How to Send Notifications on Events

This guide explains how to send push notifications in your Laravel application based on specific events, leveraging your existing `NotificationService` and `SendPushNotification` setup.

### Key Components

You'll primarily interact with:

1.  **[`App\Services\NotificationService`](app/Services/NotificationService.php):** Your central point for creating and sending both database and push notifications.
2.  **`App\Notifications\SendPushNotification`:** The specific notification class that defines the structure and content of your push messages.

---

### Scenario 1: Sending a Notification Directly (e.g., from a Controller or Service)

For immediate notification triggers within a controller, another service, or a job, you can directly call the `NotificationService`.

**Example: Sending a User-Specific Notification**

Let's say you have a new event, like a "Task Assigned" event, and you want to notify the user who was assigned the task.

```php
// In a Controller, Service, or Job
use App\Services\NotificationService;
use App\Models\User; // Assuming you have the User model
use App\Models\Task; // Assuming you have a Task model

// ... where your event occurs

$assignedUser = User::find($userId); // Get the user who was assigned the task
$assignerUser = User::find($assignerId); // Get the user who assigned the task
$task = Task::find($taskId); // Get the task object

if ($assignedUser && $assignerUser && $task) {
    NotificationService::create(
        $assignedUser, // The user receiving the notification
        'New Task Assigned!', // Title
        $assignerUser->name . ' has assigned you a new task: ' . $task->title, // Body
        'Task Management', // Category
        'task_assigned' // Type (a unique identifier for this notification type)
    );
}
```

**Explanation:**

*   You call [`NotificationService::create()`](app/Services/NotificationService.php:23) with the recipient [`User`](app/Models/User.php), `title`, `body`, `category`, and `type`.
*   The `NotificationService` handles:
    *   Creating a record in your `notifications` table.
    *   Attaching the `notification` to the `user` in the `notification_user` pivot table.
    *   Calling [`NotificationService::sendPushNotifications()`](app/Services/NotificationService.php:51) which then dispatches the actual push message to the user's device via FCM.

**Example: Sending a Broadcast Notification (if not from `NotificationController::store`)**

If you have an event that should trigger a broadcast notification (to all users with push tokens) and it's not going through the `NotificationController::store` method:

```php
// In a Service or Job
use App\Services\NotificationService;
use App\Models\Notification;

// ... where your event occurs

$broadcastNotification = Notification::create([
    'title'    => 'Important Announcement!',
    'body'     => 'All systems are updated. Please restart your app.',
    'category' => 'System Update',
    'type'     => 'broadcast',
]);

// Since it's a broadcast, we don't attach it to a specific user here
// The sendPushNotifications method will find all users with push tokens.
NotificationService::sendPushNotifications($broadcastNotification);
```

---

### Scenario 2: Using Laravel Events and Listeners (Recommended for Decoupling)

For a more robust and decoupled approach, especially when events happen deep within your application logic, Laravel's Event system is ideal.

**Steps:**

1.  **Define an Event:** Create a new event class (e.g., `app/Events/TaskAssigned.php`).

    ```php
    // app/Events/TaskAssigned.php
    <?php

    namespace App\Events;

    use App\Models\User;
    use App\Models\Task; // Assuming you have a Task model
    use Illuminate\Broadcasting\InteractsWithSockets;
    use Illuminate\Foundation\Events\Dispatchable;
    use Illuminate\Queue\SerializesModels;

    class TaskAssigned
    {
        use Dispatchable, InteractsWithSockets, SerializesModels;

        public $assignedUser;
        public $assignerUser;
        public $task;

        public function __construct(User $assignedUser, User $assignerUser, Task $task)
        {
            $this->assignedUser = $assignedUser;
            $this->assignerUser = $assignerUser;
            $this->task = $task;
        }
    }
    ```

2.  **Dispatch the Event:** Whenever the "Task Assigned" action occurs, dispatch this event.

    ```php
    // In your TaskService or TaskController
    use App\Events\TaskAssigned;
    use App\Models\User;
    use App\Models\Task;

    // ... inside a method where a task is assigned
    $assignedUser = User::find($userId);
    $assignerUser = auth()->user(); // Assuming authenticated user is the assigner
    $task = Task::find($taskId);

    if ($assignedUser && $assignerUser && $task) {
        event(new TaskAssigned($assignedUser, $assignerUser, $task));
    }
    ```

3.  **Create a Listener:** Create a listener that reacts to the `TaskAssigned` event and sends the notification.

    ```bash
    php artisan make:listener SendTaskAssignedNotification --event=TaskAssigned
    ```

    ```php
    // app/Listeners/SendTaskAssignedNotification.php
    <?php

    namespace App\Listeners;

    use App\Events\TaskAssigned;
    use App\Services\NotificationService;
    use Illuminate\Contracts\Queue\ShouldQueue; // Consider if you want to queue this listener
    use Illuminate\Queue\InteractsWithQueue;

    class SendTaskAssignedNotification // implements ShouldQueue // Uncomment to queue
    {
        // use InteractsWithQueue; // Uncomment to queue

        public function handle(TaskAssigned $event)
        {
            $assignedUser = $event->assignedUser;
            $assignerUser = $event->assignerUser;
            $task = $event->task;

            NotificationService::create(
                $assignedUser,
                'New Task Assigned!',
                $assignerUser->name . ' has assigned you a new task: ' . $task->title,
                'Task Management',
                'task_assigned'
            );
        }
    }
    ```

4.  **Register the Event and Listener:** Add your event and listener to your `app/Providers/EventServiceProvider.php`.

    ```php
    // app/Providers/EventServiceProvider.php
    protected $listen = [
        // ... other events
        \App\Events\TaskAssigned::class => [
            \App\Listeners\SendTaskAssignedNotification::class,
        ],
    ];
    ```

**Benefits of Events and Listeners:**

*   **Decoupling:** Your application logic doesn't need to know how notifications are sent; it just dispatches an event.
*   **Scalability:** You can easily add more listeners to an event (e.g., send an email, log an activity) without modifying the original event dispatcher.
*   **Maintainability:** Logic is organized and easier to understand.

---

### Customizing `App\Notifications\SendPushNotification`

If you need to send different types of data or customize the push notification payload, you'll modify [`App\Notifications\SendPushNotification`](app/Notifications/SendPushNotification.php).

Currently, it takes `title`, `body`, and `type`. You can extend this by adding an `extraData` property:

```php
// app/Notifications/SendPushNotification.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use NotificationChannels\Fcm\FcmChannel;
use NotificationChannels\Fcm\FcmMessage;
use Illuminate\Support\Facades\Log;

class SendPushNotification extends Notification
{
    use Queueable;

    public $title;
    public $body;
    public $type;
    public $extraData; // New property for additional data

    public function __construct(string $title, string $body, string $type, array $extraData = [])
    {
        $this->title = $title;
        $this->body = $body;
        $this->type = $type;
        $this->extraData = $extraData; // Assign new property
    }

    public function via($notifiable)
    {
        return [FcmChannel::class];
    }

    public function toFcm($notifiable)
    {
        Log::info('Preparing FCM message for notification:', [
            'notifiable_id' => $notifiable->id,
            'title' => $this->title,
            'body' => $this->body,
            'type' => $this->type,
            'extra_data' => $this->extraData, // Log extra data
        ]);

        return FcmMessage::create()
            ->setNotification(\NotificationChannels\Fcm\Resources\Notification::create()
                ->setTitle($this->title)
                ->setBody($this->body)
            )
            ->setData([
                'type' => $this->type,
                'title' => $this->title, // Duplicate title/body in data for some clients
                'body' => $this->body,   // Duplicate title/body in data for some clients
                ...$this->extraData, // Include extra data here
            ]);
    }

    public function toArray($notifiable)
    {
        return [
            'title' => $this->title,
            'body' => $this->body,
            'type' => $this->type,
            'extra_data' => $this->extraData,
        ];
    }
}
```

Then, when calling `NotificationService::create` or dispatching your event, you can pass this `extraData`:

```php
// Example with extraData
NotificationService::create(
    $assignedUser,
    'New Task Assigned!',
    'You have a new task.',
    'Task Management',
    'task_assigned',
    ['task_id' => $task->id, 'priority' => $task->priority] // New extraData
);
```

This `extraData` will be available in the `data` payload of the FCM message, allowing your frontend to react specifically to the `task_id` or `priority`.

By following these patterns, you can easily integrate new notification triggers into your application as new events arise.