PHP code example of cjmellor / level-up

1. Go to this page and download the library: Download cjmellor/level-up library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

cjmellor / level-up example snippets


return [

    'models' => [
        'achievement' => LevelUp\Experience\Models\Achievement::class,
        'activity' => LevelUp\Experience\Models\Activity::class,
        'experience' => LevelUp\Experience\Models\Experience::class,
        'experience_audit' => LevelUp\Experience\Models\ExperienceAudit::class,
        'level' => LevelUp\Experience\Models\Level::class,
        'streak' => LevelUp\Experience\Models\Streak::class,
        'streak_history' => LevelUp\Experience\Models\StreakHistory::class,
        'achievement_user' => LevelUp\Experience\Models\Pivots\AchievementUser::class,
        'tier' => LevelUp\Experience\Models\Tier::class,
        'multiplier' => LevelUp\Experience\Models\Multiplier::class,
        'multiplier_user' => LevelUp\Experience\Models\Pivots\MultiplierUser::class,
        'multiplier_tier' => LevelUp\Experience\Models\Pivots\MultiplierTier::class,
        'challenge' => LevelUp\Experience\Models\Challenge::class,
        'challenge_user' => LevelUp\Experience\Models\Pivots\ChallengeUser::class,
        'challenge_completion' => LevelUp\Experience\Models\ChallengeCompletion::class,
        'leaderboard_snapshot' => LevelUp\Experience\Models\LeaderboardSnapshot::class,
        'division' => LevelUp\Experience\Models\Division::class,
        'cohort' => LevelUp\Experience\Models\Cohort::class,
        'cohort_user' => LevelUp\Experience\Models\Pivots\CohortUser::class,
    ],

    /*
    |--------------------------------------------------------------------------
    | User Foreign Key
    |--------------------------------------------------------------------------
    |
    | This value is the foreign key that will be used to relate the Experience model to the User model.
    |
    | 'foreign_key_type' controls the DB column type used for the user FK on
    | every package table. Set to 'uuid' or 'ulid' if your host User model
    | uses HasUuids / HasUlids. Leave as 'bigint' for standard auto-increment
    | user IDs. This only affects fresh migrations; existing installs keep
    | whichever column type they originally migrated with.
    |
     */
    'user' => [
        'foreign_key' => 'user_id',
        'foreign_key_type' => 'bigint',
        'model' => App\Models\User::class,
        'users_table' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Package Entities
    |--------------------------------------------------------------------------
    |
    | 'id_type' controls the primary key column type used for the package's
    | own tables (experiences, levels, achievements, etc.) and every internal
    | foreign key between them. Set to 'uuid' or 'ulid' if you want package
    | IDs to be opaque (e.g., for safe exposure on a public API surface).
    | Leave as 'bigint' for standard auto-increment IDs. Only affects fresh
    | migrations; existing installs keep whichever column type they already
    | migrated with. See the README "Customizing Identifiers" section for
    | guidance on switching an existing install.
    |
    */
    'entities' => [
        'id_type' => 'bigint',
    ],

    /*
    |--------------------------------------------------------------------------
    | Table Prefix
    |--------------------------------------------------------------------------
    |
    | Prepended to every default package table name. Leave empty for no prefix.
    | Per-table overrides in 'tables' below are taken verbatim and are NOT
    | prefixed.
    |
    */
    'table_prefix' => env('LEVEL_UP_TABLE_PREFIX', ''),

    /*
    |--------------------------------------------------------------------------
    | Tables
    |--------------------------------------------------------------------------
    |
    | The table name used for each of the package's models. Leave a value
    | equal to the default to apply table_prefix above; set it to any other
    | string to override that table's name exactly (no prefix applied).
    |
    */
    'tables' => [
        'experiences' => 'experiences',
        'experience_audits' => 'experience_audits',
        'levels' => 'levels',
        'achievements' => 'achievements',
        'achievement_user' => 'achievement_user',
        'streaks' => 'streaks',
        'streak_histories' => 'streak_histories',
        'streak_activities' => 'streak_activities',
        'tiers' => 'tiers',
        'multipliers' => 'multipliers',
        'multiplier_user' => 'multiplier_user',
        'multiplier_tier' => 'multiplier_tier',
        'challenges' => 'challenges',
        'challenge_user' => 'challenge_user',
        'challenge_completions' => 'challenge_completions',
        'leaderboard_snapshots' => 'leaderboard_snapshots',
        'divisions' => 'divisions',
        'cohorts' => 'cohorts',
        'cohort_user' => 'cohort_user',
    ],

    /*
    |-----------------------------------------------------------------------
    | Leaderboard
    |-----------------------------------------------------------------------
    |
    | Configure the leaderboard. 'metrics' maps registry keys to
    | RankingMetric classes — register custom metrics by adding entries.
    | 'default_metric' is used when no metric is specified.
    |
    | 'week_starts_on' sets the boundary of Period::Week as a Carbon
    | day-of-week number: 0 (Sunday) through 6 (Saturday). Defaults to
    | Monday. 'timezone' controls which timezone period boundaries
    | (start of day/week/month) are computed in; null uses the
    | application timezone.
    |
    | 'boards' declares named Boards — leaderboards the package can
    | track over time. Each entry maps a board name to a 'metric'
    | (--
    | Challenges
    | -------------------------------------------------------------------------
    |
    | Configure the challenges system. Challenges are multi-condition goals
    | that users can enroll in and complete for rewards.
    |
    */
    'challenges' => [
        'enabled' => env(key: 'CHALLENGES_ENABLED', default: true),
    ],
];

// config/level-up.php
'table_prefix' => 'levelup_',

'tables' => [
    'experiences' => 'xp_log',         // renamed
    'levels'      => 'user_tiers',     // renamed
    'tiers'       => 'rank_brackets',  // renamed
    // leave the rest at their defaults
],

'table_prefix' => 'lvl_',
'tables' => [
    'levels' => 'xp_levels',  // → 'xp_levels' (NO prefix)
    // others stay default → all become 'lvl_<default>'
],

use LevelUp\Experience\Concerns\GiveExperience;

class User extends Model
{
    use GiveExperience;

    // ...
}

$user->addPoints(10);

$user->deductPoints(10);

$user->setPoints(10);

$user->getPoints();

use LevelUp\Experience\Models\Multiplier;

Multiplier::create([
    ‘name’ => ‘WrestleMania Weekend’,
    ‘multiplier’ => 5,
    ‘is_active’ => true,
    ‘starts_at’ => ‘2026-04-05 00:00:00’,
    ‘expires_at’ => ‘2026-04-07 23:59:59’,
]);

// Scope to one or more tiers (variadic, idempotent)
$multiplier->scopeToTier($premiumTier, $diamondTier);

// Scope to one or more users (variadic, idempotent)
$multiplier->scopeToUser($user);

// Reverse either with unscope helpers
$multiplier->unscopeFromTier($diamondTier);
$multiplier->unscopeFromUser($user);

// Check whether a multiplier has any scopes
$multiplier->isGlobal();  // true if no users or tiers attached

Multiplier::active()->get();               // Currently active
Multiplier::active()->forUser($user)->get(); // Active for a specific user
Multiplier::scheduled()->get();             // Armed but starts_at is in the future
Multiplier::expired()->get();               // Past their expires_at

$user->addPoints(
    amount: 10,
    multiplier: 2
);

public int $pointsAdded,
public int $totalPoints,
public string $type,
public ?string $reason,
public Model $user,
public ?array $multipliers, // Applied multipliers (if any)

public Model $user,
public Collection $multipliers,   // DB multiplier models that were applied
public int $originalAmount,       // Points before multipliers
public int $finalAmount,          // Points after multipliers
public string $strategy,          // 'compound', 'additive', or 'highest'

public int $pointsDecreasedBy,
public int $totalPoints,
public ?string $reason,
public Model $user,

Level::add(
    ['level' => 1, 'next_level_experience' => null],
    ['level' => 2, 'next_level_experience' => 100],
    ['level' => 3, 'next_level_experience' => 250],
);

$user->nextLevelAt();

$user->getLevel();

public Model $user,
public int $level

Achievement::create([
    'name' => 'Hit Level 20',
    'is_secret' => false,
    'description' => 'When a User hits Level 20',
    'image' => 'storage/app/achievements/level-20.png',
]);

// App\Models\User.php

use LevelUp\Experience\Concerns\HasAchievements;

class User extends Authenticable
{
	use HasAchievements;
	
	// ...
}

$achievement = Achievement::find(1);

$user->grantAchievement($achievement);

$user->getUserAchievements();

$user->revokeAchievement($achievement);

$user->grantAchievement(
    achievement: $achievement, 
    progress: 50 // 50%
);

$user->grantAchievement(
    achievement: $achievement,
    progress: 50,
    count: 5 // e.g. 5 games played
);

$user->achievementsWithProgress()->get();

$user->achievementsWithSpecificProgress(25)->get();

$user->incrementAchievementProgress(
    achievement: $achievement, 
    amount: 10
);

$user->incrementAchievementProgress(
    achievement: $achievement,
    amount: 10,
    count: 1 // one more game played
);

$achievement->update(['is_secret' => true]);

$user->secretAchievements;

$user->allAchievements;

public Achievement $achievement,
public Model $user,

public Achievement $achievement,
public Model $user,

public Achievement $achievement,
public Model $user,
public int $amount,
public ?int $count,

$entries = Leaderboard::generate();

foreach ($entries as $entry) {
    $entry->user;  // the User model (with Experience eager-loaded)
    $entry->score; // the user's score on this metric
    $entry->rank;  // the user's position on the board (1 is first)
}

Leaderboard::rankOf(user: $user); // 4 — or null if the user isn't on the board

Leaderboard::around(user: $user, range: 2); // up to 2 entries above + the user + up to 2 below

Leaderboard::by('xp')->rankOf(user: $user);
Leaderboard::by(MyCustomMetric::class)->around(user: $user, range: 3);

Leaderboard::by('xp')->generate();
Leaderboard::by(MyCustomMetric::class)->generate();
Leaderboard::by(new MyCustomMetric())->generate();

Leaderboard::by('level')->generate();

use LevelUp\Experience\Metrics\StreakMetric;

Leaderboard::by(new StreakMetric(activity: $activity))->generate();

Leaderboard::by('achievements')->generate();                    // most achievements earned, ever
Leaderboard::by('achievements')->period(Period::Week)->generate(); // most achievements earned this week
Leaderboard::by('challenges')->generate();                      // most challenges completed, ever

use LevelUp\Experience\Enums\Period;

Leaderboard::period(Period::Day)->generate();   // points earned today
Leaderboard::period(Period::Week)->generate();  // points earned this week
Leaderboard::period(Period::Month)->generate(); // points earned this month

Leaderboard::since(start: now()->subDays(3))->generate();

Leaderboard::since(start: $seasonStart, until: $seasonEnd)->generate();

Leaderboard::period(Period::Week)->rankOf(user: $user);
Leaderboard::period(Period::Week)->around(user: $user, range: 2);

'leaderboard' => [
    // ...
    'week_starts_on' => Carbon\CarbonInterface::MONDAY, // 0 (Sunday) – 6 (Saturday)
    'timezone' => null, // null = the application timezone
],

$friendIds = $user->friends()->pluck('id')->push($user->id); // friendIds))->generate();

// This week's XP, friends only
Leaderboard::restrictTo(fn ($query) => $query->whereIn('id', $friendIds))
    ->period(Period::Week)
    ->generate();

// Your rank among your friends — null if you're outside the restriction
Leaderboard::restrictTo(fn ($query) => $query->whereIn('id', $friendIds))->rankOf(user: $user);

'leaderboard' => [
    // ...
    'boards' => [
        'weekly-xp' => ['metric' => 'xp', 'period' => 'week'],
        'gold-race' => ['metric' => 'xp', 'period' => 'week', 'tier' => 'Gold'],
    ],
],

Leaderboard::board('weekly-xp')->generate();

Leaderboard::board('weekly-xp')->rankOf(user: $user);

// This week's XP, friends only — refinements compose on top of the declaration
Leaderboard::board('weekly-xp')
    ->restrictTo(fn ($query) => $query->whereIn('id', $friendIds))
    ->generate();

// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('level-up:snapshot-boards')->hourly();

'boards' => [
    'weekly-xp' => ['metric' => 'xp', 'period' => 'week', 'track_top' => 50],
],

'leaderboard' => [
    // ...
    'snapshots' => [
        'retention_days' => 30,
    ],
],

'leaderboard' => [
    // ...
    'league' => [
        'board' => 'weekly-xp', // must be declared under 'boards' with a 'period'
        'cohort_size' => 30,
        'divisions' => [
            'Bronze' => ['promote' => 10, 'relegate' => 0],
            'Silver' => ['promote' => 7, 'relegate' => 5],
            'Gold' => ['promote' => 0, 'relegate' => 5],
        ],
    ],
],

use LevelUp\Experience\Concerns\HasLeagues;

$user->currentDivision();   // ?Division — the rung they hold (null until first-ever earn)
$user->currentCohort();     // ?Cohort — this period's cohort (null if not yet enrolled this period)
$user->cohortStandings();   // Collection<LeaderboardEntry> — ranked entries within the user's cohort only

// routes/console.php
use Illuminate\Support\Facades\Schedule;

// e.g. for a weekly league with Monday-start weeks:
Schedule::command('level-up:league-rollover')->weeklyOn(1, '00:05');

use LevelUp\Experience\Models\Experience;

$users = Experience::query()
    ->with('user')
    ->orderByDesc('experience_points')
    ->limit(10)
    ->get()
    ->map(fn (Experience $experience) => $experience->user);

Leaderboard::generate(limit: 10);                                 // top 10 by XP, all-time
Leaderboard::by('xp')->period(Period::Week)->generate(limit: 10); // top 10 earners this week
Leaderboard::by('achievements')->period(Period::Month)->generate(limit: 3); // this month's achievements podium

$rank = Leaderboard::rankOf(user: $user);
$total = User::query()->whereHas('experience')->count();

$topPercent = $rank === null ? null : (int) ceil($rank / $total * 100); // 4 → "top 4%"

$user->addPoints(
    amount: 50,
    multiplier: 2,
    type: AuditType::Add->value,
    reason: "Some reason here",
);

$user->experienceHistory;

use LevelUp\Experience\Concerns\HasStreaks;

class User extends Model
{
	use HasStreaks;

	// ...
}

$activity = Activity::find(1);

$user->recordStreak($activity);

$activity = Activity::find(1);

$user->resetStreak($activity);

use LevelUp\Experience\Models\StreakHistory;

StreakHistory::all();

$user->getCurrentStreakCount($activity); // 2

$user->hasStreakToday($activity);

public int $pointsAdded,
public int $totalPoints,
public string $type,
public ?string $reason,
public Model $user,

public Model $user,
public Activity $activity,
public Streak $streak,

'freeze_duration' => env(key: 'STREAK_FREEZE_DURATION', default: 1),

$user->freezeStreak(activity: $activity);

$user->freezeStreak(activity: $activity, days: 5); // freeze for 5 days

$user->unfreezeStreak($activity);

$user->isStreakFrozen($activity);

public int $frozenStreakLength,
public Carbon $frozenUntil,

use LevelUp\Experience\Concerns\HasTiers;

class User extends Model
{
    use GiveExperience, HasAchievements, HasStreaks, HasTiers;
}

use LevelUp\Experience\Models\Tier;

Tier::add(
    ['name' => 'Bronze', 'experience' => 0],
    ['name' => 'Silver', 'experience' => 500],
    ['name' => 'Gold', 'experience' => 2000],
    ['name' => 'Platinum', 'experience' => 5000, 'metadata' => ['color' => '#E5E4E2']],
);

$user->getTier();           // Current tier (Tier model or null)
$user->getNextTier();       // Next tier above current
$user->tierProgress();      // Percentage (0-100) through current bracket
$user->nextTierAt();        // XP remaining until next tier
$user->isAtTier('Gold');    // Check exact tier
$user->isAtOrAboveTier('Silver'); // Check tier hierarchy

$goldMultiplier = Multiplier::create([
    'name' => 'Gold Tier Bonus',
    'multiplier' => 2,
    'is_active' => true,
]);

$goldMultiplier->tiers()->attach(Tier::where('name', 'Gold')->first());

$goldTier = Tier::where('name', 'Gold')->first();

Achievement::create([
    'name' => 'Golden Streak',
    'tier_id' => $goldTier->id,
]);

// config/level-up.php
'tiers' => [
    'streak_freeze_days' => [
        'Bronze' => 1,
        'Silver' => 2,
        'Gold' => 3,
        'Platinum' => 7,
    ],
],

Leaderboard::forTier('Gold')->generate();

public Model $user,
public ?Tier $previousTier,
public ?Tier $newTier,
public TierDirection $direction, // TierDirection::Promoted or TierDirection::Demoted

use LevelUp\Experience\Concerns\HasChallenges;

class User extends Model
{
    use GiveExperience, HasAchievements, HasStreaks, HasTiers, HasChallenges;
}

use LevelUp\Experience\Models\Challenge;

Challenge::create([
    'name' => 'Welcome Warrior',
    'description' => 'Complete these tasks to earn a bonus!',
    'conditions' => [
        ['type' => 'points_earned', 'amount' => 100],
        ['type' => 'level_reached', 'level' => 5],
    ],
    'rewards' => [
        ['type' => 'points', 'amount' => 500],
    ],
    'auto_enroll' => true,
    'is_repeatable' => false,
    'starts_at' => '2026-04-01 00:00:00', // optional
    'expires_at' => '2026-04-30 23:59:59', // optional
]);

Challenge::create([
    'name' => 'Podium Finish',
    'description' => 'Crack the top 3 on the weekly XP board.',
    'conditions' => [
        ['type' => 'leaderboard_rank', 'board' => 'weekly-xp', 'rank' => 3],
    ],
    'rewards' => [
        ['type' => 'points', 'amount' => 500],
    ],
    'auto_enroll' => true,
]);

$challenge = Challenge::find(1);

$user->enrollInChallenge($challenge);

$user->unenrollFromChallenge($challenge);

$user->activeChallenges;        // Enrolled, not yet completed
$user->completedChallenges;     // Challenges completed at least once (distinct; repeatable-safe)
$user->challengeCompletions;    // Every completion event (one row per completion, repeatable 

use LevelUp\Experience\Contracts\ChallengeCondition;
use Illuminate\Database\Eloquent\Model;

class HasVerifiedEmail implements ChallengeCondition
{
    public function check(Model $user, array $condition): bool
    {
        return $user->hasVerifiedEmail();
    }
}

Challenge::create([
    'conditions' => [
        ['type' => 'custom', 'class' => HasVerifiedEmail::class],
    ],
    // ...
]);

public Challenge $challenge,
public Model $user,

public Challenge $challenge,
public Model $user,

public Challenge $challenge,
public Model $user,

'entities' => [
    'id_type' => 'uuid', // 'bigint' (default) | 'uuid' | 'ulid'
],

php artisan vendor:publish --tag="level-up-migrations"
php artisan migrate

php artisan vendor:publish --tag="level-up-config"