Weave Code
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 Easy Metrics Laravel Package

sakanjo/laravel-easy-metrics

Laravel package to quickly build app metrics (value, trend, bar, line, pie, doughnut, polar). Supports ranges, aggregates (count/sum/min/max/avg), and growth rates. Designed to work with Laravel and Filament widgets for dashboards.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Installation: Add the package via Composer:

    composer require sakanjo/laravel-easy-metrics
    
  2. First Use Case: Create a simple metric in a Filament widget or a Laravel command. For example, to display a user count trend in a Filament widget:

    use SaKanjo\EasyMetrics\Metrics\Trend;
    use App\Models\User;
    
    [$labels, $data] = Trend::make(User::class)
        ->range(30)
        ->countByMonths();
    
  3. Quick Value Metric: For a single KPI like total users:

    use SaKanjo\EasyMetrics\Metrics\Value;
    
    $totalUsers = Value::make(User::class)
        ->count();
    
  4. Explore Metrics: Test other metric types like Doughnut for categorical breakdowns or Bar for time-series comparisons.


Implementation Patterns

1. Metric Type Selection

  • Value Metric: Use for single aggregated values (e.g., total count, sum, average).
    Value::make(User::class)
        ->sum('revenue')
        ->range(30);
    
  • Doughnut/Pie Metric: Use for categorical distributions (e.g., user status breakdowns).
    [$labels, $data] = Doughnut::make(User::class)
        ->count('status');
    
  • Trend/Line/Bar Metric: Use for time-series data (e.g., daily/weekly/monthly trends).
    [$labels, $data] = Trend::make(User::class)
        ->countByMonths();
    

2. Flexible Grouping

Pass a second column to aggregate functions to group results:

// Group users by gender and count
[$labels, $data] = Doughnut::make(User::class)
    ->count('gender');

// Group revenue by region
[$labels, $data] = Doughnut::make(Order::class)
    ->sum('amount', 'region');

3. Time Range Configuration

Configure time ranges for trends or comparisons:

// Fixed range (30 days)
Trend::make(User::class)
    ->range(30)
    ->countByDays();

// Custom ranges (e.g., 15 days, 30 days, all time)
Trend::make(User::class)
    ->ranges([15, 30, Range::ALL])
    ->countByMonths();

// Predefined ranges (e.g., today, yesterday, month-to-date)
Trend::make(User::class)
    ->ranges([Range::TODAY, Range::YESTERDAY, Range::MTD])
    ->countByDays();

4. Growth Rate Reporting

Add growth metrics to any metric type:

// Value metric with growth rate
[$value, $growth] = Value::make(User::class)
    ->withGrowthRate()
    ->growthRateType(GrowthRateType::Percentage)
    ->count();

// Trend metric with growth rate
[$labels, $data, $growth] = Trend::make(User::class)
    ->withGrowthRate()
    ->countByMonths();

5. Integration with Filament

Use the package directly in Filament widgets for dashboards:

use SaKanjo\EasyMetrics\Metrics\Trend;
use Filament\Widgets\ChartWidget;

class UsersTrendWidget extends ChartWidget {
    protected function getData(): array {
        [$labels, $data] = Trend::make(User::class)
            ->range($this->filter)
            ->countByMonths();

        return [
            'datasets' => [[
                'label' => 'Users',
                'data' => $data,
            ]],
            'labels' => $labels,
        ];
    }

    protected function getType(): string {
        return 'line';
    }
}

6. Custom Date Columns

Specify a custom date column for time-based metrics:

Trend::make(Order::class)
    ->dateColumn('created_at') // Defaults to 'created_at'
    ->countByWeeks();

Gotchas and Tips

Pitfalls

  1. Zero Division in Growth Rates: Growth rates may fail if the baseline value (e.g., previous period) is zero. Handle this in your UI or add a check:

    if ($growth->previousValue === 0) {
        $growth->percentageChange = 0;
    }
    
  2. Database Engine Quirks: Time truncation (e.g., BY MONTH, BY DAY) may behave differently across databases (MySQL vs. PostgreSQL). Test thoroughly if using mixed environments.

  3. Performance with Large Datasets: Aggregations like countByMonths() on tables with millions of records can be slow. Optimize with database indexes or limit ranges:

    Trend::make(User::class)
        ->range(30) // Limit to 30 days
        ->countByDays();
    
  4. Enum Labels Require EasyEnum: To use getLabel() for enum-based metrics, ensure your enum uses SaKanjo\EasyEnum:

    enum UserStatus: int {
        use EasyEnum;
    
        case Active = 1;
        case Inactive = 0;
    }
    
  5. Default Date Column: All time-based metrics default to created_at. Override with dateColumn() if your model uses a different column (e.g., published_at).


Debugging Tips

  1. Inspect Raw Queries: Enable Laravel query logging to debug complex aggregations:

    DB::enableQueryLog();
    $data = Trend::make(User::class)->countByMonths();
    dd(DB::getQueryLog());
    
  2. Check Ranges: Verify time ranges with dd() before rendering:

    $metric = Trend::make(User::class)->range(30);
    dd($metric->getRange());
    
  3. Growth Rate Edge Cases: Log growth calculations to catch unexpected values:

    [$value, $growth] = Value::make(User::class)
        ->withGrowthRate()
        ->count();
    logger()->info('Growth rate', [
        'current' => $value,
        'previous' => $growth->previousValue,
        'percentage' => $growth->percentageChange,
    ]);
    

Extension Points

  1. Custom Metric Classes: Extend existing metrics (e.g., Trend) to add domain-specific logic:

    class RevenueTrend extends Trend {
        public function revenueByMonths() {
            return $this->sumByMonths('amount');
        }
    }
    
  2. Override Growth Calculations: Modify growth rate logic by extending the GrowthRate class or using middleware:

    // Example: Custom growth rate logic
    $growth = $metric->withGrowthRate()
        ->customGrowthLogic(function ($current, $previous) {
            return $current - $previous; // Absolute difference
        });
    
  3. Add Custom Ranges: Extend the Range enum for project-specific time periods:

    enum CustomRange {
        use \SaKanjo\EasyMetrics\Enums\Range;
    
        case QUARTERLY;
    }
    
  4. Integrate with Caching: Cache metric results to improve performance:

    $cacheKey = 'users_trend_' . $range;
    return Cache::remember($cacheKey, now()->addHours(1), function () use ($range) {
        return Trend::make(User::class)
            ->range($range)
            ->countByMonths();
    });
    

Pro Tips

  1. Use rangesFromOptions in Filament: Dynamically generate range options for user-selectable time periods:

    protected function getFilters(): array {
        return [
            7 => 'Last 7 Days',
            30 => 'Last 30 Days',
            Range::MTD => 'Month-to-Date',
            Range::YTD => 'Year-to-Date',
        ];
    }
    
    // In widget:
    Trend::make(User::class)
        ->rangesFromOptions($this->getFilters())
        ->countByDays();
    
  2. Combine Metrics for Dashboards: Use multiple metrics in a single widget for richer insights:

    [$users, $growth] = Value::make(User::class)
        ->withGrowthRate()
        ->count();
    
    [$activeUsers, $inactiveUsers] = Doughnut::make(User::class)
        ->count('status');
    
  3. Localization: Localize labels and growth rate messages:

    __("Growth: :percentage%", ['percentage' => $growth->percentageChange]);
    
  4. Testing: Mock metrics in tests using Laravel's query builder:

    $metric = Mockery::mock(Trend::class);
    $metric->shouldReceive('countByMonths')
        ->andReturn([['Jan',
    
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.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope