Corepine logo Corepine Wirechat
Login
Wirechat v0.6x latest

Conversation

Conversation is the top-level thread model. Every private chat, self chat, and group chat starts here.

This record coordinates participants, messages, disappearing-message state, and conversation-level visibility rules.

Core fields:

Field Purpose
id Primary key for the thread.
type Conversation type enum: private, self, or group.
disappearing_started_at When disappearing mode was enabled.
disappearing_duration Disappearing duration in seconds.
meta Nullable JSON metadata for low-risk app-specific or provider-specific data.
created_at Thread creation timestamp.
updated_at Latest activity timestamp used by unread and delete or clear logic.

Important Relationships

participants()

Returns the membership rows for everyone in the conversation.

$conversation->participants()->with('participantable')->get()

messages()

Returns the messages that belong to the conversation.

$conversation->messages()->latest()->get()

lastMessage()

Returns the latest message for previews and list ordering.

$conversation->lastMessage

group()

Returns the group metadata row when the conversation is a group thread.

$conversation->group

attachments()

Builds an attachment query for all message attachments in the conversation.

$conversation->attachments()->latest()->get()

actions()

Returns actions recorded directly against the conversation model.

$conversation->actions()->latest()->get()

Important Helpers

participant()

Resolves the participant row for a given app model.

$conversation->participant(auth()->user())

addParticipant()

Adds a participant while enforcing private, self, and admin-removal rules.

$conversation->addParticipant($user)

peerParticipant()

Resolves the other participant in a private conversation.

$conversation->peerParticipant(auth()->user())

peerParticipants()

Returns every participant except the given reference model.

$conversation->peerParticipants(auth()->user())

getReceiver()

Resolves the other side of a private conversation for UI usage. This helper depends on an authenticated user being available internally, so it is best used inside auth-aware UI flows. When you already have the current user model, prefer peerParticipant() because it accepts the current user explicitly.

$peerParticipant = $conversation->peerParticipant(auth()->user())

markAsRead()

Updates conversation_read_at for the given user or the authenticated user.

$conversation->markAsRead()

readBy()

Checks whether the conversation is fully read for a participant.

$conversation->readBy(auth()->user())

getUnreadCountFor()

Counts unread messages for a given participantable model.

$conversation->getUnreadCountFor(auth()->user())

hasDisappearingTurnedOn()

Returns true when disappearing mode is active.

$conversation->hasDisappearingTurnedOn()

turnOnDisappearing()

Enables disappearing messages and currently requires at least one hour.

$conversation->turnOnDisappearing(86400)

turnOffDisappearing()

Disables disappearing messages.

$conversation->turnOffDisappearing()

deleteFor()

Deletes the conversation for one participant and may fully delete the record when package rules allow.

$conversation->deleteFor(auth()->user())

hasBeenDeletedBy()

Checks whether delete-for-user is still active for a participant.

$conversation->hasBeenDeletedBy(auth()->user())

clearFor()

Clears conversation history for one participant without fully deleting the thread.

$conversation->clearFor(auth()->user())

isPrivate()

Returns true when the conversation is a private conversation between two different users.

$conversation->isPrivate()

isSelf()

Returns true when the conversation is a self conversation for a single user.

$conversation->isSelf()

isGroup()

Returns true when the conversation is a group conversation.

$conversation->isGroup()

isOwner()

Checks whether the given user is the owner of the conversation. In group conversations this is the group owner. In private conversations both participants are effectively owners, so this can return true for either side.

$conversation->isOwner(auth()->user())

isAdmin()

Checks whether the given user has admin-level access in the conversation. In groups this returns true for admins and for the owner, because the owner is also treated as an admin.

$conversation->isAdmin(auth()->user())

Important Query Helpers

whereParticipantable()

Filters conversations that contain a specific model as participant.

Conversation::query()->whereParticipantable(auth()->user())->get()

whereHasParticipant()

Filters conversations by raw participantable id and morph type.

Conversation::query()->whereHasParticipant($user->getKey(), $user->getMorphClass())->get()

withoutBlanks()

Hides conversations with no visible messages for the authenticated user.

Conversation::query()->withoutBlanks()->get()

withoutCleared()

Hides conversations cleared by the authenticated participant until new activity appears.

Conversation::query()->withoutCleared()->get()

withoutDeleted()

Hides conversations deleted by the authenticated participant until new activity appears.

Conversation::query()->withoutDeleted()->get()

withDeleted()

Includes conversations even if the authenticated participant has deleted them.

Conversation::query()->withDeleted()->get()

Aggregates And Eager Loading

Use Eloquent relationship counts when you need message or member totals for conversation lists:

use Wirechat\Wirechat\Models\Conversation;

$conversations = Conversation::query()
    ->withCount(['messages', 'participants'])
    ->get();

foreach ($conversations as $conversation) {
    $conversation->messages_count;
    $conversation->participants_count;
}

Use eager loading to keep custom conversation lists from running the same relationship queries repeatedly:

$conversations = $user->conversations()
    ->with(['lastMessage', 'participants.participantable'])
    ->get();

When rendering a full conversation transcript, load the message relationships you need for that view:

$conversation->load(['messages.participant.participantable', 'messages.attachment']);

Legacy helpers receiverParticipant() and authParticipant() still exist, but new code should prefer peerParticipant() and participant().

Typical safe customizations:

  • Add app-specific relations such as tickets, orders, or inbox metadata.
  • Add accessors for labels or badges.
  • Add custom scopes for conversation lists.
  • Keep participants() and messages() intact because most of Wirechat depends on them.