andrewdyer/metrics

A library for calculating and aggregating metrics from Eloquent queries

Maintainers

Package info

github.com/andrewdyer/metrics

pkg:composer/andrewdyer/metrics

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.0 2026-06-02 21:55 UTC

This package is auto-updated.

Last update: 2026-06-02 22:21:27 UTC


README

A library for calculating and aggregating metrics from Eloquent queries.

Latest Stable Version Total Downloads License PHP Version Require

Introduction

This library provides strongly typed metric calculations and aggregations from Eloquent queries, including Value, Trend, and Partition metrics that return structured result objects with JSON serialisation support. The package is built on top of andrewdyer/php-package-template.

Prerequisites

  • PHP: Version 8.3 or higher is required.
  • Composer: Dependency management tool for PHP.
  • Eloquent ORM: An configured Eloquent connection is required.

Installation

composer require andrewdyer/metrics

Getting Started

1. Set up Eloquent

This library requires an Eloquent connection. In a Laravel application this is configured automatically. Outside of Laravel, bootstrap Eloquent using the Capsule manager:

use Illuminate\Database\Capsule\Manager as Capsule;

$capsule = new Capsule();

$capsule->addConnection([
    'driver'   => 'mysql',
    'host'     => '127.0.0.1',
    'database' => 'my_database',
    'username' => 'root',
    'password' => '',
    'charset'  => 'utf8',
    'prefix'   => '',
]);

$capsule->setAsGlobal();
$capsule->bootEloquent();

2. Create a metric

Extend Value and implement calculate() to define the query, and getStartDate() / getEndDate() to define the date range:

use AndrewDyer\Metrics\Value;
use AndrewDyer\Metrics\Results\ValueResult;
use DateTimeImmutable;

class TotalNewUsers extends Value
{
    public function calculate(): ValueResult
    {
        return $this->count(User::query());
    }

    public function getStartDate(): DateTimeImmutable
    {
        return new DateTimeImmutable('first day of this month');
    }

    public function getEndDate(): DateTimeImmutable
    {
        return new DateTimeImmutable('last day of this month');
    }
}

Usage

Calculating a metric

Call calculate() on any metric instance to run the query and return a typed result:

$metric = new TotalNewUsers();
$result = $metric->calculate();

$result->getResult(); // e.g. 42

JSON serialisation

All result objects implement JsonSerializable:

json_encode($metric->calculate());
// {"result": 42}

Customising the metric name and description

Override getName() and getDescription() on any metric to provide a human-readable label:

public function getName(): string
{
    return 'Total New Users';
}

public function getDescription(): string
{
    return 'The total number of users who signed up this month.';
}

Rounding

Override getRoundingPrecision() and getRoundingMode() to control how aggregate values are rounded:

public function getRoundingPrecision(): int
{
    return 2;
}

public function getRoundingMode(): int
{
    return PHP_ROUND_HALF_UP;
}

Metric Types

Value

A Value metric calculates a single aggregate over a date range. An optional $dateColumn argument overrides the default created_at column.

Count

Returns the number of records within the date range:

$this->count(User::query());

Sum

Totals the values of a column across all matching records:

$this->sum(User::query(), 'revenue');

Average

Calculates the mean value of a column across all matching records:

$this->average(User::query(), 'revenue');

Minimum

Returns the smallest value of a column within the date range:

$this->min(User::query(), 'revenue');

Maximum

Returns the largest value of a column within the date range:

$this->max(User::query(), 'revenue');

Trend

A Trend metric calculates an aggregate grouped over time at a given frequency. Missing dates within the range are automatically filled with zero values.

Extend Trend and implement calculate(), getStartDate(), getEndDate(), and getFrequency():

use AndrewDyer\Metrics\Trend;
use AndrewDyer\Metrics\Enums\Frequency;
use AndrewDyer\Metrics\Results\TrendResult;
use DateTimeImmutable;

class UserSignupsOverTime extends Trend
{
    public function calculate(): TrendResult
    {
        return $this->count(User::query(), null, 'created_at');
    }

    public function getFrequency(): Frequency
    {
        return Frequency::Monthly;
    }

    public function getStartDate(): DateTimeImmutable
    {
        return new DateTimeImmutable('first day of january this year');
    }

    public function getEndDate(): DateTimeImmutable
    {
        return new DateTimeImmutable('last day of december this year');
    }
}

Calculating the metric returns a keyed array of labels to aggregate values:

$metric = new UserSignupsOverTime();
$result = $metric->calculate();

$result->getResult(); // ['January 2026' => 12, 'February 2026' => 9, ...]

Supported frequencies

Frequency::Daily
Frequency::Weekly
Frequency::Monthly

Count

Tracks how many records fall within each period of the date range:

$this->count(User::query(), null, 'created_at');

Sum

Totals a column's values for each period across the date range:

$this->sum(User::query(), 'revenue', 'created_at');

Average

Calculates the mean value of a column for each period in the range:

$this->average(User::query(), 'revenue', 'created_at');

Minimum

Returns the lowest value of a column recorded within each period:

$this->min(User::query(), 'revenue', 'created_at');

Maximum

Returns the highest value of a column recorded within each period:

$this->max(User::query(), 'revenue', 'created_at');

Partition

A Partition metric calculates an aggregate grouped by a categorical column, returning a key-value breakdown.

Extend Partition and implement calculate():

use AndrewDyer\Metrics\Partition;
use AndrewDyer\Metrics\Results\PartitionResult;
use DateTimeImmutable;

class UsersByCountry extends Partition
{
    public function calculate(): PartitionResult
    {
        return $this->count(User::query(), 'country');
    }

    public function getStartDate(): DateTimeImmutable
    {
        return new DateTimeImmutable('first day of this year');
    }

    public function getEndDate(): DateTimeImmutable
    {
        return new DateTimeImmutable('today');
    }
}

Calculating the metric returns a keyed array of group labels to aggregate values:

$metric = new UsersByCountry();
$result = $metric->calculate();

$result->getResult(); // ['GB' => 42, 'US' => 31, 'DE' => 14]

Count

Groups records by a column and counts how many fall into each category:

$this->count(User::query(), 'country');

Sum

Groups records by a column and totals a second column within each group:

$this->sum(User::query(), 'country', 'revenue');

Average

Groups records by a column and calculates the mean of a second column per group:

$this->average(User::query(), 'country', 'revenue');

Database Support

The following database drivers are supported:

Driver Minimum Version
MySQL 5.7+
MariaDB 10.2+
SQLite 3.38.0+
PostgreSQL 9.4+

License

Licensed under the MIT licence and is free for private or commercial projects.