cesargb/event-tracker

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.1.0 2026-07-29 11:27 UTC

This package is auto-updated.

Last update: 2026-07-29 16:39:13 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 public properties

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

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

class OrderShipped implements ShouldBeTracked
{
    use TracksPublicProperties;

    public function __construct(public readonly int $orderId, public readonly float $total) {}
}

This sends ['order_id' => ..., 'total' => ...] — every public property, keyed by its snake-cased name. Only values that reduce to a primitive are included:

Value Result
int, float, string, bool sent as-is
BackedEnum its ->value
UnitEnum (pure enum) its ->name
DateTimeInterface ISO 8601 (->format(DateTimeInterface::ATOM))
object with __toString() cast to string
null, arrays, any other object omitted

static, protected, and private properties are never included, and neither is a typed property left uninitialized. Override trackerExcludedProperties() to keep specific properties out — for example an API token that happens to be public:

class OrderShipped implements ShouldBeTracked
{
    use TracksPublicProperties;

    public function __construct(public readonly int $orderId, public readonly string $apiToken) {}

    protected function trackerExcludedProperties(): array
    {
        return ['apiToken'];
    }
}

Note the exclusion list uses the property's name as declared on the class (apiToken), not its snake_cased key. Because the trait sends everything public, keep anything sensitive protected or add it to trackerExcludedProperties(). A trackerProperties() declared on the event itself takes precedence over the trait, and both tracker traits can be combined on the same event.

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