PHPackages                             martinko366/laravel-db-chat - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. martinko366/laravel-db-chat

ActiveLibrary[Database &amp; ORM](/categories/database)

martinko366/laravel-db-chat
===========================

A database-driven chat package for Laravel with long-polling support

0.1.2(5mo ago)18MITPHPPHP ^8.1CI passing

Since Nov 8Pushed 5mo agoCompare

[ Source](https://github.com/Martinko366/laravel-db-chat)[ Packagist](https://packagist.org/packages/martinko366/laravel-db-chat)[ RSS](/packages/martinko366-laravel-db-chat/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (5)Versions (4)Used By (0)

Laravel DB Chat
===============

[](#laravel-db-chat)

[![Tests](https://github.com/Martinko366/laravel-db-chat/actions/workflows/tests.yml/badge.svg)](https://github.com/Martinko366/laravel-db-chat/actions/workflows/tests.yml)[![Code Style](https://github.com/Martinko366/laravel-db-chat/actions/workflows/code-style.yml/badge.svg)](https://github.com/Martinko366/laravel-db-chat/actions/workflows/code-style.yml)[![Latest Stable Version](https://camo.githubusercontent.com/ef618800c1870e5e13786f185d95f538b6ba841151669826f4d14d330eca57af/68747470733a2f2f706f7365722e707567782e6f72672f6d617274696e6b6f3336362f6c61726176656c2d64622d636861742f762f737461626c65)](https://packagist.org/packages/martinko366/laravel-db-chat)[![Total Downloads](https://camo.githubusercontent.com/1199b89b4080e33a3f1bf851ad5a3cf35f69c93b17c4d1decb1c7e30c01b5323/68747470733a2f2f706f7365722e707567782e6f72672f6d617274696e6b6f3336362f6c61726176656c2d64622d636861742f646f776e6c6f616473)](https://packagist.org/packages/martinko366/laravel-db-chat)[![License](https://camo.githubusercontent.com/4306f9e00aca731a2c63bdece7c716598964ec51460b467cdd57d66fc8a242e5/68747470733a2f2f706f7365722e707567782e6f72672f6d617274696e6b6f3336362f6c61726176656c2d64622d636861742f6c6963656e7365)](https://packagist.org/packages/martinko366/laravel-db-chat)[![PHP Version Require](https://camo.githubusercontent.com/b339cd2b63e9c56f29554cbaae32e0379f05793aab344e1358abf3af05d3f675/68747470733a2f2f706f7365722e707567782e6f72672f6d617274696e6b6f3336362f6c61726176656c2d64622d636861742f726571756972652f706870)](https://packagist.org/packages/martinko366/laravel-db-chat)

A database-driven chat package for Laravel with long-polling support. No Redis, Pusher, or external services required - everything runs on your existing database.

Features
--------

[](#features)

- ✅ **Pure Database Solution** - No external services needed
- ✅ **Direct &amp; Group Chats** - Support for 1:1 and group conversations
- ✅ **Long Polling** - Realtime-ish updates without WebSockets
- ✅ **Read Receipts** - Track who has seen which messages
- ✅ **Cursor-based Polling** - Efficient message fetching using monotonic IDs
- ✅ **Rate Limiting** - Built-in protection against abuse
- ✅ **Laravel 10, 11 &amp; 12** - Compatible with modern Laravel versions

Installation
------------

[](#installation)

Install the package via Composer:

```
composer require martinko366/laravel-db-chat
```

Publish the configuration and migrations:

```
php artisan vendor:publish --tag=dbchat-config
php artisan vendor:publish --tag=dbchat-migrations
```

Run the migrations:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

The package configuration file is located at `config/dbchat.php`. You can customize:

- Database table names
- User model
- Route prefix and middleware
- Polling timeout and intervals
- Rate limits
- Message length limits

Usage
-----

[](#usage)

### Authentication

[](#authentication)

The package uses Laravel Sanctum by default. Ensure you have authentication configured:

```
// config/dbchat.php
'route' => [
    'prefix' => 'api/dbchat',
    'middleware' => ['api', 'auth:sanctum'],
],
```

### API Endpoints

[](#api-endpoints)

All endpoints are prefixed with `/api/dbchat` by default.

#### Create a Conversation

[](#create-a-conversation)

**POST** `/api/dbchat/conversations`

```
{
  "type": "direct",
  "participants": [1, 2]
}
```

For group chats:

```
{
  "type": "group",
  "title": "Team Chat",
  "participants": [1, 2, 3, 4]
}
```

**Response:**

```
{
  "conversation": {
    "id": 1,
    "type": "direct",
    "title": null,
    "created_at": "2024-01-01T00:00:00.000000Z"
  }
}
```

#### List Conversations

[](#list-conversations)

**GET** `/api/dbchat/conversations`

Returns all conversations for the authenticated user.

#### Get Conversation Details

[](#get-conversation-details)

**GET** `/api/dbchat/conversations/{id}`

#### Send a Message

[](#send-a-message)

**POST** `/api/dbchat/conversations/{id}/messages`

```
{
  "body": "Hello, world!",
  "attachments": [
    {
      "type": "image",
      "url": "https://example.com/image.jpg"
    }
  ]
}
```

**Response:**

```
{
  "message": {
    "id": 523,
    "conversation_id": 1,
    "sender_id": 1,
    "body": "Hello, world!",
    "attachments": null,
    "created_at": "2024-01-01T00:00:00.000000Z"
  }
}
```

#### Get Messages

[](#get-messages)

**GET** `/api/dbchat/conversations/{id}/messages?before_message_id=100&limit=50`

Fetch historical messages with pagination.

#### Long Polling for New Messages

[](#long-polling-for-new-messages)

**GET** `/api/dbchat/poll?after_message_id=523`

This endpoint will wait up to 25 seconds (configurable) for new messages. Returns:

- `200` with new messages if available
- `204 No Content` if no new messages before timeout

**Response (200):**

```
{
  "last_message_id": 526,
  "messages": [
    {
      "id": 524,
      "conversation_id": 1,
      "sender_id": 2,
      "body": "Hi there!",
      "created_at": "2024-01-01T00:00:01.000000Z"
    },
    {
      "id": 525,
      "conversation_id": 1,
      "sender_id": 2,
      "body": "How are you?",
      "created_at": "2024-01-01T00:00:02.000000Z"
    }
  ]
}
```

#### Mark Message as Read

[](#mark-message-as-read)

**POST** `/api/dbchat/messages/{id}/read`

Returns `204 No Content` on success.

### Client Implementation Example

[](#client-implementation-example)

Here's a simple JavaScript client for long polling:

```
class ChatClient {
  constructor(baseUrl, token) {
    this.baseUrl = baseUrl;
    this.token = token;
    this.lastMessageId = 0;
    this.isPolling = false;
  }

  async startPolling() {
    this.isPolling = true;

    while (this.isPolling) {
      try {
        const response = await fetch(
          `${this.baseUrl}/poll?after_message_id=${this.lastMessageId}`,
          {
            headers: {
              'Authorization': `Bearer ${this.token}`,
              'Accept': 'application/json'
            }
          }
        );

        if (response.status === 200) {
          const data = await response.json();
          this.lastMessageId = data.last_message_id;
          this.handleNewMessages(data.messages);
        }
        // Status 204 means no new messages, just continue polling
      } catch (error) {
        console.error('Polling error:', error);
        await this.sleep(5000); // Wait before retrying on error
      }
    }
  }

  stopPolling() {
    this.isPolling = false;
  }

  handleNewMessages(messages) {
    messages.forEach(message => {
      console.log('New message:', message);
      // Update your UI here
    });
  }

  async sendMessage(conversationId, body) {
    const response = await fetch(
      `${this.baseUrl}/conversations/${conversationId}/messages`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        body: JSON.stringify({ body })
      }
    );

    return response.json();
  }

  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// Usage
const client = new ChatClient('https://yourapp.com/api/dbchat', 'your-token');
client.startPolling();
```

### Vue/React Component Example

[](#vuereact-component-example)

Here's a basic Vue 3 composition example:

```

import { ref, onMounted, onUnmounted } from 'vue';

const messages = ref([]);
const lastMessageId = ref(0);
let isPolling = true;

async function poll() {
  while (isPolling) {
    try {
      const response = await fetch(
        `/api/dbchat/poll?after_message_id=${lastMessageId.value}`,
        { credentials: 'include' }
      );

      if (response.status === 200) {
        const data = await response.json();
        lastMessageId.value = data.last_message_id;
        messages.value.push(...data.messages);
      }
    } catch (error) {
      console.error(error);
      await new Promise(resolve => setTimeout(resolve, 5000));
    }
  }
}

onMounted(() => {
  poll();
});

onUnmounted(() => {
  isPolling = false;
});

```

How It Works
------------

[](#how-it-works)

### The Polling Mechanism

[](#the-polling-mechanism)

1. Client keeps track of `lastMessageId` (starts at 0)
2. Client calls `/poll?after_message_id=X`
3. Server queries for messages with `id > X`
4. If messages exist, return immediately
5. If no messages, wait up to 25 seconds, checking every 500ms
6. Return `204 No Content` if timeout reached
7. Client updates `lastMessageId` and polls again

### Database Schema

[](#database-schema)

**conversations**

- id, type (direct/group), title, timestamps

**participants**

- id, conversation\_id, user\_id, joined\_at, timestamps
- Unique index on (conversation\_id, user\_id)

**messages**

- id (auto-increment), conversation\_id, sender\_id, body, attachments, timestamps
- Index on (conversation\_id, id) for efficient polling

**message\_reads**

- id, message\_id, user\_id, read\_at
- Unique index on (message\_id, user\_id)

### Performance Tips

[](#performance-tips)

1. The package uses indexed queries with monotonic IDs for efficient polling
2. Direct conversations are deduplicated automatically
3. Use the `before_message_id` parameter for pagination
4. Configure rate limits based on your needs
5. Adjust polling timeout and check interval for your use case

Environment Variables
---------------------

[](#environment-variables)

```
DBCHAT_USER_MODEL=App\Models\User
DBCHAT_POLL_TIMEOUT=25
DBCHAT_POLL_CHECK_INTERVAL=500
DBCHAT_POLL_RATE_LIMIT=120
DBCHAT_MESSAGE_MAX_LENGTH=5000
DBCHAT_MESSAGE_PAGINATION_LIMIT=50
DBCHAT_MESSAGE_RATE_LIMIT=60
```

Advanced: SSE (Server-Sent Events)
----------------------------------

[](#advanced-sse-server-sent-events)

If you prefer SSE over long polling, you can create a custom controller:

```
use Symfony\Component\HttpFoundation\StreamedResponse;

class SSEController extends Controller
{
    public function __invoke(Request $request, MessageService $messageService)
    {
        return new StreamedResponse(function () use ($request, $messageService) {
            $lastMessageId = $request->query('after_message_id', 0);
            $conversationIds = // ... get user's conversation IDs

            while (true) {
                $messages = $messageService->getNewMessages($conversationIds, $lastMessageId);

                if ($messages->isNotEmpty()) {
                    echo "data: " . json_encode([
                        'last_message_id' => $messages->last()->id,
                        'messages' => $messages,
                    ]) . "\n\n";

                    ob_flush();
                    flush();

                    $lastMessageId = $messages->last()->id;
                }

                sleep(1);
            }
        }, 200, [
            'Content-Type' => 'text/event-stream',
            'Cache-Control' => 'no-cache',
            'X-Accel-Buffering' => 'no',
        ]);
    }
}
```

Testing
-------

[](#testing)

```
composer test
```

Security
--------

[](#security)

- All routes are protected by authentication middleware
- Users can only access conversations they're participants in
- Rate limiting prevents abuse
- Input validation on all endpoints

License
-------

[](#license)

MIT License

Credits
-------

[](#credits)

Created by Martinko366

Support
-------

[](#support)

For issues and questions, please use the GitHub issue tracker.

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance72

Regular maintenance activity

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity36

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~12 days

Total

3

Last Release

161d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0a0e5f04af2b36fcc9aa33802d2f3305956bd694a6800bf754aeea38e2f7f3a2?d=identicon)[Martinko366](/maintainers/Martinko366)

---

Top Contributors

[![Martinko366](https://avatars.githubusercontent.com/u/62943193?v=4)](https://github.com/Martinko366 "Martinko366 (7 commits)")

---

Tags

laraveldatabasemessagingchatlong-polling

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/martinko366-laravel-db-chat/health.svg)

```
[![Health](https://phpackages.com/badges/martinko366-laravel-db-chat/health.svg)](https://phpackages.com/packages/martinko366-laravel-db-chat)
```

###  Alternatives

[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k7.2M71](/packages/mongodb-laravel-mongodb)[spiritix/lada-cache

A Redis based, automated and scalable database caching layer for Laravel

591444.8k2](/packages/spiritix-lada-cache)[pdphilip/elasticsearch

An Elasticsearch implementation of Laravel's Eloquent ORM

145360.2k4](/packages/pdphilip-elasticsearch)[ntanduy/cloudflare-d1-database

Easy configuration and setup for D1 Database connections in Laravel.

215.4k](/packages/ntanduy-cloudflare-d1-database)[toponepercent/baum

Baum is an implementation of the Nested Set pattern for Eloquent models.

3154.7k](/packages/toponepercent-baum)[dragon-code/laravel-data-dumper

Adding data from certain tables when executing the `php artisan schema:dump` console command

3418.6k](/packages/dragon-code-laravel-data-dumper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
