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

Tomato Support Laravel Package

tomatophp/tomato-support

tomato-support adds a helpdesk and ticketing system to TomatoPHP admin panels built with Filament. Teams can manage customer tickets, replies, priorities, and statuses from one dashboard, keeping support requests organized in a single, easy-to-use place.

View on GitHub
Deep Wiki
Context7

Getting Started

Preflight before you type composer require. This package carries two conflicting identities: the description.md bills it as a generic helpers/base-classes utility for the TomatoPHP ecosystem, while the package name and the PM assessment describe an in-admin ticketing module for Filament. Resolve that ambiguity before it enters your lockfile, because it determines whether you are adding a small utility dependency or adopting a domain module with migrations.

composer show tomatophp/tomato-support --all      # versions, requires, suggests
composer show tomatophp/tomato-support --tree     # what it drags in

Confirm three things from the output: the Laravel constraint, the PHP constraint, and — critically — the Filament major version it was built against. Filament's resource/form APIs churn between majors, and a mismatch fails silently (blank tables, missing actions) rather than loudly.

Install pinned, not floated.

composer require tomatophp/tomato-support:1.0.3

The v1.0.3 changelog is a compare link with no enumerated changes, and the last release is dated 2024-05-08. A ^1.0 constraint on a package with an empty patch changelog and zero dependents means you absorb whatever lands next without a review gate. Pin it and bump deliberately.

Where to look first, in this order:

  1. vendor/tomatophp/tomato-support/src/ — a directory listing settles the helpers-vs-ticketing question in ten seconds. Look for Models/, Filament/, database/migrations/, routes/.
  2. The service provider (*ServiceProvider.php) — read register() and boot(). This tells you what is auto-discovered, what is config-driven, which panel it hooks into, and whether it registers policies or gates.
  3. config/ inside the package — the canonical list of knobs, and often the clearest documentation available.
  4. php artisan vendor:publish with no arguments — the interactive tag list reveals exactly what the package expects you to publish (config, migrations, views, translations, assets).

First publish/migrate cycle:

php artisan vendor:publish --provider="TomatoPHP\TomatoSupport\TomatoSupportServiceProvider"
php artisan migrate --pretend          # read the DDL before it touches a real DB
php artisan migrate
php artisan route:list | grep -i support

First use case to wire up: the lowest-risk, highest-value path is an intake form on your own page that creates a ticket landing in the existing admin resource. That exercises model, migration, and the Filament resource without requiring you to understand assignment, notification, or API surface yet. Internal IT/ops request queues are the ideal pilot — the audience is known, volume is low, and nobody expects omnichannel intake.

Implementation Patterns

Hide the package behind your own contract. This is the single highest-leverage decision, and it costs an hour. You are depending on a zero-star, small-maintainer package; the escape hatch must exist on day one, not on the day the maintainer goes quiet.

// app/Contracts/SupportDesk.php
interface SupportDesk
{
    public function open(array $attributes): TicketData;
    public function reply(int|string $ticketId, string $body, array $meta = []): void;
    public function transition(int|string $ticketId, string $status): void;
}

Bind an adapter in a service provider that delegates to the package model. Product code depends on SupportDesk, never on the vendor namespace. A future swap to a dedicated help desk becomes one class.

Register the panel plugin in the panel provider, not in AppServiceProvider. If the package ships a Filament plugin class, it belongs in panel():

->plugin(\TomatoPHP\TomatoSupport\Filament\TomatoSupportPlugin::make())

Keep panel wiring co-located with the panel definition so a second panel (e.g. a tenant-facing one) can opt out cleanly.

Extend via observers and events, not by editing vendor files. Notification fan-out, audit rows, and Slack pings should attach to the ticket model's lifecycle:

Ticket::observe(TicketObserver::class);

This survives upgrades. Forking the package to add a created hook does not.

For Filament surface changes, prefer subclassing a resource (class TicketResource extends \TomatoPHP\...\TicketResource) over re-declaring a competitor resource against the same model. Two resources on one model produce duplicate navigation entries and route-name collisions that are annoying to unwind. If the package exposes ->form()/->table() merge points, use those first.

Multi-tenancy needs verification, not assumption. If tickets must be per-tenant, check the migration for a tenant column and the model for a global scope. If neither exists, add your own scope in a booted() hook plus an observer that stamps tenant_id on create — do this before the first ticket exists, because backfilling tenanted rows afterward is a data migration.

Intake: own the form, delegate the write. Build the public/Bade or Livewire intake form yourself and POST through your SupportDesk interface. Do not reverse-engineer the package's admin resource to reuse its form schema; internal admin forms are usually shaped for agents (assignment, internal notes) and leak fields you must never expose to end users.

API surface, if present. The description mentions an API. If routes/api.php ships, it is almost certainly guarded by a package-specific middleware or config flag, and it will not automatically respect your Sanctum abilities. Wrap it: register your own route group with auth:sanctum and an ability check, or disable the package routes in config and proxy to the service layer.

Permissions. Check whether the package seeds permissions (spatie/laravel-permission is common in this ecosystem) and whether policies are registered. If the seeder exists but is not invoked, php artisan db:seed --class="...PermissionsSeeder" (guarded with firstOrCreate) as part of your deploy, or you will ship an admin who sees 403s on every ticket action.

Test the flow, not the package. A single feature test covering create → reply → transition is the smoke test that catches upstream breakage:

it('opens and replies to a ticket', function () {
    $desk = app(SupportDesk::class);
    $ticket = $desk->open(['subject' => 'Printer', 'body' => '...']);
    $desk->reply($ticket->id, 'On it');
    expect($desk->find($ticket->id)->replies)->toHaveCount(1);
});

Run it in CI on every composer update. That test is your early-warning system for a maintainer shipping a breaking change inside a patch release.

Gotchas and Tips

Trust the src/ listing over the description.md. The published description emphasizes generic string/array/file helpers and base classes — boilerplate text that appears across TomatoPHP packages. The name, the PM assessment, and the API mention all point at ticketing. If the installed tree contains no Models/ or migrations, you have adopted a utility library and the entire ticketing plan is void. Verify in ten seconds rather than ten days.

Empty changelog, stale release. v1.0.3 documents nothing beyond a compare link, and the last release predates today by more than a year. Before any bump, run composer diff or read https://github.com/tomatophp/tomato-support/compare/v1.0.2...v1.0.3 yourself. Semver implies no breaking change; on a small-maintainer package, "implies" is not "verified."

Migration publishing traps. Two failure modes: the package expects migrations to run from the vendor path (you should not publish them), or it expects you to publish them and you instead ran migrate twice under different filenames. Always --pretend first, and check whether published migrations collide by timestamp with your own. Never edit a published migration after it has run in production — add a new one.

Guard mismatch is the classic 302 loop. If ticket routes sit behind auth (the web guard) but your admin panel authenticates via a Filament-specific guard, you get an infinite redirect to login. Diagnose with php artisan route:list --columns=uri,middleware and compare against your panel's guard config.

Assets. Filament plugin views and CSS frequently need an explicit publish (--tag=filament-assets or php artisan filament:assets) plus a php artisan storage:link if attachments use the public disk. Missing attachments after a "successful" upload are almost always the disk config or the symlink, not the package.

Config caching. If you config:cache in deploy (you should), scan the package config for closures — closures in config files break under cache and the error message points at the cache command, not the offending file.

Do not extend by forking without tooling. If you must patch, use cweagans/composer-patches with patches stored in-repo. Manual vendor edits evaporate on the next composer install and will be rediscovered by whoever deploys next, at the worst possible time.

Debugging shortcuts. php artisan config:show tomato-support for the resolved config, php artisan about for the framework/Filament version matrix, and a DB::listen(fn ($q) => logger($q->sql)) in tinker when a Filament table returns nothing. Blank tables are usually a Filament-major mismatch or a global scope, in that order.

Plan for volume before you need it. A few hundred tickets a month is fine on a default schema. Once the table grows, ensure indexes exist on status, the assignee column, and created_at — the package likely ships none beyond the primary key, and the admin's default sort/filter set will table-scan.

Scope discipline. This foundation credibly delivers in-admin ticketing with intake, status, and assignment. It does not deliver SLA timers, escalation policies, CSAT, email piping, or deflection. Do not let a stakeholder demo turn those into implied commitments — they are a separate build-or-buy decision with its own business case.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource