PHPackages                             pdphilip/omnievent - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. pdphilip/omnievent

ActiveLibrary

pdphilip/omnievent
==================

OmniEvent for Laravel is a Laravel Model event tracking and searching with Elasticsearch module

v3.1.0(2mo ago)321.7k[3 PRs](https://github.com/pdphilip/omnievent/pulls)MITPHPPHP ^8.2CI passing

Since Sep 3Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/pdphilip/omnievent)[ Packagist](https://packagist.org/packages/pdphilip/omnievent)[ Docs](https://github.com/pdphilip/omnievent)[ GitHub Sponsors](https://github.com/pdphilip)[ RSS](/packages/pdphilip-omnievent/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (15)Versions (18)Used By (0)

OmniEvent for Laravel
=====================

[](#omnievent-for-laravel)

[![OmniEvent for Laravel](https://camo.githubusercontent.com/8a48f578ce6da6e3e9e52652a76cb782f8fa924beed59cff24f5ad26f22036b0/68747470733a2f2f63646e2e736e6970666f726d2e696f2f70647068696c69702f6f6d6e696576656e742f6f6d6e696576656e742d6c6f676f2e706e67)](https://camo.githubusercontent.com/8a48f578ce6da6e3e9e52652a76cb782f8fa924beed59cff24f5ad26f22036b0/68747470733a2f2f63646e2e736e6970666f726d2e696f2f70647068696c69702f6f6d6e696576656e742f6f6d6e696576656e742d6c6f676f2e706e67)[![Latest Version on Packagist](https://camo.githubusercontent.com/4cb7ed93a8155e270d8fc1dfdfbf94a2d30337ea33a3e91c24cccbb4e8b9ec4f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f70647068696c69702f6f6d6e696576656e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/pdphilip/omnievent)[![GitHub Tests Action Status](https://camo.githubusercontent.com/53584004ba9461797086860aa1f033640477cb978f7f836a097567f1e338b65f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f70647068696c69702f6f6d6e696576656e742f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/pdphilip/omnievent/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/2c7d8ad1265fa82f8601b6842601c75082ec7cc08e051febde5ad4317baefdcc/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f70647068696c69702f6f6d6e696576656e742f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/pdphilip/omnievent/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/c10123af4fbdd71dbc042f7d0f2e5744c043655482e30a176ae30bca78a9a1bc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f70647068696c69702f6f6d6e696576656e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/pdphilip/omnievent)

Track model events in Elasticsearch. Query them with Eloquent.

```
$user->triggerEvent('login', ['ip' => $request->ip()]);
$user->triggerEvent('purchase', ['amount' => 99.95, 'currency' => 'USD']);
$user->triggerEvent('password_reset');
```

Every event is stored as a document in Elasticsearch with a timestamp, optional metadata, and automatic request context (IP, browser, device, geolocation) via [CfRequest](https://github.com/pdphilip/cf-request).

Query events using the full Elasticsearch Eloquent builder - the same API you already know from [Laravel-Elasticsearch](https://github.com/pdphilip/laravel-elasticsearch):

```
// Quick search - returns Collection
$logins = User::eventSearch('login');

// Full power - Elasticsearch Eloquent builder
User::viaEvents()
    ->where('event', 'purchase')
    ->where('meta.amount', '>=', 50)
    ->where('created_at', '>=', now()->subDays(30))
    ->orderByDesc('created_at')
    ->paginate(20);
```

Events are automatically cleaned up when a model is deleted.

---

Requirements
------------

[](#requirements)

VersionPHP8.2+Laravel10 / 11 / 12Elasticsearch8.xInstallation
------------

[](#installation)

```
composer require pdphilip/omnievent
```

```
php artisan omnievent:install
```

This publishes `config/omnievent.php`.

> Requires a [Laravel-Elasticsearch](https://github.com/pdphilip/laravel-elasticsearch) connection. See [configuration guide](https://elasticsearch.pdphilip.com/getting-started/configuration).

---

Quick Start
-----------

[](#quick-start)

### 1. Generate an event model

[](#1-generate-an-event-model)

```
php artisan omnievent:make User
```

This creates `app/Models/Events/UserEvent.php`:

```
namespace App\Models\Events;

use App\Models\User;
use PDPhilip\OmniEvent\EventModel;

class UserEvent extends EventModel
{
    protected $baseModel = User::class;

    public function modelType(User $model): ?string
    {
        return null;
    }
}
```

### 2. Add the trait

[](#2-add-the-trait)

```
use PDPhilip\OmniEvent\Eventable;

class User extends Model
{
    use Eventable;
}
```

That's it. The Elasticsearch index is created automatically on first boot.

### 3. Track events

[](#3-track-events)

```
$user->triggerEvent('login');
$user->triggerEvent('purchase', ['amount' => 49.99, 'currency' => 'EUR']);
```

---

Querying Events
---------------

[](#querying-events)

### Quick Search

[](#quick-search)

Returns a `Collection` of event records matching the event name:

```
$logins = User::eventSearch('login');
```

### Full Builder

[](#full-builder)

Returns the Elasticsearch Eloquent builder for the event model. Chain any query method you'd use on a normal Eloquent model:

```
// Filter by event type and date range
User::viaEvents()
    ->where('event', 'purchase')
    ->where('created_at', '>=', now()->subMonth())
    ->get();

// Paginate
User::viaEvents()
    ->where('event', 'login')
    ->orderByDesc('created_at')
    ->paginate(15);

// Count
User::viaEvents()
    ->where('event', 'purchase')
    ->count();

// Filter by metadata
User::viaEvents()
    ->where('meta.currency', 'USD')
    ->where('meta.amount', '>=', 100)
    ->get();

// Filter by request context
User::viaEvents()
    ->where('request.country', 'US')
    ->where('request.deviceType', 'mobile')
    ->get();
```

Since `viaEvents()` returns a standard Elasticsearch Eloquent builder, you get access to everything: `where`, `orderBy`, `limit`, `paginate`, `count`, `aggregate`, `searchTerm`, `distinct`, and more. See the [Laravel-Elasticsearch docs](https://elasticsearch.pdphilip.com) for the full query API.

---

Event Record Structure
----------------------

[](#event-record-structure)

Each event is stored as an Elasticsearch document with these fields:

FieldTypeDescription`model_id`keywordThe base model's primary key`model_type`keywordOptional type from `modelType()` method`event`keywordThe event name`ts`integerUnix timestamp`meta`flattenedCustom metadata (any key-value data)`created_at`datetimeLaravel timestampWhen `save_request` is enabled in config, each event also captures:

FieldTypeDescription`request.ip`keywordClient IP address`request.browser`keywordBrowser name and version`request.device`keywordDevice brand and model`request.deviceType`keyword`desktop`, `mobile`, `tablet`, `tv``request.os`keywordOperating system`request.country`keywordISO country code`request.region`keywordRegion/state`request.city`keywordCity`request.postal_code`keywordPostal code`request.lat`floatLatitude`request.lon`floatLongitude`request.timezone`keywordTimezone`request.is_bot`booleanBot detection flag`request.geo`geo\_pointGeoJSON point for geo queriesRequest data is captured automatically via [CfRequest](https://github.com/pdphilip/cf-request). Behind Cloudflare, you get full geolocation. Without Cloudflare, you still get IP, browser, device, and bot detection.

---

Model Types
-----------

[](#model-types)

The `modelType()` method on your event model lets you tag events with a model subtype. Useful for segmenting events by user role, account tier, or any model attribute:

```
class UserEvent extends EventModel
{
    protected $baseModel = User::class;

    public function modelType(User $model): ?string
    {
        return $model->plan; // 'free', 'pro', 'enterprise'
    }
}
```

Then filter by type:

```
User::viaEvents()
    ->where('model_type', 'pro')
    ->where('event', 'export')
    ->count();
```

Return `null` to skip the type field entirely.

---

Resolving the Base Model
------------------------

[](#resolving-the-base-model)

Every event record can resolve back to its source model:

```
$event = UserEvent::where('event', 'login')->first();

// Via relationship (eager-loadable)
$event->model;          // User instance
$event->model->name;    // 'David'

// Via direct lookup
$event->asModel();      // User instance or null

// Eager load across a collection
$events = UserEvent::where('event', 'login')
    ->with('model')
    ->get();
```

The base model is resolved from the `$baseModel` property on your event model. If not set, OmniEvent guesses it from the table name (`user_events` -&gt; `User`).

---

Automatic Cleanup
-----------------

[](#automatic-cleanup)

When a model is deleted, all its events are automatically removed:

```
$user->delete(); // All UserEvent records for this user are deleted
```

This is registered via the `Eventable` trait's boot method. No manual cleanup needed.

---

Configuration
-------------

[](#configuration)

```
// config/omnievent.php
return [
    // Elasticsearch connection name
    'database' => 'elasticsearch',

    // Throw exceptions on event save failure (false = log and return false)
    'throw_exceptions' => true,

    // Capture request metadata (IP, browser, geo) with each event
    'save_request' => true,

    // Namespaces for model resolution
    'namespaces' => [
        'models' => 'App\Models',
        'events' => 'App\Models\Events',
    ],

    // File paths (relative to app/) for event model discovery
    'app_paths' => [
        'models' => 'Models/',
        'events' => 'Models/Events/',
    ],
];
```

### Error Handling

[](#error-handling)

By default, exceptions from Elasticsearch are thrown. Set `throw_exceptions` to `false` to silently log errors and return `false` from `triggerEvent()`:

```
// config/omnievent.php
'throw_exceptions' => false,
```

```
// Now returns false instead of throwing
$success = $user->triggerEvent('login'); // false if ES is down
```

This is useful in production where event tracking should never break your application flow.

---

API Reference
-------------

[](#api-reference)

### Eventable Trait (on your base model)

[](#eventable-trait-on-your-base-model)

MethodReturnsDescription`$model->triggerEvent(string $event, array $meta = [])``bool`Save an event with optional metadata`Model::viaEvents()``Builder`Elasticsearch Eloquent builder for the event model`Model::eventSearch(string $event)``Collection`Shorthand for `viaEvents()->where('event', $event)->get()`### EventModel (your event model class)

[](#eventmodel-your-event-model-class)

MethodReturnsDescription`$event->model()``BelongsTo`Relationship to the base model (eager-loadable)`$event->asModel()``?Model`Direct lookup of the base model`EventModel::saveEvent(Model $model, string $event, array $meta = [])``bool`Create an event record`EventModel::deleteAllEvents(Model $model)``void`Delete all events for a model`EventModel::validateSchema()``array`Create the Elasticsearch index if it doesn't exist---

Changelog
---------

[](#changelog)

See [CHANGELOG](CHANGELOG.md) for recent changes.

Credits
-------

[](#credits)

- [David Philip](https://github.com/pdphilip)

License
-------

[](#license)

The MIT License (MIT). See [License File](LICENSE.md) for details.

###  Health Score

50

—

FairBetter than 96% of packages

Maintenance85

Actively maintained with recent releases

Popularity31

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 74.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~41 days

Recently: every ~21 days

Total

14

Last Release

84d ago

Major Versions

v1.0.7 → V2.0.02025-03-28

v2.x-dev → v3.0.02026-02-22

### Community

Maintainers

![](https://www.gravatar.com/avatar/d6945e816609fe0d57ad2e073ad9f6ea008ac19636ff439e528c765df6c26230?d=identicon)[pdphilip](/maintainers/pdphilip)

---

Top Contributors

[![pdphilip](https://avatars.githubusercontent.com/u/6921550?v=4)](https://github.com/pdphilip "pdphilip (29 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (5 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (5 commits)")

---

Tags

laravelPDPhilipomnievent

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/pdphilip-omnievent/health.svg)

```
[![Health](https://phpackages.com/badges/pdphilip-omnievent/health.svg)](https://phpackages.com/packages/pdphilip-omnievent)
```

###  Alternatives

[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24149.7k](/packages/vormkracht10-laravel-mails)[spatie/laravel-prometheus

Export Laravel metrics to Prometheus

2651.3M6](/packages/spatie-laravel-prometheus)[pdphilip/cf-request

Cloudflare Laravel Request

2725.6k1](/packages/pdphilip-cf-request)[pdphilip/elasticlens

Search your Laravel models with the convenience of Eloquent and the power of Elasticsearch

10427.6k](/packages/pdphilip-elasticlens)[hydrat/filament-table-layout-toggle

Filament plugin adding a toggle button to tables, allowing user to switch between Grid and Table layouts.

6292.3k1](/packages/hydrat-filament-table-layout-toggle)[scalar/laravel

Render your OpenAPI-based API reference

6183.9k2](/packages/scalar-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
