Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Messenger Bundle Laravel Package

invis1ble/messenger-bundle

A PHP Messenger bundle that simplifies wiring message buses, handlers, and transports into your application. It reduces boilerplate around configuration and integration, helping you build decoupled, asynchronous workflows with sensible defaults and a cleaner setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're installing first. Despite the "messenger" name, this is not symfony/messenger. It's a Symfony bundle that wires the invis1ble/messenger abstractions into the Symfony DI container. It is a CQRS-style dispatcher — not a transport/worker — but it does ship command, query, and event buses (validated in the v6.2.0 test suite), plus async event delivery and synchronous test transports. The core library is now on the ^5.1 series and the bundle has real-kernel tests, so it is actively maintained (CI covers Symfony 6.4 / 7.4 / 8.0 / 8.1 across PHP 8.2 / 8.4 / 8.5).

Minimal setup for a Symfony app:

composer require 'invis1ble/messenger-bundle:^6.2' --with-all-dependencies
// config/bundles.php
return [
    // ...
    Invis1ble\MessengerBundle\MessengerBundle::class => ['all' => true],
];

Check the version matrix before pulling this in. Symfony ^6.4 || ^7.0 || ^8.0 is supported, but Symfony 8.0 requires PHP 8.4+ and 8.1 requires PHP 8.4.1+. On Symfony 6.4/7.x you can stay on PHP 8.2.

Then the shortest path to a first working use case:

  1. Read the public bus interfaces first. The release notes confirm the public bus interfaces and service IDs are unchanged and stable through v6.2.0, so once you've learned them you can rely on them. Look at the command, query, and event bus contracts under vendor/invis1ble/messenger/src/.
  2. Skim the bundle's DependencyInjection/ extension and Resources/config/. With a small package, the service definitions are still the real documentation, though the "unmaintained 0-star" risk is lower now that v6.2.0 has shipped with a real-kernel test suite.
  3. First use case — a command round-trip:
final class RegisterUser
{
    public function __construct(public readonly string $email) {}
}

final class RegisterUserHandler
{
    public function __invoke(RegisterUser $message): void
    {
        // ...
    }
}

Register the handler with the bundle's tag (still the one string you should not guess — see Gotchas), inject the command bus interface, and dispatch. If you also need "read" operations, use the query bus (returns a result) rather than returning data from a command handler.

If you're coming from Laravel: there is no bundle registration step and no config/bundles.php. You have two realistic options — (a) skip the bundle entirely and bind the library's interfaces in a service provider manually, or (b) pull in symfony/dependency-injection just for this, which is almost never worth it. For a Laravel app, option (a) is the sane path and the bundle becomes irrelevant. The Laravel path is not what the bundle's real-kernel tests exercise, so you're on your own there either way.

Implementation Patterns

Interface injection, not concrete bus. Always type-hint the library's bus interfaces in your controllers, console commands, and listeners. With the interface set now stable across 6.x, this is lower-risk than before and remains the single decision that keeps the rest of your code decoupled.

Separate command, query, and event concerns. The v6.2.0 test matrix explicitly covers commands, query results, and async event delivery — so use them as intended: command bus for writes (one handler), query bus for reads (returns a result), event bus for fan-out to N handlers. Don't collapse them into one bus just because it dispatches fine.

Handler registration via tags + autoconfigure. Use _instanceof so you never hand-tag:

_instanceof:
    Invis1ble\Messenger\Handler\HandlerInterface:   # confirm the exact contract name in the vendor source
        tags: ['invis1ble.messenger.handler']

The release notes call out "handler isolation" as a tested invariant, so a correctly tagged handler will not be invoked for unrelated messages — but a mis-tagged one silently won't be invoked at all. See Gotchas.

Keep messages as plain, serializable value objects. Even where the current bus is synchronous, async event delivery is now a first-class concern in the bundle's test suite. readonly properties, scalar/array constructor args, no entities, no Closure, no DateTime without a format. This is cheap insurance and it is what the package expects.

Use the async event path rather than hand-rolling it. v6.2.0's integration tests now validate async event delivery, so for fan-out to slow side-effecting listeners prefer the bundle's async route (or a Symfony Messenger bridge) over inline dispatch. If you still want a thin decorator for conditional async, the pattern is unchanged:

final class AsyncCapableBus implements Bus
{
    public function __construct(
        private Bus $inner,
        private MessageBusInterface $symfonyBus, // symfony/messenger
    ) {}

    public function dispatch(Message $message): mixed
    {
        return $message instanceof ShouldBeAsync
            ? $this->symfonyBus->dispatch($message)
            : $this->inner->dispatch($message);
    }
}

Use the synchronous test transport for tests. v6.2.0's suite explicitly covers "synchronous test transports", which is the intended seam for asserting on dispatched messages without hitting a real queue. Pair it with a hand-rolled RecordingBus (collects dispatches, returns canned query results) in tests/Support/, or wrap the real bus in a SpyBus that delegates and records. Avoid mocking the concrete bus class — still the least stable surface.

Lean on the traceable buses for debugging. The release notes call out traceable buses (validated in tests). If the Symfony Profiler panel for this bundle exists in your install, use it before reaching for var_dump in a handler; it's the fastest way to see why a message wasn't picked up.

Laravel integration sketch. Bind in a service provider:

$this->app->singleton(Bus::class, fn ($app) => new DefaultBus($app->make(HandlerResolver::class)));

Then consider a job-based async path mirroring the decorator above, using dispatch(new HandleMessageJob($message)) instead of a Symfony transport. Do not assume the bundle's async transport works in Laravel — the transports are Symfony-native.

Gotchas and Tips

The "0 stars / future release date" red flag from the earlier profile is no longer meaningful. v6.2.0 shipped against the invis1ble/messenger 5.1 library, with a real CI matrix covering 4 Symfony versions × 3 PHP versions and real-kernel tests. Treat the package as maintained; treat the docs (blog posts, Stack Overflow) as still thin, because they are.

Pin the version, but pin the current line. Use ^6.2 (or ~6.2.0 if you want stricter). The release notes explicitly state public bus interfaces and service IDs are unchanged in 6.2.0, but the 6.x line still has upgradeable surface (Symfony dependency range, PHP constraints). Read the diff before a minor bump.

Watch the PHP floor when mixing Symfony and Laravel/other packages. Symfony 8.0 requires PHP 8.4 and Symfony 8.1 requires 8.4.1. If your application pins PHP 8.2 or 8.3 — common on Laravel — stay on the Symfony 6.4/7.x track and the corresponding bundle constraint. Also update Symfony Flex's extra.symfony.require if you're upgrading Symfony alongside the bundle, or Composer will resolve to a version the bundle won't accept.

Name collision with symfony/messenger is still the #1 confusion source. Autowiring Symfony\Component\Messenger\MessageBusInterface and expecting this bundle to satisfy it will fail. Decide explicitly which one your application code depends on. With async event delivery now first-class in the bundle, this matters more — you may find yourself deliberately mixing both, in which case keep the Symfony Messenger boundary in the adapter layer only.

Handler-not-found errors are almost always DI, not code. Order to check: (1) is the tag actually applied — bin/console debug:container --tag=...; (2) did the cache clear after adding the class (bin/console cache:clear); (3) does the resolver match on the message class or the handler's parameter type — parent classes and interfaces may not match if the resolver does not walk instanceof. Handler isolation being tested does not mean your handler was discovered.

Tag name is not guessable. Copy the string verbatim from the bundle's extension class (grep -rn "addTag\|->tag(" vendor/invis1ble/messenger-bundle/). The release notes mention "autowired aliases" being tested, so alias-based resolution is reliable — but tags are still a literal string.

Extension points worth knowing. The bus interfaces are the primary seam — decorate them for logging, timing, transactions, or async handoff, and prefer composition over subclassing the bundle's concrete bus so a package update can't break your subclass.

Async event delivery changes the "everything is synchronous" model — but only if you use it. Inline dispatch still blocks the HTTP request, and an exception mid-fan-out leaves earlier event handlers committed. If you have multiple event handlers with side effects, prefer the async path or wrap the dispatch in an explicit transaction. The old advice to hold off adopting the Symfony Messenger bridge is now softer: the bundle has its own async event story, so reach for it earlier than "only when you need it".

Keep your own application-level interface as the public seam. Given the active 6.x line and stable public interfaces, the risk profile is lower, but App\Messenger\CommandBus behind an adapter still gives you a one-class swap if the package changes direction. Laravel devs in particular should assume the bundle-level integration will never get first-class testing, so the adapter is doing real work there.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin