Skip to content

Nova Metric Conventions

Types of Metrics

We use three main types of metrics:

  1. Value Metrics - Single value calculations
  2. Trend Metrics - Time-series data
  3. Partition Metrics - Data grouping/segmentation

Directory Structure

Metrics are organized by module: app/YourModule/Nova/Metrics/

Common Patterns

Value Metrics

php
namespace App\Modules\Course\Nova\Metrics\Quiz;

use Laravel\Nova\Metrics\Value;

final class UngradedOEQCount extends Value
{
    public function calculate(): mixed
    {
        // Implementation
    }
}

Trend Metrics

php
namespace App\Member\Nova\Metrics;

use Laravel\Nova\Metrics\Trend;

final class NewMembersTrend extends Trend
{
    public function calculate(Request $request): TrendResult
    {
        return $this->countByDays($request, Member::class);
    }
}

Partition Metrics

php
namespace App\Member\Nova\Metrics;

use Laravel\Nova\Metrics\Partition;

final class MembershipDurationPartition extends Partition
{
    public function calculate(): PartitionResult
    {
        // Implementation
    }
}

Best Practices

  1. Naming Conventions

    • Value metrics: End with descriptive noun (Count, Total, Average)
    • Trend metrics: End with "Trend"
    • Partition metrics: End with "Partition"
  2. Type Safety

php
/** @extends \Laravel\Nova\Metrics\Value<\App\Modules\YourModule\Models\YourModel> */
final class YourMetric extends Value
{
}
  1. Caching
php
public function cacheFor(): \DateTime
{
    return now()->addMinutes(5);
}
  1. Ranges
php
public function ranges(): array
{
    return [
        30 => '30 Days',
        60 => '60 Days',
        90 => '90 Days',
    ];
}

Examples

Value Metric

php
use Laravel\Nova\Metrics\Value;
use Laravel\Nova\Http\Requests\NovaRequest;

final class ActiveIndividualMembers extends Value
{
    public function name(): string
    {
        return 'Active Individual Members';
    }

    public function calculate(NovaRequest $request): mixed
    {
        return $this->count($request, Member::class, function ($query) {
            return $query->where('status', 'active')
                        ->where('type', 'individual');
        });
    }

    public function cacheFor(): \DateTime
    {
        return now()->addMinutes(5);
    }
}

Trend Metric

php
use App\Nova\Metrics\FilterableTrend;use Laravel\Nova\Http\Requests\NovaRequest;use Laravel\Nova\Metrics\TrendResult;

final class RefundsTrend extends FilterableTrend
{
    public function name(): string
    {
        return 'Refunds Over Time';
    }

    public function calculate(NovaRequest $request): TrendResult
    {
        return $this->sumByDays(
            $request,
            Transaction::class,
            'amount',
            function ($query) {
                return $query->whereType('refund');
            }
        )->dollars();
    }

    public function ranges(): array
    {
        return [
            30 => '30 Days',
            60 => '60 Days',
            90 => '90 Days',
        ];
    }
}

Partition Metric

php
namespace App\Member\Nova\Metrics;

use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Metrics\Partition;
use Laravel\Nova\Metrics\PartitionResult;

final class MembershipDurationPartition extends Partition
{
    public function name(): string
    {
        return 'Membership Duration Distribution';
    }

    public function calculate(NovaRequest $request): PartitionResult
    {
        return $this->count($request, Member::class, 'membership_duration')
            ->label(function ($value) {
                return $this->formatDuration($value);
            });
    }

    private function formatDuration(string $value): string
    {
        // Implementation
    }
}

Filterable Trend

php
namespace App\Nova\Payment\Metrics;

use App\Modules\Payment\Nova\TrendFilters\InvoiceCountryFilter;
use App\Nova\Metrics\FilterableTrend;

final class PaymentsTrend extends FilterableTrend
{
    public function filters(): array
    {
        return [
            new InvoiceCountryFilter,
        ];
    }

    protected function applyFilter($query, $value): void
    {
        // Implementation
    }
}