Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Relational Metrics Laravel Package

syrian-open-source/laravel-relational-metrics

A Laravel package for calculating relational metrics from Eloquent models, letting you define and query counts, sums, averages, and other aggregates for dashboards, reports, and insights with clean, reusable code.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require syrian-open-source/laravel-relational-metrics

Laravel's package auto-discovery should register the service provider. If the repo ships a config file, publish it before you write your first metric:

php artisan vendor:publish --provider="SyrianOpenSource\RelationalMetrics\RelationalMetricsServiceProvider"

First place to look: the README.md for the exact facade/class name and method signatures, then src/ (there is usually a single Metric/Metrics class plus a service provider). The package is small and last tagged in March 2022, so reading the source is faster than trusting blog posts.

First use case: replace a hand-written Model::where(...)->count() buried in a controller with a named, reusable metric. The canonical first metric is "count of a model matching a condition", then "count of a model through a relation", then "aggregate (sum/avg) over a relation".

// Confirm the exact entry point in the README; the shape is roughly:
use SyrianOpenSource\RelationalMetrics\Facades\RelationalMetrics;

RelationalMetrics::model(Order::class)->count();
RelationalMetrics::model(Order::class)->where('status', 'paid')->count();
RelationalMetrics::model(User::class)->relation('orders')->count();

If the package exposes a trait, put it on the models you metric most:

use SyrianOpenSource\RelationalMetrics\Concerns\HasMetrics;

class Order extends Model
{
    use HasMetrics;
}

Sanity-check the install with a tinker session (php artisan tinker) against a seeded table before wiring it into a dashboard — that catches config/connection assumptions immediately.

Implementation Patterns

1. Named metrics instead of scattered queries. Wrap each KPI in a small class or a dedicated method so the definition lives in one place and can be reused by HTTP controllers, console commands, and widgets.

class PaidOrdersThisMonth
{
    public function __invoke(): int
    {
        return RelationalMetrics::model(Order::class)
            ->where('status', 'paid')
            ->whereBetween('created_at', [now()->startOfMonth(), now()->endOfMonth()])
            ->count();
    }
}

2. Relation-scoped metrics. The package's distinguishing feature is measuring through relations — e.g. "average order total per customer", "users with at least one failed payment". Model this by chaining the relation name onto the metric builder rather than pre-loading models in PHP.

// Count related rows without hydrating them
RelationalMetrics::model(User::class)->relation('posts')->count();

// Conditional metrics *inside* the relation
RelationalMetrics::model(User::class)
    ->relation('orders')
    ->where('orders.status', 'refunded')
    ->count();

3. Conditional / multi-condition metrics. Use this when a dashboard needs several numbers from the same base model in one request. Define them side by side so a reviewer can see the differences:

$metrics = [
    'total'    => RelationalMetrics::model(Order::class)->count(),
    'paid'     => RelationalMetrics::model(Order::class)->where('status', 'paid')->count(),
    'refunded' => RelationalMetrics::model(Order::class)->where('status', 'refunded')->count(),
];

If the underlying implementation returns a builder you can reuse, prefer cloning one base query (clone $base) over rebuilding from scratch three times.

4. Aggregates, not just counts. Sums/averages over relations are the natural second tier: revenue per merchant, average rating per product. Keep the aggregate column name explicit and qualify it with the table when joining (orders.total, not total).

5. Cache the expensive ones. Metrics over large tables or nested relations should sit behind Cache::remember() with a key that encodes the metric name and its parameters, and be invalidated by model events:

Cache::remember("metrics:paid_orders:{$month}", 300, fn () => (new PaidOrdersThisMonth)());

6. Integrate at the edges. Call metrics from API resource collections, dashboard widgets (Filament/Nova cards), and scheduled report commands — not from model accessors and not from Blade. Keeping metrics out of serialization paths avoids accidental N+1s.

7. Test at the query level. Because a metric is just a query, assert against seeded data:

Order::factory()->count(3)->create(['status' => 'paid']);
Order::factory()->count(2)->create(['status' => 'pending']);

$this->assertSame(3, RelationalMetrics::model(Order::class)->where('status', 'paid')->count());

Gotchas and Tips

  • Package age. Last release was March 2022. Check the composer.json constraints for laravel/framework and php before adding it to a Laravel 10/11 app; you may need --ignore-platform-reqs (a red flag) or a fork. Pin the version and add a comment in your composer.json rationale.
  • N+1 in disguise. ->relation(...)->count() executed per row in a loop is still N queries. For "counts per parent", prefer native withCount()/withSum() and reserve this package for cross-cutting, conditional, or dashboard-style metrics.
  • Global scopes and soft deletes. The metric builder almost certainly composes with Eloquent, so SoftDeletes and any global scopes apply — which may or may not be what your KPI means. Verify by comparing the metric to a raw DB::table(...)->count() on a table with soft-deleted rows.
  • Qualify columns. Once a relation join is added, unqualified where('status', ...) can become ambiguous and throw a SQL error. Always prefix with the table name in relational metrics.
  • SQL dialect differences. Conditional aggregates (SUM(CASE WHEN ...) or FILTER (WHERE ...)) behave differently on SQLite vs MySQL vs Postgres. Run your metric test suite against the same driver you deploy on; SQLite green does not guarantee Postgres green.
  • Sparse docs → read the source. The repo has ~26 stars and a single maintainer; treat the src/ directory as the source of truth. If a method you expect doesn't exist, wrap the builder in your own thin helper rather than forking — you keep upgrade freedom.
  • Debugging. Because most builders expose the underlying Builder, use ->toSql()/->getBindings() (or DB::listen) on the metric to see the real query when numbers look wrong. Most "bug reports" against metric packages are wrong scopes, not wrong packages.
  • Cache invalidation is your job. The package computes; it does not know when your data changed. Hook created/updated/deleted events on the base and related models to bust metric cache keys, otherwise dashboards silently drift.
  • Config quirks. If the config file defines a default connection or table prefix, remember it also applies in queued jobs and scheduled commands — a metric that's correct in a web request can be wrong in a worker pointing at a replica.
  • Extension points. If the package offers a base metric class or a Metric contract, extend it instead of calling the facade inline; that gives you one place to add caching, logging, and default date ranges across every KPI. If it only offers a facade, create your own App\Metrics\* classes that delegate to it — that insulation is what makes replacing the package later cheap.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource