Skip to content

ram64/laravel-merit

Repository files navigation

Achievements, XP tracking, and leveling.

[![Latest Version on Packagist](https://img.shields public static function name(?Model $achiever = null): string { return 'First Post'; }

public static function description(?Model $achiever = null): string
{
    return 'Create your first post on the platform.';
}

// Example of dynamic content (optional):
// public static function name(?Model $achiever = null): string
// {
//     if ($achiever) {
//         $progress = static::getProgress($achiever);
//         $remaining = static::getRemainingProgress($achiever);
//         if ($remaining > 0) {
//             return "First Post ({$progress}/{$remaining} remaining)";
//         }
//     }
//     return 'First Post';
// }gist/v/ram64/laravel-merit.svg?style=flat-square)](https://packagist.org/packages/ram64/laravel-merit)

GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Laravel Merit brings gamification to your Laravel apps with clean, code-first achievements, XP tracking, and leveling. Define achievements in config, track progress with traits, and reward your users with milestones and badges.

Support us

To do

Installation

You can install the package via composer:

composer require ram64/laravel-merit

You can publish and run the migrations with:

php artisan vendor:publish --tag="laravel-merit-migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --tag="laravel-merit-config"

This is the contents of the published config file:

return [

    'achiever_model' => env('MERIT_ACHIEVER_MODEL', App\Models\User::class),
    'achievements_table' => env('MERIT_ACHIEVEMENTS_TABLE', 'achiever_achievements'),
    'cache_ttl' => 10,
    'queue_events' => env('MERIT_QUEUE_EVENTS', false),
];

Optionally, you can publish the views using

php artisan vendor:publish --tag="laravel-merit-views"

Usage

Basic Setup

  1. Add the CanAchieve trait to your model:
use Ram64\LaravelMerit\Concerns\CanAchieve;

class User extends Authenticatable
{
    use CanAchieve;
    
    // Your model code...
}
  1. Create Achievement Definitions:

Use the artisan command to create new achievements:

php artisan make:merit-achievement FirstPost --category=posts

This creates a new achievement class:

<?php

namespace App\Definitions\Achievements\Posts;

use Illuminate\Database\Eloquent\Model;
use Ram64\LaravelMerit\Definitions\Achievements\AchievementDefinition;

class FirstPostAchievement extends AchievementDefinition
{
    public static function key(): string
    {
        return 'first_post';
    }

    public static function name(): string
    {
        return 'First Post';
    }

    public static function description(): string
    {
        return 'Create your very first post';
    }

    public static function goal(): int
    {
        return 1;
    }

    public static function category(): string
    {
        return 'posts';
    }

    public static function qualifiesFor(Model $achiever): bool
    {
        return static::getCount($achiever, 'posts') >= static::goal();
    }

    public static function calculateCurrentProgress(Model $achiever): int
    {
        return min(static::getCount($achiever, 'posts'), static::goal());
    }
}
  1. Track Achievement Progress:
use Ram64\LaravelMerit\Services\AchievementTracker;

// Check all achievements for a user
AchievementTracker::check($user);

// Get achievement definition by key
$definition = AchievementTracker::getDefinition('first_post');

// Get definition from an AchieverAchievement model
$achievement = $user->achievements()->where('achievement_key', 'first_post')->first();
$definition = AchievementTracker::getDefinitionFromAchievement($achievement);

// Get all achievement keys
$keys = AchievementTracker::getAchievementKeys();

// Get achievement display data
$display = AchievementTracker::getAchievementDisplay($user, 'first_post');

Achievement Prerequisites

Laravel Merit supports flexible prerequisite definitions. Achievements can require other achievements to be completed first:

public static function prerequisite(): string|array|null
{
    // No prerequisites
    return null;
    
    // Single string key prerequisite
    return 'first_post';
    
    // Single class prerequisite
    return FirstPostAchievement::class;
    
    // Multiple mixed prerequisites
    return [
        'first_post',                    // String key
        FifthPostAchievement::class,     // Class reference
    ];
}

Experience & Leveling System

Laravel Merit includes a comprehensive experience and leveling system:

use Ram64\LaravelMerit\Concerns\Experiencer;

class User extends Authenticatable
{
    use Experiencer;
}

```php
use Ram64\LaravelMerit\Concerns\CanExperience;

class User extends Authenticatable
{
    use CanExperience;
}

// Award experience
$user->gainExperience(100, 'Completed quest');

// Check level and progress $level = $user->getLevel(); $progress = $user->getExperienceProgress();


**Features:**
- Flexible level calculation (static thresholds or dynamic formulas)
- Experience logging with optional enable/disable
- Events for experience changes and level-ups
- Caching for performance
- Polymorphic support for any model

## Performance & Caching

Laravel Merit includes comprehensive caching to ensure high performance, especially with dynamic achievement content:

### Cached Methods

For optimal performance, use these cached methods instead of calling `name()` and `description()` directly:

```php
// Fast cached access (recommended)
$name = FirstPostAchievement::getCachedName($user);
$description = FirstPostAchievement::getCachedDescription($user);

// Direct access (bypasses cache)
$name = FirstPostAchievement::name($user);
$description = FirstPostAchievement::description($user);

Cache Invalidation

Caches are automatically cleared when:

  • Achievement progress changes
  • Achievements are unlocked
  • Manual award/increment operations occur

Cache Configuration

Configure cache TTL in config/merit.php:

'cache_ttl' => 10, // minutes

Performance Tips

  1. Use getAchievementDisplay() for complete achievement data - it's fully cached
  2. Use cached methods for individual name/description access
  3. Avoid direct database queries in dynamic content methods - use cached progress methods
  4. Consider cache TTL based on your update frequency

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

About

Laravel Merit brings gamification to your Laravel apps with clean, code-first achievements, XP tracking, and leveling. Define achievements in config, track progress with traits, and reward your users with milestones and badges.

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors

Languages