Download the PHP package syriable/laravel-messenger without Composer

On this page you can find all versions of the php package syriable/laravel-messenger. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-messenger

Laravel Messenger

Latest Version on Packagist Tests Total Downloads

A headless, backend-only one-to-one messaging domain platform for Laravel. Think Facebook Messenger / Instagram DMs / WhatsApp direct messages β€” not support tickets, channels or forums.

It is Laravel-native, event-driven, performance-oriented and extensible by composition. It ships no UI, controllers, routes, policies or assets β€” your application owns presentation and authorization; the package owns the messaging domain.

Features

Installation

Publishing the migrations is required β€” the package ships them as customisable stubs and does not run them automatically. The quickest path is the bundled installer, which publishes the stubs (and optionally the config) and can run the migration in one step:

Or do it manually β€” publish, then migrate:

Optionally publish the config file:

Need to detect a missing-migration state at boot in your host app? Call Syriable\Messenger\Commands\InstallCommand::tablesExist().

The migrations use microsecond-precision timestamps (timestamp(6)) so the clear/visibility boundary stays correct when events share a wall-clock second. If you publish a fresh copy over an older install, re-check those columns.

Setup

Add the Messageable trait and MessengerParticipant contract to any model that can take part in a conversation:

Participants are morphable, so different model types can message each other (e.g. a Buyer and a SupportAgent).

Register a morph map (recommended for production)

Participant identity is stored as the model's getMorphClass() β€” by default the fully-qualified class name (App\Models\User). If you later rename or move that class, every stored participant_type becomes stale and the participant's conversations silently disappear from their inbox. Register a morph map before you run the first migration so the database stores a stable alias instead of the raw class name:

With the map in place, participant_type stores 'user' instead of 'App\Models\User', making your data portable across class renames. If you adopt a morph map on an existing install, migrate the stored participant_type (and sender_type) values to the new aliases in the same deployment.

Usage

Sending messages

A conversation is created automatically on the first message β€” conversations are never empty.

A valid message must contain a body, at least one attachment, or both.

A reply_to reference must point to an existing message in the same conversation that is still visible to the sender (i.e. created after the sender's clear timestamp). A reply on a brand-new conversation, to a message from another conversation, or to a message the sender has cleared is rejected with InvalidReplyException. Empty (zero-byte) and over-limit attachments are rejected by the send pipeline; oversized original filenames are truncated to fit storage.

Reading the inbox & messages

Cursors are keyset (not offset) and exclude the cursor message itself, so they stay correct as new messages arrive and never re-scan skipped rows. The result is always returned in chronological order regardless of direction, and a cursor that does not belong to the conversation throws InvalidArgumentException.

Inbox N+1. inbox() is N+1-free for the package's own relations, but it does not load the polymorphic model behind each participant unless you ask it to. If you render participant names or avatars, pass ['with_participant_models' => true] so the Users are loaded in one grouped query β€” otherwise resolving otherParticipantFor($alice)->participant lazily issues one query per conversation.

Conversation state (per participant)

Reporting a message

Handling domain exceptions in the host application

The package is headless: when a messaging rule is violated it throws a typed domain exception and never converts it to an HTTP response, a ValidationException, or a flash message. Translating these into your UI/API is the host application's job. Every package exception extends a single base class, Syriable\Messenger\Exceptions\MessengerException (which extends RuntimeException), so you can catch them all in one place or handle subclasses individually.

Exception Thrown when Suggested mapping
ConversationBlockedException Sending into a conversation either side has blocked or marked as spam 403 / inline notice
InvalidMessageException The message has no body and no attachments, or the body exceeds max_body_length 422
InvalidAttachmentException An attachment is empty, too large, over the per-message count, or a disallowed type/mime 422
InvalidReplyException reply_to points outside the conversation or to a message the sender has cleared 422
InvalidParticipantException The actor is not a member of the conversation, or a participant does not exist (with the optional existence guard) 403 / 404
InvalidReportException A report's reason/note exceeds its limit, or (with the optional guard) the reporter is not a participant 422

Prefer an explicit redirect target over back(). back() relies on the Referer header; API clients, Inertia/Livewire flows that strip it, and direct POSTs fall back to /, silently dropping the error flash. Redirect to a named route (the conversation view) so the error is always rendered. The same mapping applies in API controllers (return a JSON error) and Livewire/Inertia layers.

Duplicate submissions are a host responsibility. The package has no idempotency guard by design β€” calling send() twice with the same body stores two messages. Prevent double-submits in your UI (disable the button on submit, debounce, or carry a request id you de-duplicate on) just as you would for any form POST.

Events

Every lifecycle operation dispatches an immutable, past-tense domain event you can listen to:

MessageSent, ConversationCreated, ConversationArchived / ConversationUnarchived, ConversationStarred / ConversationUnstarred, ConversationBlocked / ConversationUnblocked, ConversationMarkedAsSpam / ConversationUnmarkedAsSpam, ConversationCleared, ConversationRead, ConversationMarkedAsUnread, MessageReported.

Realtime broadcasting

Broadcasting is optional and event-driven β€” it is never coupled into the actions. It is disabled by default; turn it on by setting MESSENGER_BROADCASTING_ENABLED=true. The published configuration defaults:

When enabled, a MessageSentBroadcast is broadcast on messenger.conversation.{id} (as message.sent). Listen with Laravel Echo:

Private channels require a channel authorization callback in your host application. Without one, Echo subscriptions to private channels will fail with a 403:

If you set private => false in the config, messages broadcast on a public channel with no access control β€” anyone who knows a conversation ID can subscribe. Only use this in trusted internal environments.

The broadcast is a lightweight notification. It carries the message's core fields plus a metadata-only attachment summary β€” has_attachments and an attachments array of { id, name, mime_type, size } β€” so clients can render attachment-only or mixed messages without a follow-up request. It intentionally does not include file contents or URLs (those are disk/authorization concerns); load the message (e.g. Messenger::messages()) or override broadcastWith() if you need more.

Customizing the send pipeline

Messages pass through a composable, configurable pipeline before they are stored. Add your own moderation / filtering pipes:

A pipe implements Syriable\Messenger\Contracts\SendPipe:

The default pipes provide the package's core guarantees (valid participants, mutual block/spam, non-empty messages, attachment limits, valid replies). The pipeline is yours to customise, but removing a default pipe removes the guarantee it provides β€” e.g. dropping EnsureMessageHasContent lets empty messages persist. Add pipes freely; only remove a default one when you intend to drop its check. Note that EnsureAttachmentsAreValid validates client-reported type/size/count metadata by default. Set messenger.attachments.verify_real_mime to true to additionally check the server-detected (content-sniffed) MIME against the allow-list, catching a payload renamed to a permitted extension. For deeper guarantees (virus scanning, archive-bomb checks), add your own pipe. See docs/ARCHITECTURE.md.

Authorization

The package is not responsible for business authorization (no policies, roles or ACL). Your application decides who may message whom. The package only enforces internal messaging constraints: blocked / spam conversations, participant membership and message validity.

Reads require participation. Conversation-scoped operations enforce membership: Messenger::messages($conversation, $viewer) (and the participant-state actions archive, clear, block, markAsRead, …) throw InvalidParticipantException when the viewer is not a participant β€” they do not return an empty result. Catch it and map to 403/404. Note that Messenger::between() resolves the conversation for any caller who knows the participant pair; only the membership-scoped operations enforce the check.

Consistent with this, message reporting is participant-only by default: Messenger::report() rejects a report from an identity that is not a member of the message's conversation (InvalidReportException). Set messenger.reports.participants_only to false to restore the unrestricted headless contract and authorise reporting in your application instead.

Two security guards ship on by default (set either to false to opt out):

Security notes

Because the package is headless and host-owned, a few responsibilities sit with your application:

Pruning attachment files

Messages are immutable and the package never hard-deletes, so when you delete messages/conversations yourself the underlying attachment files stay on disk. Reclaim them with the bundled command, which removes files under the configured attachments directory that no longer have a matching database row:

Or programmatically (returns the orphaned paths):

Pruning is explicit and opt-in β€” it never runs automatically β€” so it is safe against the immutability model.

Database & concurrency

The send path is built for parallel writes: the lazy first-message race recovers by attaching to the winning conversation, block/spam is re-checked under a row lock inside the transaction, the unread counter increments atomically in SQL, and the write transaction is retried a bounded number of times on transient concurrency errors (deadlock, lock-wait timeout, SQLite database is locked). The suite runs on SQLite, MySQL 8 and PostgreSQL 16 in CI.

SQLite serialises all writers, so under heavy parallel write load it can still raise database is locked faster than the retries absorb. For production with meaningful concurrency, use MySQL or PostgreSQL. If you do run SQLite, enable WAL and a busy timeout so the driver waits for the lock instead of failing immediately:

Architecture

See docs/ARCHITECTURE.md for the full design: thin models, single-responsibility actions, read-only queries, DTOs, the send pipeline, domain events and the performance / denormalization strategy.

Testing

License

The MIT License (MIT). Please see License File for more information.


All versions of laravel-messenger with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
spatie/laravel-package-tools Version ^1.16
illuminate/contracts Version ^11.0||^12.0||^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package syriable/laravel-messenger contains the following files

Loading the files please wait ...