Larawards
Larawards implements achievements, trophies and badges in Laravel. An award is a class that knows how to compute a score for a model, and tiers turn one class into a whole family of related achievements.
Installation
composer require edulazaro/larawards php artisan migrate
Awards are persisted, so the migration is required.
Creating an award
php artisan make:award FooAchievement
That creates app/Awards/FooAchievement.php.
An award has a type: achievement, badge, or whatever you need:
/** @var string The award type. */ public $type = 'achievement';
Tiers
A tier is a single thing that can be awarded. Tiers let one class define a whole ladder of similar achievements instead of one class per milestone:
protected array $tiers = [ 'comment_written' => [ 'score' => 1, 'title' => 'First Comment Written', ], '3_comments_written' => [ 'score' => 3, 'title' => '3 Comments Written', ], '10_comments_written' => [ 'score' => 10, 'title' => '10 Comments Written', ], ];
Each tier has a title, the name shown to the user, and a score, the threshold at which it is awarded.
The score method
This is where the logic lives. It returns the current score for the awardable model:
/** * Get the awardable score for a user. * * @return int */ public function score(): int { return $this->rewardable->comments()->count(); }
Making a model awardable
namespace App\Models; use EduLazaro\Larawards\Concerns\HasRewards; class User { use HasRewards; }
Any model using HasRewards can receive awards.
Registering awards
User::awardable(AchievementsBadge::class);
Or grouped:
User::awardableGroup('achievements', [ CommentsAchievement::class, LessonsWatchedAchievement::class, ]);
Checking awards
An award is scoped to a model first, then checked. The check awards any tier whose requirement is now met:
FooAchievement::scope($user)->check();
Several at once:
User::awardables()->check(); // every award for the user User::awardables()->group('top_awards')->check(); // one group User::awardables()->where('type', 'achievement')->check(); // one type
Awarded tiers land in the rewards table.
Events
Set the $event property and it fires each time the award is granted:
namespace App\Awards; use EduLazaro\Larawards\Concerns\IsAward; use EduLazaro\Larawards\Contracts\AwardInterface; use App\Events\AchievementUnlocked; class CommentsAchievement implements AwardInterface { use IsAward; protected string $event = AchievementUnlocked::class; }
Reading rewards back
$rewards = $user->rewards; $isRewarded = $user->rewards()->where('name', 'comment_written')->exists();
Across users:
use EduLazaro\Larawards\Models\Reward; Reward::where('award_id', 'comments_achievement')->get();
Awards morph map
Works like Laravel's morph maps. By default the stored award id is the fully qualified class name, which is ugly in the database. enforceMap assigns readable aliases:
namespace App\Providers; use Illuminate\Support\ServiceProvider; use EduLazaro\Larawards\Collections\Awards; use App\Awards\CommentsAchievement; use App\Awards\LikesAchievement; class AwardServiceProvider extends ServiceProvider { public function boot(): void { Awards::enforceMap([ 'comments_achievement' => CommentsAchievement::class, 'likes_achievement' => LikesAchievement::class, ]); } }
App\Awards\CommentsAchievement is then stored as comments_achievement.
built and maintained by Edu Lazaro · MIT license