Laravel Package

Laravel package with service providers and middleware

Laravel Package

The entrolytics-laravel-middleware package provides a comprehensive Laravel package for analytics tracking with service providers, middleware, facades, and seamless Laravel integration.

Installation

composer require entrolytics/laravel-middleware

Quick Start

Install Package

composer require entrolytics/laravel-middleware

Publish Configuration

php artisan vendor:publish --provider="Entrolytics\Laravel\EntrolyticsServiceProvider"

Configure Environment

# .env
ENTROLYTICS_WEBSITE_ID=your-website-id
ENTROLYTICS_API_KEY=your-api-key
ENTROLYTICS_HOST=https://entrolytics.dev

Use in Controller

<?php

namespace App\Http\Controllers;

use Entrolytics\Facades\Entrolytics;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function show($id)
    {
        $user = User::findOrFail($id);

        // Track page view
        Entrolytics::page('user_profile', [
            'user_id' => $user->id,
            'user_role' => $user->role
        ]);

        return view('users.show', compact('user'));
    }

    public function store(Request $request)
    {
        // Track event
        Entrolytics::track('user_creation_attempt', [
            'email' => $request->email,
            'source' => $request->input('source', 'web')
        ]);

        $user = User::create($request->validated());

        // Track success
        Entrolytics::track('user_created', [
            'user_id' => $user->id,
            'email' => $user->email
        ]);

        return redirect()->route('users.show', $user);
    }
}

Configuration

Configuration File

// config/entrolytics.php
return [
    /*
    |--------------------------------------------------------------------------
    | Website ID
    |--------------------------------------------------------------------------
    |
    | Your Entrolytics website ID. This is required for tracking.
    |
    */
    'website_id' => env('ENTROLYTICS_WEBSITE_ID'),

    /*
    |--------------------------------------------------------------------------
    | API Key
    |--------------------------------------------------------------------------
    |
    | Your Entrolytics API key. Optional, used for enhanced features.
    |
    */
    'api_key' => env('ENTROLYTICS_API_KEY'),

    /*
    |--------------------------------------------------------------------------
    | Host
    |--------------------------------------------------------------------------
    |
    | The Entrolytics API host URL.
    |
    */
    'host' => env('ENTROLYTICS_HOST', 'https://entrolytics.dev'),

    /*
    |--------------------------------------------------------------------------
    | Auto Track
    |--------------------------------------------------------------------------
    |
    | Automatically track HTTP requests.
    |
    */
    'auto_track' => env('ENTROLYTICS_AUTO_TRACK', true),

    /*
    |--------------------------------------------------------------------------
    | Track Errors
    |--------------------------------------------------------------------------
    |
    | Automatically track exceptions and errors.
    |
    */
    'track_errors' => env('ENTROLYTICS_TRACK_ERRORS', true),

    /*
    |--------------------------------------------------------------------------
    | Exclude Paths
    |--------------------------------------------------------------------------
    |
    | Paths to exclude from automatic tracking.
    |
    */
    'exclude_paths' => [
        'health',
        'metrics',
        'nova-api/*',
        'telescope*',
    ],

    /*
    |--------------------------------------------------------------------------
    | Include Headers
    |--------------------------------------------------------------------------
    |
    | HTTP headers to include in tracking data.
    |
    */
    'include_headers' => [
        'User-Agent',
        'X-Forwarded-For',
        'X-Real-IP',
        'Referer',
    ],

    /*
    |--------------------------------------------------------------------------
    | User Identification
    |--------------------------------------------------------------------------
    |
    | Automatically identify authenticated users.
    |
    */
    'identify_users' => env('ENTROLYTICS_IDENTIFY_USERS', true),

    /*
    |--------------------------------------------------------------------------
    | Queue Tracking
    |--------------------------------------------------------------------------
    |
    | Track queued job events.
    |
    */
    'track_queue' => env('ENTROLYTICS_TRACK_QUEUE', true),

    /*
    |--------------------------------------------------------------------------
    | Debug Mode
    |--------------------------------------------------------------------------
    |
    | Enable debug logging for development.
    |
    */
    'debug' => env('ENTROLYTICS_DEBUG', env('APP_DEBUG', false)),
];

Service Provider Registration

// config/app.php
'providers' => [
    // ... other providers
    /*
     * Package Service Providers...
     */
    Entrolytics\Laravel\EntrolyticsServiceProvider::class,
],

/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
*/
'aliases' => [
    // ... other aliases
    'Entrolytics' => Entrolytics\Laravel\Facades\Entrolytics::class,
],

API Reference

Facade Methods

use Entrolytics\Facades\Entrolytics;

// Track custom events
Entrolytics::track(string $event, array $properties = []): void

// Track page views
Entrolytics::page(string $url, array $properties = []): void

// Identify users
Entrolytics::identify(string $userId, array $traits = []): void

// Set user properties
Entrolytics::setUserProperties(array $properties): void

// Track multiple events
Entrolytics::trackBatch(array $events): void

// Flush pending events
Entrolytics::flush(): void

// Enable/disable tracking
Entrolytics::setEnabled(bool $enabled): void

// Check if tracking is enabled
Entrolytics::isEnabled(): bool

// Get configuration
Entrolytics::getConfig(): array

Helper Functions

// Global helper functions
entrolytics_track(string $event, array $properties = []): void
entrolytics_page(string $url, array $properties = []): void
entrolytics_identify(string $userId, array $traits = []): void
entrolytics_set_properties(array $properties): void

Request Macro

// Available on Illuminate\Http\Request
$request->entrolytics()->track($event, $properties);
$request->entrolytics()->identify($userId, $traits);
$request->entrolytics()->page($url, $properties);

Advanced Usage

Middleware Integration

// app/Http/Kernel.php
protected $middleware = [
    // ... other middleware
    \Entrolytics\Laravel\Middleware\TrackRequests::class,
];

protected $middlewareGroups = [
    'web' => [
        // ... other middleware
        \Entrolytics\Laravel\Middleware\IdentifyUsers::class,
    ],

    'api' => [
        // ... other middleware
        \Entrolytics\Laravel\Middleware\TrackApiRequests::class,
    ],
];

Custom Middleware

<?php

namespace App\Http\Middleware;

use Closure;
use Entrolytics\Facades\Entrolytics;
use Illuminate\Http\Request;

class CustomAnalytics
{
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);

        // Track API version
        if ($apiVersion = $request->header('API-Version')) {
            Entrolytics::track('api_request', [
                'version' => $apiVersion,
                'method' => $request->method(),
                'endpoint' => $request->path(),
                'status' => $response->getStatusCode()
            ]);
        }

        // Track authenticated users with custom properties
        if ($request->user()) {
            Entrolytics::identify($request->user()->id, [
                'email' => $request->user()->email,
                'role' => $request->user()->role,
                'subscription' => $request->user()->subscription?->type,
                'last_login' => $request->user()->last_login_at->toISOString()
            ]);
        }

        return $response;
    }
}

Controller Integration

<?php

namespace App\Http\Controllers;

use Entrolytics\Facades\Entrolytics;
use Illuminate\Http\Request;

class AnalyticsController extends Controller
{
    public function dashboard()
    {
        // Track dashboard access
        Entrolytics::page('dashboard', [
            'user_role' => auth()->user()->role,
            'has_notifications' => auth()->user()->unreadNotifications()->count() > 0,
            'last_login' => auth()->user()->last_login_at->diffInDays(now())
        ]);

        return view('dashboard');
    }

    public function purchase(Request $request)
    {
        $product = Product::findOrFail($request->product_id);

        // Track purchase attempt
        Entrolytics::track('purchase_attempt', [
            'product_id' => $product->id,
            'product_name' => $product->name,
            'price' => $product->price,
            'currency' => $product->currency,
            'payment_method' => $request->payment_method
        ]);

        try {
            $order = Order::create([
                'user_id' => auth()->id(),
                'product_id' => $product->id,
                'amount' => $product->price,
                // ... other fields
            ]);

            // Track successful purchase
            Entrolytics::track('purchase_completed', [
                'order_id' => $order->id,
                'product_id' => $product->id,
                'amount' => $order->amount,
                'currency' => $order->currency,
                'payment_method' => $request->payment_method
            ]);

            // Update user properties
            Entrolytics::setUserProperties([
                'total_purchases' => auth()->user()->orders()->count(),
                'total_spent' => auth()->user()->orders()->sum('amount'),
                'last_purchase' => now()->toISOString()
            ]);

            return redirect()->route('orders.show', $order);

        } catch (\Exception $e) {
            // Track purchase failure
            Entrolytics::track('purchase_failed', [
                'product_id' => $product->id,
                'error' => $e->getMessage(),
                'error_type' => get_class($e),
                'payment_method' => $request->payment_method
            ]);

            throw $e;
        }
    }
}

Model Events

<?php

namespace App\Providers;

use App\Models\User;
use Illuminate\Support\Facades\Event;
use Entrolytics\Facades\Entrolytics;
use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        // User authentication events
        Event::listen(Login::class, function ($event) {
            Entrolytics::identify($event->user->id, [
                'email' => $event->user->email,
                'name' => $event->user->name,
                'role' => $event->user->role
            ]);

            Entrolytics::track('login', [
                'method' => 'web',
                'ip_address' => request()->ip(),
                'user_agent' => request()->userAgent()
            ]);
        });

        Event::listen(Logout::class, function ($event) {
            Entrolytics::track('logout', [
                'method' => 'web',
                'session_duration' => session('login_time') ? now()->diffInSeconds(session('login_time')) : null
            ]);
        });

        // Model events
        User::created(function ($user) {
            Entrolytics::track('user_registered', [
                'user_id' => $user->id,
                'email' => $user->email,
                'registration_source' => request()->input('source', 'web')
            ]);
        });

        User::updated(function ($user) {
            Entrolytics::track('user_updated', [
                'user_id' => $user->id,
                'changed_fields' => array_keys($user->getDirty())
            ]);
        });
    }
}

Queue Job Tracking

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Entrolytics\Facades\Entrolytics;

class ProcessAnalytics implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $data;

    public function __construct(array $data)
    {
        $this->data = $data;
    }

    public function handle()
    {
        // Track job start
        Entrolytics::track('job_started', [
            'job_class' => static::class,
            'queue' => $this->queue,
            'attempt' => $this->attempts()
        ]);

        try {
            // Process the data
            $result = $this->processData($this->data);

            // Track job completion
            Entrolytics::track('job_completed', [
                'job_class' => static::class,
                'result_count' => count($result),
                'processing_time' => $this->job->getJob()?->getRuntime()
            ]);

        } catch (\Exception $e) {
            // Track job failure
            Entrolytics::track('job_failed', [
                'job_class' => static::class,
                'error' => $e->getMessage(),
                'error_type' => get_class($e),
                'attempt' => $this->attempts()
            ]);

            throw $e;
        }
    }

    public function failed(\Throwable $exception)
    {
        Entrolytics::track('job_permanently_failed', [
            'job_class' => static::class,
            'error' => $exception->getMessage(),
            'max_attempts' => $this->tries
        ]);
    }
}

Form Request Validation

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Entrolytics\Facades\Entrolytics;

class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ];
    }

    protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
    {
        // Track validation errors
        Entrolytics::track('form_validation_failed', [
            'form' => 'user_registration',
            'errors' => $validator->errors()->toArray(),
            'invalid_fields' => array_keys($validator->errors()->toArray())
        ]);

        parent::failedValidation($validator);
    }
}

Testing

Unit Tests

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Entrolytics\Facades\Entrolytics;
use Entrolytics\Laravel\EntrolyticsManager;
use Illuminate\Foundation\Testing\RefreshDatabase;

class AnalyticsTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        // Mock the analytics client
        Entrolytics::fake();
    }

    public function test_track_event()
    {
        Entrolytics::track('test_event', ['property' => 'value']);

        Entrolytics::assertTracked('test_event', function ($event) {
            return $event['properties']['property'] === 'value';
        });
    }

    public function test_identify_user()
    {
        $user = User::factory()->create();

        Entrolytics::identify($user->id, [
            'email' => $user->email,
            'name' => $user->name
        ]);

        Entrolytics::assertIdentified($user->id, function ($traits) {
            return $traits['email'] === $user->email;
        });
    }

    public function test_middleware_tracking()
    {
        $response = $this->get('/');

        $response->assertStatus(200);

        // Assert that automatic tracking was called
        Entrolytics::assertTracked('page_view');
    }
}

Feature Tests

<?php

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\User;
use Entrolytics\Facades\Entrolytics;

class UserControllerTest extends TestCase
{
    public function test_user_creation_tracks_events()
    {
        Entrolytics::fake();

        $userData = [
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'password' => 'password',
            'password_confirmation' => 'password'
        ];

        $response = $this->post('/users', $userData);

        $response->assertRedirect();

        // Assert events were tracked
        Entrolytics::assertTracked('user_creation_attempt');
        Entrolytics::assertTracked('user_created');

        // Assert user was identified
        $user = User::where('email', 'john@example.com')->first();
        Entrolytics::assertIdentified($user->id);
    }

    public function test_form_validation_errors_tracked()
    {
        Entrolytics::fake();

        $invalidData = [
            'name' => '',
            'email' => 'invalid-email',
            'password' => '123'
        ];

        $response = $this->post('/users', $invalidData);

        $response->assertSessionHasErrors();

        // Assert validation error was tracked
        Entrolytics::assertTracked('form_validation_failed', function ($event) {
            return isset($event['properties']['errors']);
        });
    }
}

Performance Optimization

Async Tracking

<?php

namespace App\Http\Controllers;

use Entrolytics\Facades\Entrolytics;
use Illuminate\Http\Request;

class PerformanceController extends Controller
{
    public function fastEndpoint(Request $request)
    {
        // Track asynchronously to avoid blocking
        dispatch(function () use ($request) {
            Entrolytics::track('fast_endpoint_access', [
                'path' => $request->path(),
                'method' => $request->method()
            ]);
        })->afterResponse();

        return response()->json(['status' => 'ok']);
    }
}

Batching

<?php

namespace App\Services;

use Entrolytics\Facades\Entrolytics;
use Illuminate\Support\Collection;

class AnalyticsBatchService
{
    protected $events = [];
    protected $batchSize = 50;

    public function addEvent(string $event, array $properties = [])
    {
        $this->events[] = [
            'event' => $event,
            'properties' => $properties,
            'timestamp' => now()->toISOString()
        ];

        if (count($this->events) >= $this->batchSize) {
            $this->flush();
        }
    }

    public function flush()
    {
        if (!empty($this->events)) {
            Entrolytics::trackBatch($this->events);
            $this->events = [];
        }
    }

    public function __destruct()
    {
        $this->flush();
    }
}

Troubleshooting

Best Practices

Migration Guide

From Manual Analytics

// Before - Manual tracking
use Analytics;

class UserController extends Controller
{
    public function show($id)
    {
        Analytics::track('user_view', ['user_id' => $id]);
        // ...
    }
}

// After - Laravel package
use Entrolytics\Facades\Entrolytics;

class UserController extends Controller
{
    public function show($id)
    {
        Entrolytics::page('user_profile', ['user_id' => $id]);
        // ...
    }
}

From Other Laravel Analytics

// Before - Other package
use OtherAnalytics\Facades\Analytics;

// After - Entrolytics
use Entrolytics\Facades\Entrolytics;

// Update service provider registration
// config/app.php
'providers' => [
    // Remove: OtherAnalytics\ServiceProvider::class
    Entrolytics\Laravel\EntrolyticsServiceProvider::class,
],

Laravel package for Entrolytics - First-party growth analytics for the edge