Appearance
Nova Metric Conventions
Types of Metrics
We use three main types of metrics:
- Value Metrics - Single value calculations
- Trend Metrics - Time-series data
- 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
Naming Conventions
- Value metrics: End with descriptive noun (Count, Total, Average)
- Trend metrics: End with "Trend"
- Partition metrics: End with "Partition"
Type Safety
php
/** @extends \Laravel\Nova\Metrics\Value<\App\Modules\YourModule\Models\YourModel> */
final class YourMetric extends Value
{
}- Caching
php
public function cacheFor(): \DateTime
{
return now()->addMinutes(5);
}- 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
}
}