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

Commerce Support Laravel Package

aiarmada/commerce-support

Shared foundation for AI Armada's Laravel commerce packages, offering common support utilities, helpers, and base classes that keep storefront, cart, and checkout modules consistent and easy to integrate.

View on GitHub
Deep Wiki
Context7

Getting Started

aiarmada/commerce-support is the foundation layer of the Commerce Suite monorepo — not a feature package. Day-to-day you rarely import it directly; instead every sibling package (commerce-catalog, commerce-orders, filament-*, etc.) inherits its conventions. Treat it as the source of truth for base models, config resolution, Filament navigation, and lifecycle columns.

First steps (in this exact order):

  1. Read the routing doc first. packages/commerce-support/CONTEXT.md — its Snapshot names the Composer package, search paths, and related packages; Read next points you at the canonical docs.
  2. Read the docs in order: docs/01-overview.md → 03-configuration.md → 04-usage.md → 99-troubleshooting.md. Skip 02-installation.md on first pass unless you are wiring it fresh.
  3. Install / discover. Service provider is auto-discovered. If it has a config tag:
    php artisan vendor:publish --tag=commerce-support-config
    
  4. Inspect the config file — config/commerce-support.php. It is where json_column_type and the filament.navigation.items.* override surface live.
  5. Verify it is wired before building on it:
    ./vendor/bin/pest packages/commerce-support
    

First use case — runtime Filament navigation override. This is the most visible feature the support package exposes today. Instead of editing a Resource's $navigationGroup / getNavigationGroup() default, override it from your app's config:

// config/commerce-support.php
'filament' => [
    'navigation' => [
        'items' => [
            \App\Filament\Resources\OrderResource::class => [
                'group' => 'Sales',
                'sort'  => 10,
            ],
        ],
    ],
],

The engine reads the Resource's config default first, then merges your override. No code change in the Resource required.


Implementation Patterns

Extend the base model contract, don't reinvent it

When the support package ships a base model or model concern, adopt it rather than building your own. The contract the whole suite relies on:

use Illuminate\Database\Eloquent\Concerns\HasUuids;

class Order extends Model
{
    use HasUuids;

    // Do NOT declare protected $table.
    public function getTable(): string
    {
        // Self-join safety: honour per-instance alias first.
        return $this->table ?? config('commerce-support.tables.orders', 'orders');
    }
}

Two non-negotiables baked into this pattern:

  • Never declare protected $table. getTable() must resolve from package config so tables stay prefixable and remappable.
  • Honour $this->table inside getTable() for self-referencing relations — Laravel aliases the inner table with setTable() and silently misbinds your join otherwise.

Config-driven JSON columns

Any migration that uses a JSON column must read the type from config, not hardcode json:

$table->{$this->jsonColumnType('payload')}('payload')->nullable();

This keeps SQLite/Postgres/MySQL portability in the hands of one config key (commerce-support.json_column_type). Hardcoding json will fail CI on SQLite and is a classic review rejection.

Application-level cascades in booted()

The suite forbids database FK constraints. Do integrity in the model:

protected static function booted(): void
{
    static::deleting(function (self $order) {
        $order->lines()->delete();
    });
}

The same rules apply to foreignUuid('order_id') columns — no ->constrained(), no ->cascadeOnDelete().

Lifecycle: status enum + timestampTz

  • Lifecycle column is always named status.
  • state is reserved for geographic address regions — do not overload it.
  • Terminal transitions get a dedicated timestampTz column (e.g. completed_at, cancelled_at).
  • Keep the enum, transition code, and lifecycle columns in sync in the same change.
  • Use CarbonImmutable — never mutable Carbon.
$order->update([
    'status'       => OrderStatus::Completed,
    'completed_at' => CarbonImmutable::now(),
]);

Filament navigation is config-first, never static

If you author a Resource in a filament-* package (or consume one), navigation comes from config:

public static function getNavigationGroup(): string | UnitEnum | null
{
    return config('filament-orders.navigation.group');
}

No static $navigationGroup properties. This is what makes the runtime override engine work — break it and overrides silently no-op.

Octane-safe state

Long-lived workers mean no static mutable state. Bind request-scoped or container-scoped services; never cache per-request data in a static property or singleton that outlives the request.

Prefer Actions for orchestration

Multi-step flows that touch transactions, side effects, and normalization should be Actions. Look for existing Actions in packages/*/src/Actions before creating a new one; support-layer helpers are usually already there.


Gotchas and Tips

  • The package has no README-grade docs upstream. Stars = 0, dependents = 0. Documentation lives in packages/commerce-support/docs/*.md and CONTEXT.md. Read the repo, not Packagist. Budget time for that.
  • state ≠ status. Using state for lifecycle state will collide with the geographic convention; reviewers will reject it and Filament forms that co-locate city/postcode will break.
  • getTable() without the $this->table fallback is a silent bug. It only manifests on self-referencing relations (e.g. category trees) during existence checks. PHPStan will not catch it — write a test with a nested self-relation.
  • JSON column type is not optional. If you skip json_column_type config, SQLite test runs fail with type errors on migrations. Set it in your test DB (sqlite → text) before writing the migration.
  • Navigation overrides key off FQCN. commerce-support.filament.navigation.items.{FQCN} must match ::class exactly — trait-based, proxied, or aliased class names will not merge and overrides silently apply to nothing. Verify by dumping the resolved nav in a test.
  • Do not add FK constraints to "fix" cascade drift. It is a hard rule in the monorepo (rg -n "constrained\(|cascadeOnDelete\(" packages/*/database is a CI check). Fix the model booted() instead.
  • Config keys should be minimal and live under the owning package. If you catch yourself reading config('app.…') or a global key from inside a commerce package, the key belongs in that package's config file. Run rg -n -- "config\('pkg\." packages/*/config to audit for unused keys before merging.
  • PHP 8.5 / Filament v5 are the baseline. Do not write v3/v4 idioms ($navigationGroup, old form APIs) — the v4 examples are API-compatible, but v4 static properties are not.
  • Never run Pint / PHPStan / Pest repo-wide. Scope to the package you touched: ./vendor/bin/pint packages/commerce-support/src and ./vendor/bin/pest packages/commerce-support. Repo-wide runs create noise and unrelated diffs.
  • CarbonImmutable, always. Mutable Carbon will be silently accepted at runtime but violates the suite contract and breaks the "record terminal transitions in dedicated timestampTz" pattern.
  • If a static analyzer flags a method as undefined, check runtime extension points first. macro(), hasMacro(), package mixins and traits can register methods that PHPStan cannot see. Do not delete a "dead" method until you have grepped for its registration.
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.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings