Editing & system messages
Messages::message() returns a handle for one message:
use RoundlyConsulting\Messages\Facades\Messages;
Messages::message($message)->edit('edited body', by: $alice);
Messages::message($message)->delete(by: $alice); // soft delete ("unsent")Only the author may edit a message — not even an owner or admin, and regardless of messages.permissions.enabled. Deleting is allowed to the author and, in a group thread with roles enforced, to owners and admins. Either way the actor must still be a participant of the thread. Leave by: out for trusted server-side calls.
Editing or deleting an already-deleted message throws a typed RoundlyConsulting\Messages\Exceptions\MessageException. Editing fires MessageEdited; deleting fires MessageDeleted.
Scoped to a thread
When the thread and the message both come from the request, go through the thread — a message from another thread throws MessageException::notInThread():
// PATCH /threads/{thread}/messages/{message} — refuses a message of another thread
Messages::thread($thread)->message($message)->edit($request->body, by: $request->user());
Messages::thread($thread)->message($message)->delete(by: $request->user());What unsending does
- The message is soft-deleted — the row stays until a force delete or prune.
- Broadcasts and MessageResource hide the body (null), and preview() returns “This message was deleted.”
- The thread’s latest-message pointer moves to the previous surviving message.
- Attachment files are kept; only a force delete or prune removes them.
System messages
Enable system messages with messages.system-messages.enabled (MESSAGES_SYSTEM_MESSAGES). They are stored as a MessageType::System message with no sender, a translation key as the body and the parameters in the meta JSON column, so they render in any locale. With the switch on, the package writes them itself:
- a participant joins — messages::messages.system.participant_joined, with the participant’s participateAs() array under meta.participant;
- a participant leaves — messages::messages.system.participant_left, same meta;
- a thread is renamed — messages::messages.system.thread_renamed, with meta.name.
Write your own with the builder. preview() translates the key with the scalar meta values as replacements:
use RoundlyConsulting\Messages\Facades\Messages;
$message = Messages::to($thread)
->asSystem('messages::messages.system.thread_renamed', ['name' => 'Launch'])
->send(); // type System, no sender, body = the translation key, params in meta
$message->preview(); // "The conversation was renamed to Launch."Translation keys
Publish the strings with the messages-translations tag to translate or reword them:
| Key | English default |
|---|---|
messages::messages.system.participant_joined | :participant joined the conversation. |
messages::messages.system.participant_left | :participant left the conversation. |
messages::messages.system.thread_renamed | The conversation was renamed to :name. |
messages::messages.preview.deleted | This message was deleted. |
messages::messages.reply.cross-thread | A reply must target a message in the same thread. |
messages::messages.participation.not-a-participant | [:participant] is not a participant of this thread. |
messages::messages.participation.ownership-by-transfer | Ownership changes hands only through transferOwnership(). |
messages::messages.participation.owner-must-transfer | The owner must transferOwnership() before leaving the thread. |
messages::messages.participation.not-the-owner | [:participant] does not own this thread, so has no ownership to transfer. |
messages::messages.participation.direct-has-no-roles | A direct thread has no roles to change. |
messages::messages.participation.participant-missing | The model behind participant [:participant] no longer exists. |
messages::messages.participation.interface-required | Missing implementation of the :interface interface for class :class. |
messages::messages.permissions.requires-role | [:actor] requires the :role role to :action. |
messages::messages.permissions.unauthorized | [:actor] is not authorized to :action. |
messages::messages.scope.message-in-another-thread | Message [:message] belongs to another thread. |
messages::messages.scope.participant-in-another-thread | Participant [:participant] belongs to another thread. |
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.