Message
Message represents an individual chat item inside a conversation.
Wirechat now treats participant_id as the source of truth for ownership and sender identity, so this model should stay aligned with the participant layer.
Core fields:
| Field | Purpose |
|---|---|
conversation_id |
Parent conversation id. |
participant_id |
Sender participant id. |
reply_id |
Parent message reference for threaded replies. |
body |
Message text or link content. |
type |
Message type enum such as text, link, or attachment. |
kept_at |
Timestamp used to preserve a disappearing message. |
deleted_at |
Soft-delete timestamp for delete-for-everyone flows. |
Wirechat will automatically keep the type aligned with the message body.
If the body contains a recognized URL, the message is marked as link. If the body no longer contains a URL,
the type falls back to text. Attachment messages remain attachment regardless of body changes.
Important Relationships
conversation()
Returns the parent conversation.
$message->conversation
participant()
Returns the sender participant row.
$message->participant
attachment()
Returns the attachment model when the message is an attachment message.
$message->attachment
parent()
Returns the message this message replies to.
$message->parent
reply()
Returns a reply to this message when one exists.
$message->reply
actions()
Returns actions recorded against the message, including delete-for-user actions.
$message->actions()->latest()->get()
Important Accessors And Helpers
user
Returns the underlying app model behind the sender participant.
$sender = $message->user
sendable
Legacy accessor alias for $message->user. New code should prefer $message->user.
$message->sendable
sendable_id
Legacy accessor for the underlying participantable id. New code should usually work through $message->participant or $message->user instead.
$message->sendable_id
sendable_type
Legacy accessor for the underlying participantable morph type. New code should usually work through $message->participant or $message->user instead.
$message->sendable_type
resolved_link
Normalizes the message body into a full URL when it is a standalone link. Returns null for mixed-content messages.
$url = $message->resolved_link
hasAttachment()
Checks whether the message currently has an attachment record.
$message->hasAttachment()
isAttachment()
Checks whether the message type is attachment.
$message->isAttachment()
isLink()
Checks whether the message type is link. This is set automatically when the message body contains a URL.
$message->isLink()
readBy()
Checks whether the message is effectively read for a participant or app model.
$message->readBy(auth()->user())
ownedBy()
Checks whether the given user owns the message by comparing against the sender participant.
$message->ownedBy(auth()->user())
belongsToAuth()
Checks whether the currently authenticated user owns the message.
$message->belongsToAuth()
hasReply()
Checks whether this message already has a reply.
$message->hasReply()
hasParent()
Checks whether this message is itself a reply to another message.
$message->hasParent()
deleteFor()
Deletes the message only for one participant and may fully delete it once package rules are satisfied.
$message->deleteFor(auth()->user())
deleteForEveryone()
Deletes the message globally when the actor owns it or when a group admin is allowed to do it.
$message->deleteForEveryone(auth()->user())
isEmoji()
Checks whether the message body contains only emoji characters.
$message->isEmoji()
Important Query Helpers
whereIsNotOwnedBy()
Filters out messages owned by the given participantable model.
$conversation->messages()->whereIsNotOwnedBy(auth()->user())->get()