flodaq/ticket-notification-bundle
A Laravel/PHP bundle for ticket notification workflows, helping you send and manage alerts for support tickets with simple configuration and integration into existing applications.
First, the orientation check: this is a Symfony bundle, not a Laravel package. It listens to HackzillaTicketBundle events and sends mail when a ticket is created or changed. There is no service provider, no facade, no config/ticket-notification.php, and composer require in a Laravel app will get you a package that does nothing. Two honest paths:
Event/Listener + Notification classes. That's almost certainly the right call given 1 star and 0 dependents.If you're on Symfony:
composer require hackzilla/ticket-bundle flodaq/ticket-notification-bundle
Register the bundle in config/bundles.php, then look at these three files before touching config — they define the entire public surface:
DependencyInjection/Configuration.php — the actual config keys (don't trust blog posts, including this one; keys drift between versions)Resources/config/services.* — whether the subscriber is registered conditionally on the mailer serviceEventListener/ or EventSubscriber/ — which ticket events are hooked and who the recipients resolve toFirst use case: stand up Mailpit/Mailhog, create a ticket through the UI, and confirm a message arrives. That single loop validates mailer wiring, the event hook, the recipient config, and the template in one shot. If no mail arrives, bin/console debug:event-dispatcher will tell you whether the subscriber is even registered.
Recipient and template configuration (Symfony). The bundle's job is thin: from-address, recipients, and an email body template. Configuration typically looks like:
# config/packages/flodaq_ticket_notification.yaml
flodaq_ticket_notification:
from: "%env(MAIL_FROM)%"
recipients: ["%env(TICKET_NOTIFY_TO)%"]
Override the email template rather than editing vendor code — Symfony's bundle template override convention (templates/bundles/<BundleName>/...) works if the bundle exposes its views under Resources/views. Copy the original, change it, keep it in your app.
Decorating instead of forking. If you need to change recipients per queue, add a header, or skip notifications for a status, decorate the notifier/subscriber service in services.yaml:
App\Ticket\FilteringNotifier:
decorates: 'flodaq_ticket_notification.notifier' # verify the real service id
arguments: ['@.inner']
Then in the decorator, decide whether to delegate and otherwise return early. This survives composer update; editing the vendor subscriber does not.
Suppressing noise. "Modified" fires on every comment, status change, and assignment. In practice you want a per-ticket throttle or a status allowlist. A second subscriber with higher priority (getSubscribedEvents() with a larger priority number) can call $event->stopPropagation() for the cases you don't want emailed. Cheap, no fork required.
The Laravel port. If you're on Laravel and already have a ticket model, this is the pattern the bundle is describing, expressed idiomatically:
// app/Events/TicketChanged.php
class TicketChanged
{
public function __construct(
public Ticket $ticket,
public string $change, // 'created' | 'updated'
) {}
}
// app/Listeners/NotifyTicketWatchers.php
class NotifyTicketWatchers implements ShouldQueue
{
public function handle(TicketChanged $event): void
{
Notification::route('mail', config('tickets.notify_to'))
->notify(new TicketChangedNotification($event->ticket, $event->change));
}
}
// app/Notifications/TicketChangedNotification.php
class TicketChangedNotification extends Notification
{
public function __construct(private Ticket $ticket, private string $change) {}
public function via(object $notifiable): array { return ['mail']; }
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject("[#{$this->ticket->id}] Ticket {$this->change}")
->markdown('mail.ticket-changed', ['ticket' => $this->ticket]);
}
}
Fire TicketChanged from a model observer or from the service layer after persisting. ShouldQueue gives you the async behaviour you'd otherwise have to bolt on in Symfony with Messenger.
If you're on Symfony and want async: route the mail through Messenger (framework.messenger + a mailer transport configured as messenger) rather than modifying the bundle. The subscriber dispatches synchronously by default, which is exactly the thing that bites on a busy helpdesk.
ServiceProvider. Any tutorial implying otherwise is wrong. Plan to port, not install.composer.json and the notifier's constructor type-hints first; this is the single make-or-break compatibility question.composer.json to pin an old major. Loosening constraints locally is usually fine for a bundle this small; sending a PR is the polite version.debug:event-dispatcher (is the subscriber registered?) → debug:container <service_id> (did decoration take effect?) → Mailer profiler panel in the web debug toolbar (was a message created?) → the transport itself (did it leave?). Skipping to step 4 wastes the most time.KernelTestCase with the profiler's MessageEvents/mailer assertions to assert an email was sent on ticket creation. This is the fastest regression net for any template override you make.vendor/.How can I help you explore Laravel packages today?