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

Signals Laravel Package

aiarmada/signals

A Laravel package for working with signals: lightweight, typed events that let you broadcast and observe changes across your app. Clean API, framework-native integration, and easy to wire into existing services and Eloquent models.

View on GitHub
Deep Wiki
Context7

Getting Started

Read the source before you install it. With 0 stars and 0 dependents this is an unvetted package; budget 20 minutes to skim composer.json, the service provider, and the config file on GitHub before committing it to a project.

  1. Check the constraints first. Open composer.json in the repo and confirm require.php and require.laravel/framework cover your version. For an unmaintained-looking package this is the single most likely reason install fails.
  2. Install and inspect what it registers.
    composer require aiarmada/signals
    php artisan about            # confirm the provider was auto-discovered
    php artisan vendor:publish --provider="AIArmada\Signals\SignalsServiceProvider"
    
    Publish tags vary — run php artisan vendor:publish with no arguments and read the interactive list rather than guessing --tag=signals-config.
  3. Read the published config end to end. This is your map of the package: storage driver, table names, queue connection, retention window, middleware toggles. Everything in the next two sections keys off what you find there.
  4. Run migrations into a scratch database first.
    php artisan migrate --pretend   # see the DDL before it touches your DB
    
  5. Send one event and verify it round-trips. Don't start with pageviews or a dashboard; start with a deliberately boring custom event and confirm the row exists.

Where to look first, in order: the config file → the migrations (they define the data model, which is the real API) → the facade or entry-point class → any Console commands (retention/pruning is usually there).

First use case: instrument a single conversion — e.g. signup_completed or checkout_completed — with three properties (plan, source, value). Once you can see that row and query it back, you understand the package's whole model. Everything else is repetition.


Implementation Patterns

Wrap the package behind your own thin layer

With a package this young, the highest-value pattern is a one-file abstraction so a future swap is a config change, not a refactor.

// app/Analytics/Tracker.php
interface Tracker
{
    public function track(string $event, array $properties = [], ?string $subject = null): void;
}

Bind SignalsTracker to it in a service provider. Controllers and jobs type-hint Tracker, never the vendor facade. If the package is abandoned in six months you rewrite one class.

Capture at the edges, not in the domain

Two clean insertion points, and you want both:

  • Pageviews / request context — via middleware, so you get URL, referrer, UA, and session without polluting controllers. Register it on the web group only; API traffic will otherwise flood your table.
  • Domain events — a single listener that maps your existing OrderPlaced, UserRegistered events to track() calls. Your domain stays unaware analytics exists.
Event::listen(OrderPlaced::class, fn ($e) => app(Tracker::class)->track(
    'order_placed',
    ['value' => $e->order->total_cents, 'currency' => $e->order->currency],
    $e->order->user,
));

Always queue the writes

Analytics writes are the classic case for ShouldQueue. If the package's config exposes a queue connection, point it at a low-priority queue — never default — so a slow analytics insert can't back up mail or webhooks. If it doesn't expose one, wrap your Tracker implementation in a queued job yourself.

// config/queue.php or config/signals.php
'queue' => env('SIGNALS_QUEUE', 'analytics'),

Establish a property naming contract on day one

Pick snake_case, flat keys, and a fixed vocabulary for the handful of properties you'll filter on (plan, source, value, currency). Enforce it in the Tracker implementation with a small allowlist. This is the difference between usable aggregates in six months and a table full of userId, user_id, and uid meaning the same thing.

Associate with the actor explicitly

Prefer passing the subject model (user, tenant, order) into track() over relying on auth()->id() inside the package. Background jobs and webhooks run without a session, and silent anonymous events are a common source of "why are my numbers low". If you're multi-tenant, put tenant_id in every event's properties — retrofitting it later means a backfill.

Keep reporting out of the package

If the package ships query helpers or a dashboard, treat them as convenience only. For anything you'd put in front of a stakeholder, write your own query against the underlying table/view and wrap it in a read-only repository. That way a package upgrade can't change your KPI definitions, and you control indexes and caching.

Testing

Wrap the tracker in a fake in your test suite:

$this->instance(Tracker::class, $fake = new FakeTracker());
// ... act ...
$fake->assertTracked('order_placed', fn ($p) => $p['value'] === 4200);

If the package provides its own fake/assertions, use them for the integration test and your fake everywhere else — you don't want 300 tests coupled to vendor assertion APIs.


Gotchas and Tips

The package is unproven. 0 stars and 0 dependents is not a verdict, but it is a risk profile. Pin it exactly ("aiarmada/signals": "1.0.3", not ^1.0) and note it in your dependency-review doc. Have an exit plan: the Tracker interface above is the exit plan.

Config caching bites on install. After editing config/signals.php, php artisan config:clear — otherwise your local changes appear to do nothing while config:cache is active in staging. Classic first-hour confusion.

Migrations need indexes before data, not after. Adding an index to a 10M-row analytics table in production is a different task than adding it on an empty table. Read the migration, and if the query columns (event, subject_id, created_at) aren't indexed, add a follow-up migration immediately — while the table is still empty.

Timezone ambiguity will corrupt your reports. Determine whether created_at is stored UTC and whether the package buckets by app timezone. A "yesterday's signups" number that disagrees with your DB by a few hours is almost always this. Decide once, document it, and always convert in the query, not in the view.

PII and consent are your problem, not the package's. Analytics tables quietly accumulate IPs, emails in properties, and URLs with query strings. Before the first deploy: decide on IP anonymization/hashing, add a retention/prune command to the scheduler, and make sure the tracker respects your cookie-consent state (return early from middleware when consent is absent). A package can't know your jurisdiction.

Cardinality will kill query performance. Properties are usually stored as JSON or a key-value table. Once a high-cardinality key (session ID, email, UUID) lands in properties and someone adds a GROUP BY, reporting slows to a crawl. Keep high-cardinality identifiers in dedicated columns and properties for low-cardinality dimensions only.

Watch for N+1 in any built-in reporting. Dashboards that hydrate models per event row are common in small analytics packages. DB::listen() while loading the first dashboard will tell you in 30 seconds.

Queue failures are silent. A queued tracker that throws on a malformed property looks identical to "no traffic". Add a failed-job alert for the analytics queue, or at minimum log inside your Tracker implementation before dispatch.

Extension points to look for, in descending value: a config-selectable storage driver, an event fired before/after a track call (for enrichment or filtering), and a swappable middleware. If none exist, your Tracker wrapper becomes the extension point — which is fine, and further justification for building it first.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package