# Laravel Integration Guide

Vask is fully compatible with Laravel Broadcasting and Laravel Echo.

## Installation

We recommend following [Laravel's broadcasting documentation](https://laravel.com/docs/broadcasting#pusher-channels) to get setup.

Then you only need to set the environment variables to your vask app details.

## Configuration

### Environment Variables

Add your Vask credentials to your `.env` file:

```env
BROADCAST_CONNECTION=pusher

PUSHER_APP_ID=your_app_id
PUSHER_APP_KEY=your_app_id
PUSHER_APP_SECRET=your_app_secret
PUSHER_HOST=wss.vask.dev
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
```

## Broadcasting Events

### Creating a Broadcast Event

Create an event that implements `ShouldBroadcast`:

```php
<?php

namespace App\Events;

use App\Models\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public Message $message,
        public string $userName
    ) {}

    public function broadcastOn(): Channel
    {
        return new Channel('chat.' . $this->message->room_id);
    }

    public function broadcastAs(): string
    {
        return 'message.sent';
    }

    public function broadcastWith(): array
    {
        return [
            'id' => $this->message->id,
            'content' => $this->message->content,
            'user' => $this->userName,
            'created_at' => $this->message->created_at->toISOString(),
        ];
    }
}
```

### Triggering Events

Broadcast events from your controllers or anywhere in your application:

```php
use App\Events\MessageSent;

// In a controller method
public function sendMessage(Request $request)
{
    $message = Message::create([
        'room_id' => $request->room_id,
        'user_id' => auth()->id(),
        'content' => $request->content,
    ]);

    // Broadcast the event
    broadcast(new MessageSent(
        $message,
        auth()->user()->name
    ));

    return response()->json($message);
}

// Or use the event() helper
event(new MessageSent($message, $userName));

// For immediate broadcasting (bypass queue)
broadcast(new MessageSent($message, $userName))->toOthers();
```

## Client-Side Setup

### Configure Laravel Echo

Initialize Echo in your `bootstrap.js` or `app.{js,ts,tsx}` file:

```javascript
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
    wsHost: import.meta.env.VITE_PUSHER_HOST,
    wsPort: import.meta.env.VITE_PUSHER_PORT,
    wssPort: import.meta.env.VITE_PUSHER_PORT,
    forceTLS: true,
    encrypted: true,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});
```

### Listening to Events

Subscribe to channels and listen for events in your components:

```javascript
// Listen to a public channel
Echo.channel('chat.1').listen('.message.sent', (event) => {
    console.log('New message:', event);
    // Update your UI with the new message
    addMessageToChat(event);
});

// Listen to multiple events
Echo.channel('notifications')
    .listen('.user.joined', (e) => {
        console.log(e.userName + ' joined');
    })
    .listen('.user.left', (e) => {
        console.log(e.userName + ' left');
    });

// Leave a channel
Echo.leave('chat.1');
```

## Private Channels

### Authorization Routes

Define channel authorization logic in `routes/channels.php`:

```php
<?php

use App\Models\User;
use App\Models\Room;
use Illuminate\Support\Facades\Broadcast;

// Private channel authorization
Broadcast::channel('room.{roomId}', function (User $user, int $roomId) {
    // Return true if user can access this room
    return $user->rooms()->where('room_id', $roomId)->exists();
});

// Return data with authorization
Broadcast::channel('user.{userId}', function (User $user, int $userId) {
    if ($user->id === $userId) {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'avatar' => $user->avatar_url,
        ];
    }
    return false;
});
```

### Broadcasting to Private Channels

```php
use Illuminate\Broadcasting\PrivateChannel;

class OrderStatusUpdated implements ShouldBroadcast
{
    public function broadcastOn(): Channel
    {
        return new PrivateChannel('user.' . $this->order->user_id);
    }
}
```

### Listening to Private Channels

```javascript
// Subscribe to a private channel
Echo.private('user.' + userId)
    .listen('.order.updated', (event) => {
        console.log('Order updated:', event.order);
    })
    .listen('.payment.received', (event) => {
        showNotification('Payment received: $' + event.amount);
    });
```

## Presence Channels

Presence channels let you track who's online in real-time.

### Authorization with User Data

```php
Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
    if ($user->canJoinRoom($roomId)) {
        return [
            'id' => $user->id,
            'name' => $user->name,
            'avatar' => $user->avatar_url,
        ];
    }
});
```

### Using Presence Channels

```php
use Illuminate\Broadcasting\PresenceChannel;

class UserJoinedRoom implements ShouldBroadcast
{
    public function broadcastOn(): Channel
    {
        return new PresenceChannel('room.' . $this->roomId);
    }
}
```

### Client-Side Presence

```javascript
let onlineUsers = [];

Echo.join('room.' + roomId)
    .here((users) => {
        // Initial users in the channel
        console.log('Users online:', users);
        onlineUsers = users;
        updateUsersList(users);
    })
    .joining((user) => {
        // User joined the channel
        console.log(user.name + ' joined');
        onlineUsers.push(user);
        addUserToList(user);
    })
    .leaving((user) => {
        // User left the channel
        console.log(user.name + ' left');
        onlineUsers = onlineUsers.filter((u) => u.id !== user.id);
        removeUserFromList(user);
    })
    .error((error) => {
        console.error('Connection error:', error);
    })
    .listen('.message.sent', (event) => {
        // Listen to events on presence channel
        addMessageToChat(event);
    });
```

## Troubleshooting

### Connection Issues

**Problem:** "Failed to connect to Pusher".

**Solution:** Check your `.env` credentials and ensure `PUSHER_HOST` is set to `wss.vask.dev`.

### Events Not Broadcasting

**Problem:** Events are not being received by clients.

**Solutions:**

- Ensure your queue worker is running: `php artisan queue:work`.
- Check that `BROADCAST_CONNECTION=pusher` in `.env`.
- Verify the event implements `ShouldBroadcast`.
- Check Laravel logs for broadcasting errors.

### Private Channel Authorization Failing

**Problem:** 403 Forbidden when joining private channels.

**Solutions:**

- Verify authorization logic in `routes/channels.php`.
- Ensure user is authenticated before subscribing.
- Check that channel names match between backend and frontend.
- Verify CSRF token is being sent with authorization requests.

### Debug Mode

Enable Pusher debug mode to see detailed logs:

```javascript
window.Echo = new Echo({
    // ... other config
    enabledTransports: ['ws', 'wss'],
    // Enable debug mode
    enableLogging: true,
});

// Also enable Pusher logging
Pusher.logToConsole = true;
```

## Next Steps

- [Laravel Broadcasting Docs](https://laravel.com/docs/broadcasting)
- [Laravel Echo on GitHub](https://github.com/laravel/echo)
