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 Branches Module Laravel Package

tomatophp/tomato-branches-module

Tomato Branches is a module for the TomatoPHP ecosystem that adds branch and location management to your Laravel app, letting you organize records and users by branch, typically through a Filament admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Prerequisites, not optional. This is a TomatoPHP module, not a standalone package. You need a working TomatoPHP admin (tomatophp/tomato-admin), Filament v3, and the nwidart/laravel-modules loader. Dropping it into a bare Laravel app will install fine and then fail on missing providers. Confirm the stack before you composer require.
  • Install and prove it's live in one pass:
    composer require tomatophp/tomato-branches-module
    php artisan module:list            # module registered + enabled?
    php artisan migrate
    php artisan config:clear && php artisan cache:clear
    
    Then open the admin panel and look for the Branches screen. If it's absent, suspect enablement/publishing before you suspect code.
  • Publish before you customise, not after:
    php artisan vendor:publish --tag=tomato-branches-module-config
    php artisan vendor:publish --tag=tomato-branches-module-lang
    
    Tag names drift between modules — verify against the service provider's publishes() array rather than trusting the README.
  • Where to look first, in order: database/migrations/ (the actual ground truth of the schema — names, address fields, is_active), src/Models/ (the Branch model and its relations), src/Filament/ (resource, form and table schemas you'll copy into your own resources), config/, then routes/.
  • First use case that actually pays off: seed 2–3 branches, attach a user to one, then write a scoped Eloquent query against your own model filtered by branch_id. The module's CRUD is table stakes; the value on day one is branch as a first-class dimension on your records.

Implementation Patterns

  • Resolve "current branch" once, in one place. Bind a CurrentBranch singleton in the container and resolve it in a fixed order: session → user's default branch → first active branch. Everything else (scopes, Filament dropdowns, report filters) reads from that singleton. This is the single design decision that determines whether branch scoping stays sane or turns into session()->get('branch_id') scattered across forty files.
  • Override it explicitly for non-request contexts. Console commands, queued jobs, and scheduled reports have no session. Give the singleton a set() / runAs($branchId, fn () => ...) method so background work sets the branch deliberately instead of silently picking the first active one.
  • The BelongsToBranch trait + global scope is the workhorse. On each branch-owned model: add a branch_id column (your own migration, not theirs), apply the trait, and let the global scope filter by current branch. Add a withoutBranchScope() escape hatch for admin/global views — you will need it within a week.
  • Decide belongsTo vs belongsToMany up front. Single branch per user is belongsTo and trivially simple. Multi-branch staff needs a user_branch pivot and a branch-switcher UI, plus a rule for which branch is "current." Retrofitting this later means touching every scope and every policy.
  • If you use spatie/permission teams, branch is your natural team_id. Map them one-to-one instead of maintaining two parallel scoping mechanisms. Commit to this early — merging two permission-scoping systems after the fact is genuinely painful.
  • Filament: register explicitly when panels are split. If you're on the shipped panel the resource auto-discovers. If you run your own PanelProvider alongside the module, register the plugin/resource in the provider — don't rely on discovery across module boundaries.
  • Extend the resource by subclassing, not editing. Write your own BranchResource extends \TomatoPHP\...\BranchResource (or use the schema-modification hooks if the module exposes them) so a composer update can't revert your work. Same for the form/table schema additions.
  • Branch switcher in the topbar. The quick-switch is the feature users actually notice. Wire it to a Livewire action that writes the branch to session and calls $this->redirect(request()->header('Referer')) — full reload is fine here and avoids stale scoped data in cached Filament tables.
  • Pickers and API surfaces should query the Branch model (filtered to is_active) through a repository, not the module's routes. You stay insulated from route-name churn and get is_active filtering for free.
  • Seed your own branches. Put a BranchSeeder in your application, with 2–3 realistic records. Tests and local dev should never depend on an empty branch table or on the package's demo data.
  • Test the scope, not the CRUD. The package's CRUD is their problem; your risk is data leakage. Write feature tests asserting that user-in-branch-A cannot see branch-B records, and that a job running runAs(B) sees only B.

Gotchas and Tips

  • "Installed but invisible" is the #1 failure. Modules toggle in config/tomato.php / modules_statuses.json. After enabling, always php artisan config:clear && php artisan cache:clear — cached config is the usual culprit, and it costs people hours.
  • Filament major-version coupling. TomatoPHP v4 targets Filament v3; older 3.x module lines target Filament v2. The symptom is a blank resource page or a Class not found on a form component, with no obvious link to the version. Pin filament/filament and this module together in composer.json.
  • Global scopes bite outside HTTP. Any queued job, artisan command, or test that touches a branch-scoped model will silently get the wrong (or zero) rows. Always set the current branch explicitly, or call the scope-free method, in those contexts. Build this into your job base class.
  • Migrations are package-owned. Never edit shipped migrations. Add your own add_branch_id_to_* migrations in the app, and inspect the shipped schema with vendor:publish --tag=...-migrations (read it, then delete it) before writing yours. Watch foreign-key ordering: your branch_id FK requires the branches table to exist.
  • Published files are yours; vendor files are not. Re-publish deliberately on a minor bump and diff the config — silent new keys in config/ are a common upgrade surprise.
  • Deleting a branch is a data question, not a UI question. Decide now whether branches soft-delete and whether branch_id is nullOnDelete or cascadeOnDelete. Use is_active = false to retire a branch in practice; hard-deleting a branch with attached orders is the kind of thing you only do once.
  • v1.0.1 is a link-only patch release. No changelog body — treat it as bugfix-only. composer update within ^1.0 is safe; no data migration or republish expected. If you're on 1.0.0 there's no urgency, but the absence of release notes is itself a signal about maintenance rigor: validate in a spike, don't assume.
  • Debugging checklist, in this order: php artisan about (module + Filament versions) → php artisan module:list → the panel provider's discoverResources/plugin list → php artisan route:list | grep branch (did the routes load at all?). That sequence resolves most "it's broken" reports before you open a single PHP file.
  • Extension points to prefer: the published config, observers/model events on Branch (audit who renamed or deactivated what), and resource subclassing. Never patch vendor PHP — this ecosystem moves fast and local edits are the first casualty of the next update.
  • Adoption reality check. Zero stars, zero dependents, one release in 2024. It's a thin CRUD-plus-scope module, which is exactly why it's replaceable if it stalls — but plan for that: keep your branch logic in your trait/service layer, treat the package as the admin UI and the Branch entity, and you can fork or vendor it in an afternoon if needed.
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