Skip to main content

Overview

The ConversationService handles all conversation and message management operations. It creates and tracks user conversations, stores messages with metadata, and provides conversation history and statistics.

Class Structure

Namespace: App\Services Dependencies:
  • Database - Database connection for persistence

Constructor

public function __construct(Database $db)
db
Database
required
Database instance for all conversation operations

Public Methods

getOrCreateConversation

Retrieves an existing conversation or creates a new one for a phone number.
public function getOrCreateConversation(
    string $phoneNumber, 
    string $contactName = null
): array
phoneNumber
string
required
User’s WhatsApp phone number (unique identifier)
contactName
string
Display name for the contact
Returns: Array containing conversation record with fields:
  • id - Conversation ID
  • phone_number - User’s phone
  • contact_name - Contact display name
  • status - Conversation status (active, pending_human, etc.)
  • ai_enabled - Whether AI responses are enabled (1/0)
  • created_at - Creation timestamp
  • last_message_at - Last activity timestamp
Behavior:
  • If conversation exists, updates last_message_at and returns it
  • If new, creates with status active and ai_enabled = 1
$conversationService = new ConversationService($db);

$conversation = $conversationService->getOrCreateConversation(
    $messageData['from'],
    $messageData['contact_name']
);

// Returns:
// [
//   'id' => 42,
//   'phone_number' => '573001234567',
//   'contact_name' => 'Juan Pérez',
//   'status' => 'active',
//   'ai_enabled' => 1,
//   'created_at' => '2026-03-06 10:30:00',
//   'last_message_at' => '2026-03-06 10:30:00'
// ]

addMessage

Stores a new message in the conversation history.
public function addMessage(
    int $conversationId,
    string $senderType,
    string $messageText,
    string $messageId = null,
    string $contextUsed = null,
    float $confidenceScore = null,
    string $audioUrl = null,
    string $mediaType = 'text'
): int
conversationId
int
required
ID of the conversation
senderType
string
required
Either user or bot
messageText
string
required
The message content
messageId
string
WhatsApp message ID (for deduplication)
contextUsed
string
RAG context used to generate the response
confidenceScore
float
AI confidence score (0.0-1.0)
audioUrl
string
Path to audio file if message is audio
mediaType
string
default:"text"
Message type: text, audio, image, etc.
Returns: Integer ID of the inserted message
// Store user message
$messageId = $conversationService->addMessage(
    $conversation['id'],
    'user',
    $messageData['text'],
    $messageData['message_id'],
    null,
    null,
    $messageData['audio_url'] ?? null,
    $messageData['type']
);

getConversationHistory

Retrieves recent messages from a conversation.
public function getConversationHistory(
    int $conversationId, 
    int $limit = 50
): array
conversationId
int
required
ID of the conversation
limit
int
default:"50"
Maximum number of messages to retrieve
Returns: Array of message records, ordered by created_at DESC (newest first)
$history = $conversationService->getConversationHistory($conversation['id'], 20);

// Each message contains:
// [
//   'id' => 123,
//   'conversation_id' => 42,
//   'message_id' => 'wamid.ABC123...',
//   'sender_type' => 'user',
//   'message_text' => 'Hello',
//   'audio_url' => null,
//   'media_type' => 'text',
//   'context_used' => null,
//   'confidence_score' => null,
//   'created_at' => '2026-03-06 10:30:15'
// ]

getAllConversations

Retrieves all conversations with their last message.
public function getAllConversations(
    string $status = null, 
    int $limit = 100
): array
status
string
Filter by status: active, pending_human, archived, etc.
limit
int
default:"100"
Maximum conversations to retrieve
Returns: Array of conversations with last message details, ordered by last_message_at DESC
// Get all active conversations
$conversations = $conversationService->getAllConversations('active', 50);

// Get all conversations
$allConversations = $conversationService->getAllConversations();

updateConversationStatus

Changes the status of a conversation.
public function updateConversationStatus(
    int $conversationId, 
    string $status
): bool
conversationId
int
required
ID of the conversation
status
string
required
New status: active, pending_human, archived, etc.
Returns: Boolean indicating success
// When AI can't handle the conversation
if ($ragResult['confidence_score'] < 0.5) {
    $conversationService->updateConversationStatus(
        $conversation['id'],
        'pending_human'
    );
}

getConversationStats

Retrieves aggregate statistics about conversations and messages.
public function getConversationStats(): array
Returns: Array with statistics:
$stats = $conversationService->getConversationStats();

// Returns:
// [
//   'total' => 150,              // Total conversations
//   'active' => 45,              // Active conversations
//   'pending_human' => 3,        // Waiting for human agent
//   'total_messages' => 2847     // Total messages across all conversations
// ]
Use this method for dashboard statistics and monitoring conversation volume.

Database Schema

conversations Table

ColumnTypeDescription
idINTPrimary key
phone_numberVARCHARWhatsApp phone number
contact_nameVARCHARUser’s display name
statusVARCHARactive, pending_human, archived
ai_enabledTINYINTWhether AI is enabled (1/0)
created_atTIMESTAMPCreation time
last_message_atTIMESTAMPLast activity
last_bot_message_atTIMESTAMPLast bot response time

messages Table

ColumnTypeDescription
idINTPrimary key
conversation_idINTForeign key to conversations
message_idVARCHARWhatsApp message ID
sender_typeENUMuser or bot
message_textTEXTMessage content
audio_urlVARCHARAudio file path
media_typeVARCHARtext, audio, etc.
context_usedTEXTRAG context used
confidence_scoreDECIMALAI confidence (0.0-1.0)
created_atTIMESTAMPMessage time

Usage Examples

Complete Conversation Flow

$conversationService = new ConversationService($db);

// 1. Get or create conversation
$conversation = $conversationService->getOrCreateConversation(
    $messageData['from'],
    $messageData['contact_name']
);

// 2. Store user message
$conversationService->addMessage(
    $conversation['id'],
    'user',
    $messageData['text'],
    $messageData['message_id']
);

// 3. Get conversation history for context
$history = $conversationService->getConversationHistory(
    $conversation['id'],
    10
);

// 4. Generate response (using other services)
$response = $ragService->generateResponse(...);

// 5. Store bot response
$conversationService->addMessage(
    $conversation['id'],
    'bot',
    $response['text'],
    null,
    $response['context'],
    $response['confidence']
);

// 6. Update last bot message timestamp
$db->query(
    'UPDATE conversations SET last_bot_message_at = NOW() WHERE id = :id',
    [':id' => $conversation['id']]
);

Best Practices

Always use getOrCreateConversation before adding messages to ensure the conversation exists and is properly tracked.
Message deduplication: Always pass the messageId from WhatsApp when storing user messages to prevent duplicate processing.
Conversation history for AI context: Use getConversationHistory to build conversation context for AI responses. The history is returned newest-first, so reverse it if needed.

Source Code

Location: src/Services/ConversationService.php:1-124

Build docs developers (and LLMs) love