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(): HasMany

Returns the membership rows for everyone in the conversation.

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

messages(): HasMany

Returns the messages that belong to the conversation.

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

lastMessage(): HasOne

Returns the latest message for previews and list ordering.

$conversation->lastMessage

group(): HasOne

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

$conversation->group

attachments(): Builder

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

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

actions(): MorphMany

Returns actions recorded directly against the conversation model.

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

Important Helpers

participant(Model|Authenticatable $user, bool $withoutGlobalScopes = false): ?Participant

Resolves the participant row for a given app model.

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

addParticipant(Model $user, ParticipantRole $role = ParticipantRole::PARTICIPANT, bool $undoAdminRemovalAction = false): Participant

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

$conversation->addParticipant($user)

peerParticipant(Model|Authenticatable $reference): ?Participant

Resolves the other participant in a private conversation.

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

peerParticipants(Model $reference): Collection

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(?Model $user = null): void

Updates conversation_read_at for the given user or the authenticated user.

$conversation->markAsRead()

readBy(Model|Participant $user): bool

Checks whether the conversation is fully read for a participant.

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

getUnreadCountFor(Model $model): int

Counts unread messages for a given participantable model.

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

hasDisappearingTurnedOn(): bool

Returns true when disappearing mode is active.

$conversation->hasDisappearingTurnedOn()

turnOnDisappearing(int $durationInSeconds): void

Enables disappearing messages and currently requires at least one hour.

$conversation->turnOnDisappearing(86400)

turnOffDisappearing(): void

Disables disappearing messages.

$conversation->turnOffDisappearing()

deleteFor(Model|Authenticatable $user): ?bool

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

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

hasBeenDeletedBy(Model|Authenticatable $user): bool

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

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

clearFor(Model|Authenticatable $user): void

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

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

isPrivate(): bool

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

$conversation->isPrivate()

isSelf(): bool

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

$conversation->isSelf()

isGroup(): bool

Returns true when the conversation is a group conversation.

$conversation->isGroup()

isOwner(Model|Authenticatable $model): bool

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(Model|Authenticatable $model): bool

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(Model $participantable)

Filters conversations that contain a specific model as participant.

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

whereHasParticipant($userId, $userType)

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.