cesargb/event-tracker

Track application events and send them to an analytics driver such as PostHog.

Maintainers

Package info

github.com/cesargb/event-tracker

pkg:composer/cesargb/event-tracker

Transparency log

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.2.0 2026-08-03 17:05 UTC

This package is auto-updated.

Last update: 2026-08-03 17:11:22 UTC


README

Send events to an analytics driver (currently PostHog) from plain PHP, or automatically from any event dispatched through Laravel's event system.

tests static analysis lint

Installation

composer require cesargb/event-tracker

Plain PHP usage

use Cesargb\Event\Track;
use Cesargb\Event\Track\Drivers\PostHogDriver;
use Cesargb\Event\Track\Event;

Track::init(new PostHogDriver('phc_your_api_key'));

Track::capture(new Event(
    name: 'user_signup',
    userId: '42',
    timestamp: time(),
    properties: ['plan' => 'pro'],
));

Laravel usage

The service provider is auto-discovered. Publish the config file and set your PostHog API key:

php artisan vendor:publish --tag=event-tracker-config
POSTHOG_API_KEY=phc_your_api_key
POSTHOG_HOST=https://eu.i.posthog.com

# Optional: disable tracking entirely (e.g. in local/CI), defaults to true.
EVENT_TRACKER_ENABLED=true

Auto-tracking events

Mark any class dispatched through Laravel's event system with the ShouldBeTracked marker interface and it is sent automatically — no call to Track::capture() needed:

use Cesargb\Event\Track\Laravel\Contracts\ShouldBeTracked;

class OrderShipped implements ShouldBeTracked
{
    public function __construct(public readonly Order $order) {}
}

event(new OrderShipped($order));

This sends an order_shipped event with no properties and no user attribution. ShouldBeTracked has no required methods — you implement only the ones you want to override:

Method Default when not implemented
trackerName(): string Snake-case class basename (order_shipped)
trackerProperties(): array []
trackerUserId(): ?string null — the event is anonymous/personless in PostHog
trackerTimestamp(): int The current timestamp
class OrderShipped implements ShouldBeTracked
{
    public function __construct(public readonly Order $order) {}

    public function trackerProperties(): array
    {
        return ['total' => $this->order->total];
    }

    public function trackerUserId(): ?string
    {
        return (string) $this->order->user_id;
    }
}

If you don't override trackerUserId(), the event still reaches PostHog but can't be attributed to a person — set it whenever you want the event tied to a user.

Tracking the authenticated user

For the common case of attributing an event to whoever is logged in, use the TracksAuthenticatedUser trait instead of writing trackerUserId() by hand:

use Cesargb\Event\Track\Laravel\Concerns\TracksAuthenticatedUser;

class OrderShipped implements ShouldBeTracked
{
    use TracksAuthenticatedUser;

    public function __construct(public readonly Order $order) {}
}

The id is read from the default guard when the event is captured. With no authenticated user (console commands, queued jobs, guests) the event stays anonymous, exactly as if the trait weren't there. A trackerUserId() declared on the event itself takes precedence over the trait.

Tracking constructor properties

For the common case of sending an event's own data as properties, use the TracksConstructorProperties trait instead of writing trackerProperties() by hand:

use Cesargb\Event\Track\Laravel\Concerns\TracksConstructorProperties;

class OrderShipped implements ShouldBeTracked
{
    use TracksConstructorProperties;

    public function __construct(
        public readonly string $trackingNumber,
        #[\SensitiveParameter] public readonly string $customerEmail,
        private readonly Order $order,
    ) {}
}

This sends ['tracking_number' => '...'] — only promoted, public constructor properties are included, each renamed to snake_case:

Excluded Why
private/protected promoted properties ($order above) Not part of the public API of the event
A parameter marked #[\SensitiveParameter] ($customerEmail) Kept out of tracking on purpose
A public property that isn't a promoted constructor parameter Out of scope for this trait
A value with no safe scalar representation (a model, a closure, a pure enum, NAN/INF, a value nested more than 10 levels deep) Would leak more than intended or break the driver's JSON payload

A few value types are cast rather than dropped: a backed enum becomes its scalar ->value, a DateTimeInterface becomes an ISO-8601 string, and any Stringable object is cast with (string). A trackerProperties() declared on the event itself takes precedence over the trait.

A failure while tracking an event (a misconfigured driver, a network error, a broken tracker method) is reported via Laravel's exception handler and swallowed — it never bubbles up to the code that dispatched the event.

Testing

composer test
vendor/bin/pint --test